Merge: ALSA - update drivers for 9.9 - upstream 6.19

MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7942

JIRA: https://issues.redhat.com/browse/RHEL-152847

Depends: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7950

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
* regmap core

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: 0e9fc79132ce7ea1e48c388b864382aa38eb0ed4  # will be in 7.0 kernel backport

Omitted-fix: c673efd5db2223c2e8b885025bcd96bca6cdb171  # will be in 7.0 kernel backport

Omitted-fix: 75dc1980cf48826287e43dc7a49e310c6691f97e # will be in 7.0 kernel backport

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: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
This commit is contained in:
CKI KWF Bot
2026-04-06 08:09:38 +00:00
575 changed files with 28053 additions and 4442 deletions
@@ -0,0 +1,62 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/cix,sky1-ipbloq-hda.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: CIX IPBLOQ HDA controller
description:
CIX IPBLOQ High Definition Audio (HDA) Controller
maintainers:
- Joakim Zhang <joakim.zhang@cixtech.com>
allOf:
- $ref: sound-card-common.yaml#
properties:
compatible:
const: cix,sky1-ipbloq-hda
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 2
clock-names:
items:
- const: ipg
- const: per
resets:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- resets
unevaluatedProperties: false
examples:
- |
#include<dt-bindings/interrupt-controller/arm-gic.h>
hda@70c0000 {
compatible = "cix,sky1-ipbloq-hda";
reg = <0x70c0000 0x10000>;
interrupts = <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&audss_clk 7>,
<&audss_clk 8>;
clock-names = "ipg", "per";
resets = <&audss_rst 14>;
model = "CIX SKY1 EVB HDA";
};
@@ -0,0 +1,178 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mediatek,mt8189-afe-pcm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Audio Front End PCM controller for MT8189
maintainers:
- Darren Ye <darren.ye@mediatek.com>
- Cyril Chao <cyril.chao@mediatek.com>
properties:
compatible:
const: mediatek,mt8189-afe-pcm
reg:
maxItems: 1
interrupts:
maxItems: 1
memory-region:
maxItems: 1
mediatek,apmixedsys:
$ref: /schemas/types.yaml#/definitions/phandle
description: To set up the apll12 tuner
power-domains:
maxItems: 1
clocks:
items:
- description: mux for audio intbus
- description: mux for audio engen1
- description: mux for audio engen2
- description: mux for audio h
- description: audio apll1 clock
- description: audio apll2 clock
- description: audio apll1 divide4
- description: audio apll2 divide4
- description: audio apll12 divide for i2sin0
- description: audio apll12 divide for i2sin1
- description: audio apll12 divide for i2sout0
- description: audio apll12 divide for i2sout1
- description: audio apll12 divide for fmi2s
- description: audio apll12 divide for tdmout mck
- description: audio apll12 divide for tdmout bck
- description: mux for audio apll1
- description: mux for audio apll2
- description: mux for i2sin0 mck
- description: mux for i2sin1 mck
- description: mux for i2sout0 mck
- description: mux for i2sout1 mck
- description: mux for fmi2s mck
- description: mux for tdmout mck
- description: 26m clock
- description: audio slv clock
- description: audio mst clock
- description: audio intbus clock
clock-names:
items:
- const: top_aud_intbus
- const: top_aud_eng1
- const: top_aud_eng2
- const: top_aud_h
- const: apll1
- const: apll2
- const: apll1_d4
- const: apll2_d4
- const: apll12_div_i2sin0
- const: apll12_div_i2sin1
- const: apll12_div_i2sout0
- const: apll12_div_i2sout1
- const: apll12_div_fmi2s
- const: apll12_div_tdmout_m
- const: apll12_div_tdmout_b
- const: top_apll1
- const: top_apll2
- const: top_i2sin0
- const: top_i2sin1
- const: top_i2sout0
- const: top_i2sout1
- const: top_fmi2s
- const: top_dptx
- const: clk26m
- const: aud_slv_ck_peri
- const: aud_mst_ck_peri
- const: aud_intbus_ck_peri
required:
- compatible
- reg
- interrupts
- memory-region
- power-domains
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
afe@11050000 {
compatible = "mediatek,mt8189-afe-pcm";
reg = <0 0x11050000 0 0x10000>;
interrupts = <GIC_SPI 392 IRQ_TYPE_LEVEL_HIGH 0>;
memory-region = <&afe_dma_mem_reserved>;
pinctrl-names = "default";
pinctrl-0 = <&aud_pins_default>;
power-domains = <&scpsys 1>; //MT8189_POWER_DOMAIN_AUDIO
clocks = <&topckgen_clk 23>, //CLK_TOP_AUD_INTBUS_SEL
<&topckgen_clk 39>, //CLK_TOP_AUD_ENGEN1_SEL
<&topckgen_clk 40>, //CLK_TOP_AUD_ENGEN2_SEL
<&topckgen_clk 49>, //CLK_TOP_AUDIO_H_SEL
<&topckgen_clk 146>, //CLK_TOP_APLL1
<&topckgen_clk 151>, //CLK_TOP_APLL2
<&topckgen_clk 148>, //CLK_TOP_APLL1_D4
<&topckgen_clk 153>, //CLK_TOP_APLL2_D4
<&topckgen_clk 93>, //CLK_TOP_APLL12_CK_DIV_I2SIN0
<&topckgen_clk 94>, //CLK_TOP_APLL12_CK_DIV_I2SIN1
<&topckgen_clk 95>, //CLK_TOP_APLL12_CK_DIV_I2SOUT0
<&topckgen_clk 96>, //CLK_TOP_APLL12_CK_DIV_I2SOUT1
<&topckgen_clk 97>, //CLK_TOP_APLL12_CK_DIV_FMI2S
<&topckgen_clk 98>, //CLK_TOP_APLL12_CK_DIV_TDMOUT_M
<&topckgen_clk 99>, //CLK_TOP_APLL12_CK_DIV_TDMOUT_B
<&topckgen_clk 44>, //CLK_TOP_AUD_1_SEL
<&topckgen_clk 45>, //CLK_TOP_AUD_2_SEL
<&topckgen_clk 78>, //CLK_TOP_APLL_I2SIN0_MCK_SEL
<&topckgen_clk 79>, //CLK_TOP_APLL_I2SIN1_MCK_SEL
<&topckgen_clk 84>, //CLK_TOP_APLL_I2SOUT0_MCK_SEL
<&topckgen_clk 85>, //CLK_TOP_APLL_I2SOUT1_MCK_SEL
<&topckgen_clk 90>, //CLK_TOP_APLL_FMI2S_MCK_SEL
<&topckgen_clk 91>, //CLK_TOP_APLL_TDMOUT_MCK_SEL
<&topckgen_clk 191>, //CLK_TOP_TCK_26M_MX9
<&pericfg_ao_clk 77>, //CLK_PERAO_AUDIO0
<&pericfg_ao_clk 78>, //CLK_PERAO_AUDIO1
<&pericfg_ao_clk 79>; //CLK_PERAO_AUDIO2
clock-names = "top_aud_intbus",
"top_aud_eng1",
"top_aud_eng2",
"top_aud_h",
"apll1",
"apll2",
"apll1_d4",
"apll2_d4",
"apll12_div_i2sin0",
"apll12_div_i2sin1",
"apll12_div_i2sout0",
"apll12_div_i2sout1",
"apll12_div_fmi2s",
"apll12_div_tdmout_m",
"apll12_div_tdmout_b",
"top_apll1",
"top_apll2",
"top_i2sin0",
"top_i2sin1",
"top_i2sout0",
"top_i2sout1",
"top_fmi2s",
"top_dptx",
"clk26m",
"aud_slv_ck_peri",
"aud_mst_ck_peri",
"aud_intbus_ck_peri";
};
};
...
@@ -67,46 +67,72 @@ properties:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
if:
properties:
compatible:
contains:
const: nvidia,tegra210-admaif
allOf:
- if:
properties:
compatible:
contains:
const: nvidia,tegra210-admaif
then:
properties:
dmas:
description:
DMA channel specifiers, equally divided for Tx and Rx.
minItems: 1
maxItems: 20
dma-names:
items:
pattern: "^[rt]x(10|[1-9])$"
description:
Should be "rx1", "rx2" ... "rx10" for DMA Rx channel
Should be "tx1", "tx2" ... "tx10" for DMA Tx channel
minItems: 1
maxItems: 20
interconnects: false
interconnect-names: false
iommus: false
then:
properties:
dmas:
description:
DMA channel specifiers, equally divided for Tx and Rx.
minItems: 1
maxItems: 20
dma-names:
items:
pattern: "^[rt]x(10|[1-9])$"
description:
Should be "rx1", "rx2" ... "rx10" for DMA Rx channel
Should be "tx1", "tx2" ... "tx10" for DMA Tx channel
minItems: 1
maxItems: 20
interconnects: false
interconnect-names: false
iommus: false
- if:
properties:
compatible:
contains:
const: nvidia,tegra186-admaif
then:
properties:
dmas:
description:
DMA channel specifiers, equally divided for Tx and Rx.
minItems: 1
maxItems: 40
dma-names:
items:
pattern: "^[rt]x(1[0-9]|[1-9]|20)$"
description:
Should be "rx1", "rx2" ... "rx20" for DMA Rx channel
Should be "tx1", "tx2" ... "tx20" for DMA Tx channel
minItems: 1
maxItems: 40
else:
properties:
dmas:
description:
DMA channel specifiers, equally divided for Tx and Rx.
minItems: 1
maxItems: 40
dma-names:
items:
pattern: "^[rt]x(1[0-9]|[1-9]|20)$"
description:
Should be "rx1", "rx2" ... "rx20" for DMA Rx channel
Should be "tx1", "tx2" ... "tx20" for DMA Tx channel
minItems: 1
maxItems: 40
- if:
properties:
compatible:
contains:
const: nvidia,tegra264-admaif
then:
properties:
dmas:
description:
DMA channel specifiers, equally divided for Tx and Rx.
minItems: 1
maxItems: 64
dma-names:
items:
pattern: "^[rt]x(3[0-2]|[1-2][0-9]|[1-9])$"
description:
Should be "rx1", "rx2" ... "rx32" for DMA Rx channel
Should be "tx1", "tx2" ... "tx32" for DMA Tx channel
minItems: 1
maxItems: 64
required:
- compatible
@@ -1,42 +0,0 @@
Texas Instruments PCM186x Universal Audio ADC
These devices support both I2C and SPI (configured with pin strapping
on the board).
Required properties:
- compatible : "ti,pcm1862",
"ti,pcm1863",
"ti,pcm1864",
"ti,pcm1865"
- reg : The I2C address of the device for I2C, the chip select
number for SPI.
- avdd-supply: Analog core power supply (3.3v)
- dvdd-supply: Digital core power supply
- iovdd-supply: Digital IO power supply
See regulator/regulator.txt for more information
CODEC input pins:
* VINL1
* VINR1
* VINL2
* VINR2
* VINL3
* VINR3
* VINL4
* VINR4
The pins can be used in referring sound node's audio-routing property.
Example:
pcm186x: audio-codec@4a {
compatible = "ti,pcm1865";
reg = <0x4a>;
avdd-supply = <&reg_3v3_analog>;
dvdd-supply = <&reg_3v3>;
iovdd-supply = <&reg_1v8>;
};
@@ -23,6 +23,7 @@ properties:
- const: qcom,sdm845-sndcard
- items:
- enum:
- qcom,kaanapali-sndcard
- qcom,sm8550-sndcard
- qcom,sm8650-sndcard
- qcom,sm8750-sndcard
@@ -35,6 +36,7 @@ properties:
- qcom,qcs6490-rb3gen2-sndcard
- qcom,qcs9075-sndcard
- qcom,qcs9100-sndcard
- qcom,qrb2210-sndcard
- qcom,qrb4210-rb2-sndcard
- qcom,qrb5165-rb5-sndcard
- qcom,sc7180-qdsp6-sndcard
@@ -132,7 +132,7 @@ properties:
$ref: /schemas/gpio/qcom,wcd934x-gpio.yaml#
patternProperties:
"^.*@[0-9a-f]+$":
"@[0-9a-f]+$":
type: object
description: |
WCD934x subnode for each slave devices. Bindings of each subnodes
@@ -98,6 +98,7 @@ properties:
- 4 # Use GPIO2 for jack-detect
- 5 # Use GPIO3 for jack-detect
- 6 # Use GPIO4 for jack-detect
- 7 # Use HDA header for jack-detect
realtek,jack-detect-not-inverted:
description:
@@ -121,6 +122,10 @@ properties:
- 2 # Scale current by 1.0
- 3 # Scale current by 1.5
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- reg
@@ -64,6 +64,9 @@ properties:
"#sound-dai-cells":
const: 0
port:
$ref: /schemas/graph.yaml#/properties/port
required:
- compatible
- reg
@@ -0,0 +1,87 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/spacemit,k1-i2s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: K1 I2S controller
description:
The I2S bus (Inter-IC sound bus) is a serial link for digital
audio data transfer between devices in the system.
maintainers:
- Troy Mitchell <troy.mitchell@linux.spacemit.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: spacemit,k1-i2s
reg:
maxItems: 1
clocks:
items:
- description: clock for I2S sysclk
- description: clock for I2S bclk
- description: clock for I2S bus
- description: clock for I2S controller
clock-names:
items:
- const: sysclk
- const: bclk
- const: bus
- const: func
dmas:
minItems: 1
maxItems: 2
dma-names:
minItems: 1
items:
- const: tx
- const: rx
resets:
maxItems: 1
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
"#sound-dai-cells":
const: 0
required:
- compatible
- reg
- clocks
- clock-names
- dmas
- dma-names
- resets
- "#sound-dai-cells"
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/spacemit,k1-syscon.h>
i2s@d4026000 {
compatible = "spacemit,k1-i2s";
reg = <0xd4026000 0x30>;
clocks = <&syscon_mpmu CLK_I2S_SYSCLK>,
<&syscon_mpmu CLK_I2S_BCLK>,
<&syscon_apbc CLK_SSPA0_BUS>,
<&syscon_apbc CLK_SSPA0>;
clock-names = "sysclk", "bclk", "bus", "func";
dmas = <&pdma0 21>, <&pdma0 22>;
dma-names = "tx", "rx";
resets = <&syscon_apbc RESET_SSPA0>;
#sound-dai-cells = <0>;
};
@@ -0,0 +1,76 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,pcm1862.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments PCM186x Universal Audio ADC
maintainers:
- Ranganath V N <vnranganath.20@gmail.com>
description: |
The Texas Instruments PCM186x family are multi-channel audio ADCs
that support both I2C and SPI control interfaces, selected by
pin strapping. These devices include on-chip programmable gain
amplifiers and support differential or single-ended analog inputs.
CODEC input pins:
* VINL1
* VINR1
* VINL2
* VINR2
* VINL3
* VINR3
* VINL4
* VINR4
The pins can be used in referring sound node's audio-routing property.
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- ti,pcm1862
- ti,pcm1863
- ti,pcm1864
- ti,pcm1865
reg:
maxItems: 1
avdd-supply: true
dvdd-supply: true
iovdd-supply: true
'#sound-dai-cells':
const: 0
required:
- compatible
- reg
- avdd-supply
- dvdd-supply
- iovdd-supply
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
audio-codec@4a {
compatible = "ti,pcm1865";
reg = <0x4a>;
avdd-supply = <&reg_3v3_analog>;
dvdd-supply = <&reg_3v3>;
iovdd-supply = <&reg_1v8>;
};
};
@@ -24,21 +24,26 @@ description: |
Instruments Smart Amp speaker protection algorithm. The
integrated speaker voltage and current sense provides for real time
monitoring of loudspeaker behavior.
The TAS5802/TAS5815/TAS5825/TAS5827/TAS5828 is a stereo, digital input
Class-D audio amplifier optimized for efficiently driving high peak
power into small loudspeakers. An integrated on-chip DSP supports
Texas Instruments Smart Amp speaker protection algorithm.
The TAS5802/TAS5815/TAS5822/TAS5825/TAS5827/TAS5828 is a stereo,
digital input Class-D audio amplifier optimized for efficiently driving
high peak power into small loudspeakers. An integrated on-chip DSP
supports Texas Instruments Smart Amp speaker protection algorithm.
Specifications about the audio amplifier can be found at:
https://www.ti.com/lit/gpn/tas2120
https://www.ti.com/lit/gpn/tas2320
https://www.ti.com/lit/gpn/tas2563
https://www.ti.com/lit/gpn/tas2572
https://www.ti.com/lit/gpn/tas2574
https://www.ti.com/lit/gpn/tas2781
https://www.ti.com/lit/gpn/tas5806m
https://www.ti.com/lit/gpn/tas5806md
https://www.ti.com/lit/gpn/tas5815
https://www.ti.com/lit/gpn/tas5822m
https://www.ti.com/lit/gpn/tas5825m
https://www.ti.com/lit/gpn/tas5827
https://www.ti.com/lit/gpn/tas5828m
https://www.ti.com/lit/gpn/tas5830
properties:
compatible:
@@ -57,12 +62,18 @@ properties:
ti,tas2563: 6.1-W Boosted Class-D Audio Amplifier With Integrated
DSP and IV Sense, 16/20/24/32bit stereo I2S or multichannel TDM.
ti,tas2568: 5.3-W Digital Input Smart Amp with I/V Sense and Integrated
10.75-V Class-H Boost
ti,tas2570: 5.8-W Digital Input smart amp with I/V sense and integrated
11-V Class-H Boost
ti,tas2572: 6.6-W Digital Input smart amp with I/V sense and integrated
13-V Class-H Boost
ti,tas2574: 8.5-W Digital Input smart amp with I/V sense and integrated
15-V Class-H Boost
ti,tas2781: 24-V Class-D Amplifier with Real Time Integrated Speaker
Protection and Audio Processing, 16/20/24/32bit stereo I2S or
multichannel TDM.
@@ -71,9 +82,20 @@ properties:
Audio Amplifier with 96-Khz Extended Processing and Low Idle Power
Dissipation.
ti,tas5806m: 23-W, Inductor-Less, Digital Input, Stereo, Closed-Loop
Class-D Audio Amplifier with Enhanced Processing and Low Power
Dissipation.
ti,tas5806md: 23-W, Inductor-Less, Digital Input, Stereo, Closed-Loop
Class-D Audio Amplifier with Enhanced Processing and DirectPath(TM)
HP Driver
ti,tas5815: 30-W, Digital Input, Stereo, Closed-loop Class-D Audio
Amplifier with 96 kHz Enhanced Processing
ti,tas5822: 35-W, Digital Input, Stereo, Closed-Loop Class-D Audio
Amplifier with 96 kHz Enhanced Processing
ti,tas5825: 38-W Stereo, Inductor-Less, Digital Input, Closed-Loop 4.5V
to 26.4V Class-D Audio Amplifier with 192-kHz Extended Audio Processing.
@@ -82,6 +104,9 @@ properties:
ti,tas5828: 50-W Stereo, Digital Input, High Efficiency Closed-Loop
Class-D Amplifier with Hybrid-Pro Algorithm
ti,tas5830: 65-W Stereo, Digital Input, High Efficiency Closed-Loop
Class-D Amplifier with Class-H Algorithm
oneOf:
- items:
- enum:
@@ -90,13 +115,19 @@ properties:
- ti,tas2120
- ti,tas2320
- ti,tas2563
- ti,tas2568
- ti,tas2570
- ti,tas2572
- ti,tas2574
- ti,tas5802
- ti,tas5806m
- ti,tas5806md
- ti,tas5815
- ti,tas5822
- ti,tas5825
- ti,tas5827
- ti,tas5828
- ti,tas5830
- const: ti,tas2781
- enum:
- ti,tas2781
@@ -132,6 +163,8 @@ allOf:
- ti,tas2118
- ti,tas2120
- ti,tas2320
- ti,tas2568
- ti,tas2574
then:
properties:
reg:
@@ -207,6 +240,22 @@ allOf:
minimum: 0x54
maximum: 0x57
- if:
properties:
compatible:
contains:
enum:
- ti,tas5806m
- ti,tas5806md
- ti,tas5822
then:
properties:
reg:
maxItems: 4
items:
minimum: 0x2c
maximum: 0x2f
- if:
properties:
compatible:
@@ -214,6 +263,7 @@ allOf:
enum:
- ti,tas5827
- ti,tas5828
- ti,tas5830
then:
properties:
reg:
+1 -1
View File
@@ -388,7 +388,7 @@ static const char table_sigs[][ACPI_NAMESEG_SIZE] __initconst = {
ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT,
ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT,
ACPI_SIG_NHLT, ACPI_SIG_AEST, ACPI_SIG_CEDT, ACPI_SIG_AGDI,
ACPI_SIG_NBFT };
ACPI_SIG_NBFT, ACPI_SIG_SWFT};
#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
+1
View File
@@ -186,6 +186,7 @@ struct regcache_ops {
enum regcache_type type;
int (*init)(struct regmap *map);
int (*exit)(struct regmap *map);
int (*populate)(struct regmap *map);
#ifdef CONFIG_DEBUG_FS
void (*debugfs_init)(struct regmap *map);
#endif
+27 -31
View File
@@ -95,12 +95,13 @@ static int regcache_maple_write(struct regmap *map, unsigned int reg,
mas_unlock(&mas);
if (ret == 0) {
kfree(lower);
kfree(upper);
if (ret) {
kfree(entry);
return ret;
}
return ret;
kfree(lower);
kfree(upper);
return 0;
}
static int regcache_maple_drop(struct regmap *map, unsigned int min,
@@ -290,6 +291,23 @@ out:
return ret;
}
static int regcache_maple_init(struct regmap *map)
{
struct maple_tree *mt;
mt = kmalloc(sizeof(*mt), map->alloc_flags);
if (!mt)
return -ENOMEM;
map->cache = mt;
mt_init(mt);
if (!mt_external_lock(mt) && map->lock_key)
lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1);
return 0;
}
static int regcache_maple_exit(struct regmap *map)
{
struct maple_tree *mt = map->cache;
@@ -341,26 +359,12 @@ static int regcache_maple_insert_block(struct regmap *map, int first,
return ret;
}
static int regcache_maple_init(struct regmap *map)
static int regcache_maple_populate(struct regmap *map)
{
struct maple_tree *mt;
int i;
int ret;
int range_start;
mt = kmalloc(sizeof(*mt), map->alloc_flags);
if (!mt)
return -ENOMEM;
map->cache = mt;
mt_init(mt);
if (!mt_external_lock(mt) && map->lock_key)
lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1);
if (!map->num_reg_defaults)
return 0;
range_start = 0;
/* Scan for ranges of contiguous registers */
@@ -370,23 +374,14 @@ static int regcache_maple_init(struct regmap *map)
ret = regcache_maple_insert_block(map, range_start,
i - 1);
if (ret != 0)
goto err;
return ret;
range_start = i;
}
}
/* Add the last block */
ret = regcache_maple_insert_block(map, range_start,
map->num_reg_defaults - 1);
if (ret != 0)
goto err;
return 0;
err:
regcache_maple_exit(map);
return ret;
return regcache_maple_insert_block(map, range_start, map->num_reg_defaults - 1);
}
struct regcache_ops regcache_maple_ops = {
@@ -394,6 +389,7 @@ struct regcache_ops regcache_maple_ops = {
.name = "maple",
.init = regcache_maple_init,
.exit = regcache_maple_exit,
.populate = regcache_maple_populate,
.read = regcache_maple_read,
.write = regcache_maple_write,
.drop = regcache_maple_drop,
+16
View File
@@ -221,8 +221,24 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
if (ret)
goto err_free;
}
if (map->num_reg_defaults && map->cache_ops->populate) {
dev_dbg(map->dev, "Populating %s cache\n", map->cache_ops->name);
map->lock(map->lock_arg);
ret = map->cache_ops->populate(map);
map->unlock(map->lock_arg);
if (ret)
goto err_exit;
}
return 0;
err_exit:
if (map->cache_ops->exit) {
dev_dbg(map->dev, "Destroying %s cache\n", map->cache_ops->name);
map->lock(map->lock_arg);
ret = map->cache_ops->exit(map);
map->unlock(map->lock_arg);
}
err_free:
kfree(map->reg_defaults);
if (map->cache_free)
+14 -12
View File
@@ -15,11 +15,13 @@
struct regmap_mbq_context {
struct device *dev;
struct sdw_slave *sdw;
bool (*readable_reg)(struct device *dev, unsigned int reg);
struct regmap_sdw_mbq_cfg cfg;
int val_size;
bool (*readable_reg)(struct device *dev, unsigned int reg);
};
static int regmap_sdw_mbq_size(struct regmap_mbq_context *ctx, unsigned int reg)
@@ -46,7 +48,7 @@ static bool regmap_sdw_mbq_deferrable(struct regmap_mbq_context *ctx, unsigned i
static int regmap_sdw_mbq_poll_busy(struct sdw_slave *slave, unsigned int reg,
struct regmap_mbq_context *ctx)
{
struct device *dev = &slave->dev;
struct device *dev = ctx->dev;
int val, ret = 0;
dev_dbg(dev, "Deferring transaction for 0x%x\n", reg);
@@ -96,8 +98,7 @@ static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave,
static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
{
struct regmap_mbq_context *ctx = context;
struct device *dev = ctx->dev;
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct sdw_slave *slave = ctx->sdw;
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
int ret;
@@ -156,8 +157,7 @@ static int regmap_sdw_mbq_read_impl(struct sdw_slave *slave,
static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val)
{
struct regmap_mbq_context *ctx = context;
struct device *dev = ctx->dev;
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct sdw_slave *slave = ctx->sdw;
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
int ret;
@@ -208,6 +208,7 @@ static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
static struct regmap_mbq_context *
regmap_sdw_mbq_gen_context(struct device *dev,
struct sdw_slave *sdw,
const struct regmap_config *config,
const struct regmap_sdw_mbq_cfg *mbq_config)
{
@@ -218,6 +219,7 @@ regmap_sdw_mbq_gen_context(struct device *dev,
return ERR_PTR(-ENOMEM);
ctx->dev = dev;
ctx->sdw = sdw;
if (mbq_config)
ctx->cfg = *mbq_config;
@@ -228,7 +230,7 @@ regmap_sdw_mbq_gen_context(struct device *dev,
return ctx;
}
struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
struct regmap *__regmap_init_sdw_mbq(struct device *dev, struct sdw_slave *sdw,
const struct regmap_config *config,
const struct regmap_sdw_mbq_cfg *mbq_config,
struct lock_class_key *lock_key,
@@ -241,16 +243,16 @@ struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
if (ret)
return ERR_PTR(ret);
ctx = regmap_sdw_mbq_gen_context(&sdw->dev, config, mbq_config);
ctx = regmap_sdw_mbq_gen_context(dev, sdw, config, mbq_config);
if (IS_ERR(ctx))
return ERR_CAST(ctx);
return __regmap_init(&sdw->dev, &regmap_sdw_mbq, ctx,
return __regmap_init(dev, &regmap_sdw_mbq, ctx,
config, lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__regmap_init_sdw_mbq);
struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
struct regmap *__devm_regmap_init_sdw_mbq(struct device *dev, struct sdw_slave *sdw,
const struct regmap_config *config,
const struct regmap_sdw_mbq_cfg *mbq_config,
struct lock_class_key *lock_key,
@@ -263,11 +265,11 @@ struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
if (ret)
return ERR_PTR(ret);
ctx = regmap_sdw_mbq_gen_context(&sdw->dev, config, mbq_config);
ctx = regmap_sdw_mbq_gen_context(dev, sdw, config, mbq_config);
if (IS_ERR(ctx))
return ERR_CAST(ctx);
return __devm_regmap_init(&sdw->dev, &regmap_sdw_mbq, ctx,
return __devm_regmap_init(dev, &regmap_sdw_mbq, ctx,
config, lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
+91 -101
View File
@@ -9,9 +9,11 @@
* Cirrus Logic International Semiconductor Ltd.
*/
#include <linux/cleanup.h>
#include <linux/ctype.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/math.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -316,44 +318,6 @@ struct cs_dsp_alg_region_list_item {
struct cs_dsp_alg_region alg_region;
};
struct cs_dsp_buf {
struct list_head list;
void *buf;
};
static struct cs_dsp_buf *cs_dsp_buf_alloc(const void *src, size_t len,
struct list_head *list)
{
struct cs_dsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (buf == NULL)
return NULL;
buf->buf = vmalloc(len);
if (!buf->buf) {
kfree(buf);
return NULL;
}
memcpy(buf->buf, src, len);
if (list)
list_add_tail(&buf->list, list);
return buf;
}
static void cs_dsp_buf_free(struct list_head *list)
{
while (!list_empty(list)) {
struct cs_dsp_buf *buf = list_first_entry(list,
struct cs_dsp_buf,
list);
list_del(&buf->list);
vfree(buf->buf);
kfree(buf);
}
}
/**
* cs_dsp_mem_region_name() - Return a name string for a memory type
* @type: the memory type to match
@@ -388,18 +352,14 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_mem_region_name, FW_CS_DSP);
#ifdef CONFIG_DEBUG_FS
static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s)
{
char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
kfree(dsp->wmfw_file_name);
dsp->wmfw_file_name = tmp;
dsp->wmfw_file_name = kstrdup(s, GFP_KERNEL);
}
static void cs_dsp_debugfs_save_binname(struct cs_dsp *dsp, const char *s)
{
char *tmp = kasprintf(GFP_KERNEL, "%s\n", s);
kfree(dsp->bin_file_name);
dsp->bin_file_name = tmp;
dsp->bin_file_name = kstrdup(s, GFP_KERNEL);
}
static void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
@@ -410,24 +370,38 @@ static void cs_dsp_debugfs_clear(struct cs_dsp *dsp)
dsp->bin_file_name = NULL;
}
static ssize_t cs_dsp_debugfs_string_read(struct cs_dsp *dsp,
char __user *user_buf,
size_t count, loff_t *ppos,
const char **pstr)
{
const char *str;
ssize_t ret = 0;
scoped_guard(mutex, &dsp->pwr_lock) {
if (*pstr) {
str = kasprintf(GFP_KERNEL, "%s\n", *pstr);
if (str) {
ret = simple_read_from_buffer(user_buf, count,
ppos, str, strlen(str));
kfree(str);
} else {
ret = -ENOMEM;
}
}
}
return ret;
}
static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct cs_dsp *dsp = file->private_data;
ssize_t ret;
mutex_lock(&dsp->pwr_lock);
if (!dsp->wmfw_file_name || !dsp->booted)
ret = 0;
else
ret = simple_read_from_buffer(user_buf, count, ppos,
dsp->wmfw_file_name,
strlen(dsp->wmfw_file_name));
mutex_unlock(&dsp->pwr_lock);
return ret;
return cs_dsp_debugfs_string_read(dsp, user_buf, count, ppos,
&dsp->wmfw_file_name);
}
static ssize_t cs_dsp_debugfs_bin_read(struct file *file,
@@ -435,19 +409,9 @@ static ssize_t cs_dsp_debugfs_bin_read(struct file *file,
size_t count, loff_t *ppos)
{
struct cs_dsp *dsp = file->private_data;
ssize_t ret;
mutex_lock(&dsp->pwr_lock);
if (!dsp->bin_file_name || !dsp->booted)
ret = 0;
else
ret = simple_read_from_buffer(user_buf, count, ppos,
dsp->bin_file_name,
strlen(dsp->bin_file_name));
mutex_unlock(&dsp->pwr_lock);
return ret;
return cs_dsp_debugfs_string_read(dsp, user_buf, count, ppos,
&dsp->bin_file_name);
}
static const struct {
@@ -479,9 +443,11 @@ static int cs_dsp_debugfs_read_controls_show(struct seq_file *s, void *ignored)
struct cs_dsp_coeff_ctl *ctl;
unsigned int reg;
guard(mutex)(&dsp->pwr_lock);
list_for_each_entry(ctl, &dsp->ctl_list, list) {
cs_dsp_coeff_base_reg(ctl, &reg, 0);
seq_printf(s, "%22.*s: %#8zx %s:%08x %#8x %s %#8x %#4x %c%c%c%c %s %s\n",
seq_printf(s, "%22.*s: %#8x %s:%08x %#8x %s %#8x %#4x %c%c%c%c %s %s\n",
ctl->subname_len, ctl->subname, ctl->len,
cs_dsp_mem_region_name(ctl->alg_region.type),
ctl->offset, reg, ctl->fw_name, ctl->alg_region.alg, ctl->type,
@@ -1028,7 +994,7 @@ static void cs_dsp_signal_event_controls(struct cs_dsp *dsp,
static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl)
{
kfree(ctl->cache);
kvfree(ctl->cache);
kfree(ctl->subname);
kfree(ctl);
}
@@ -1078,7 +1044,7 @@ static int cs_dsp_create_control(struct cs_dsp *dsp,
ctl->type = type;
ctl->offset = offset;
ctl->len = len;
ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
ctl->cache = kvzalloc(ctl->len, GFP_KERNEL);
if (!ctl->cache) {
ret = -ENOMEM;
goto err_ctl_subname;
@@ -1096,7 +1062,7 @@ static int cs_dsp_create_control(struct cs_dsp *dsp,
err_list_del:
list_del(&ctl->list);
kfree(ctl->cache);
kvfree(ctl->cache);
err_ctl_subname:
kfree(ctl->subname);
err_ctl:
@@ -1485,7 +1451,9 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
const struct wmfw_region *region;
const struct cs_dsp_region *mem;
const char *region_name;
struct cs_dsp_buf *buf;
u8 *buf = NULL;
size_t buf_len = 0;
size_t region_len;
unsigned int reg;
int regions = 0;
int ret, offset, type;
@@ -1605,23 +1573,29 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
region_name);
if (reg) {
buf = cs_dsp_buf_alloc(region->data,
le32_to_cpu(region->len),
&buf_list);
if (!buf) {
cs_dsp_err(dsp, "Out of memory\n");
ret = -ENOMEM;
goto out_fw;
/*
* Although we expect the underlying bus does not require
* physically-contiguous buffers, we pessimistically use
* a temporary buffer instead of trusting that the
* alignment of region->data is ok.
*/
region_len = le32_to_cpu(region->len);
if (region_len > buf_len) {
buf_len = round_up(region_len, PAGE_SIZE);
vfree(buf);
buf = vmalloc(buf_len);
if (!buf) {
ret = -ENOMEM;
goto out_fw;
}
}
ret = regmap_raw_write(regmap, reg, buf->buf,
le32_to_cpu(region->len));
memcpy(buf, region->data, region_len);
ret = regmap_raw_write(regmap, reg, buf, region_len);
if (ret != 0) {
cs_dsp_err(dsp,
"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
file, regions,
le32_to_cpu(region->len), offset,
region_name, ret);
"%s.%d: Failed to write %zu bytes at %d in %s: %d\n",
file, regions, region_len, offset, region_name, ret);
goto out_fw;
}
}
@@ -1638,7 +1612,7 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
ret = 0;
out_fw:
cs_dsp_buf_free(&buf_list);
vfree(buf);
if (ret == -EOVERFLOW)
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
@@ -2171,7 +2145,9 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
struct cs_dsp_alg_region *alg_region;
const char *region_name;
int ret, pos, blocks, type, offset, reg, version;
struct cs_dsp_buf *buf;
u8 *buf = NULL;
size_t buf_len = 0;
size_t region_len;
if (!firmware)
return 0;
@@ -2313,20 +2289,28 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
}
if (reg) {
buf = cs_dsp_buf_alloc(blk->data,
le32_to_cpu(blk->len),
&buf_list);
if (!buf) {
cs_dsp_err(dsp, "Out of memory\n");
ret = -ENOMEM;
goto out_fw;
/*
* Although we expect the underlying bus does not require
* physically-contiguous buffers, we pessimistically use
* a temporary buffer instead of trusting that the
* alignment of blk->data is ok.
*/
region_len = le32_to_cpu(blk->len);
if (region_len > buf_len) {
buf_len = round_up(region_len, PAGE_SIZE);
vfree(buf);
buf = vmalloc(buf_len);
if (!buf) {
ret = -ENOMEM;
goto out_fw;
}
}
cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
file, blocks, le32_to_cpu(blk->len),
reg);
ret = regmap_raw_write(regmap, reg, buf->buf,
le32_to_cpu(blk->len));
memcpy(buf, blk->data, region_len);
cs_dsp_dbg(dsp, "%s.%d: Writing %zu bytes at %x\n",
file, blocks, region_len, reg);
ret = regmap_raw_write(regmap, reg, buf, region_len);
if (ret != 0) {
cs_dsp_err(dsp,
"%s.%d: Failed to write to %x in %s: %d\n",
@@ -2346,7 +2330,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
ret = 0;
out_fw:
cs_dsp_buf_free(&buf_list);
vfree(buf);
if (ret == -EOVERFLOW)
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
@@ -2366,6 +2350,9 @@ static int cs_dsp_create_name(struct cs_dsp *dsp)
return 0;
}
static const struct cs_dsp_client_ops cs_dsp_default_client_ops = {
};
static int cs_dsp_common_init(struct cs_dsp *dsp)
{
int ret;
@@ -2379,6 +2366,9 @@ static int cs_dsp_common_init(struct cs_dsp *dsp)
mutex_init(&dsp->pwr_lock);
if (!dsp->client_ops)
dsp->client_ops = &cs_dsp_default_client_ops;
#ifdef CONFIG_DEBUG_FS
/* Ensure this is invalid if client never provides a debugfs root */
dsp->debugfs_root = ERR_PTR(-ENODEV);
+8 -2
View File
@@ -2052,8 +2052,14 @@ EXPORT_SYMBOL(sdw_clear_slave_status);
int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
{
if (msg->len > SDW_BPT_MSG_MAX_BYTES) {
dev_err(bus->dev, "Invalid BPT message length %d\n", msg->len);
int len = 0;
int i;
for (i = 0; i < msg->sections; i++)
len += msg->sec[i].len;
if (len > SDW_BPT_MSG_MAX_BYTES) {
dev_err(bus->dev, "Invalid BPT message length %d\n", len);
return -EINVAL;
}
+16 -6
View File
@@ -73,21 +73,31 @@ struct sdw_msg {
};
/**
* struct sdw_btp_msg - Message structure
* struct sdw_btp_section - Message section structure
* @addr: Start Register address accessed in the Slave
* @len: number of bytes to transfer. More than 64Kb can be transferred
* but a practical limit of SDW_BPT_MSG_MAX_BYTES is enforced.
* @dev_num: Slave device number
* @flags: transfer flags, indicate if xfer is read or write
* @buf: message data buffer (filled by host for write, filled
* @buf: section data buffer (filled by host for write, filled
* by Peripheral hardware for reads)
*/
struct sdw_bpt_msg {
struct sdw_bpt_section {
u32 addr;
u32 len;
u8 *buf;
};
/**
* struct sdw_btp_msg - Message structure
* @sec: Pointer to array of sections
* @sections: Number of sections in the array
* @dev_num: Slave device number
* @flags: transfer flags, indicate if xfer is read or write
*/
struct sdw_bpt_msg {
struct sdw_bpt_section *sec;
int sections;
u8 dev_num;
u8 flags;
u8 *buf;
};
#define SDW_DOUBLE_RATE_FACTOR 2
+1 -1
View File
@@ -105,7 +105,7 @@ static int sdw_drv_probe(struct device *dev)
if (ret)
return ret;
ret = ida_alloc_max(&slave->bus->slave_ida, SDW_FW_MAX_DEVICES, GFP_KERNEL);
ret = ida_alloc_max(&slave->bus->slave_ida, SDW_FW_MAX_DEVICES - 1, GFP_KERNEL);
if (ret < 0) {
dev_err(dev, "Failed to allocated ID: %d\n", ret);
return ret;
+171 -66
View File
@@ -2094,6 +2094,36 @@ static unsigned int sdw_cdns_read_pdi1_buffer_size(unsigned int actual_data_size
return total * 2;
}
int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */
int row, int col, int frame_rate,
unsigned int *tx_dma_bandwidth,
unsigned int *rx_dma_bandwidth)
{
unsigned int bpt_bits = row * (col - 1);
unsigned int bpt_bytes = bpt_bits >> 3;
unsigned int pdi0_buffer_size;
unsigned int pdi1_buffer_size;
unsigned int data_per_frame;
data_per_frame = sdw_cdns_bra_actual_data_size(bpt_bytes);
if (!data_per_frame)
return -EINVAL;
if (command == 0) {
pdi0_buffer_size = sdw_cdns_write_pdi0_buffer_size(data_per_frame);
pdi1_buffer_size = SDW_CDNS_WRITE_PDI1_BUFFER_SIZE;
} else {
pdi0_buffer_size = SDW_CDNS_READ_PDI0_BUFFER_SIZE;
pdi1_buffer_size = sdw_cdns_read_pdi1_buffer_size(data_per_frame);
}
*tx_dma_bandwidth = pdi0_buffer_size * 8 * frame_rate;
*rx_dma_bandwidth = pdi1_buffer_size * 8 * frame_rate;
return 0;
}
EXPORT_SYMBOL(sdw_cdns_bpt_find_bandwidth);
int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
int row, int col, unsigned int data_bytes,
unsigned int requested_bytes_per_frame,
@@ -2114,9 +2144,6 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
if (!actual_bpt_bytes)
return -EINVAL;
if (data_bytes < actual_bpt_bytes)
actual_bpt_bytes = data_bytes;
/*
* the caller may want to set the number of bytes per frame,
* allow when possible
@@ -2126,6 +2153,9 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
*data_per_frame = actual_bpt_bytes;
if (data_bytes < actual_bpt_bytes)
actual_bpt_bytes = data_bytes;
if (command == 0) {
/*
* for writes we need to send all the data_bytes per frame,
@@ -2294,17 +2324,20 @@ static int sdw_cdns_prepare_read_pd0_buffer(u8 *header, unsigned int header_size
#define CDNS_BPT_ROLLING_COUNTER_START 1
int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
int *dma_buffer_total_bytes)
int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer,
int dma_buffer_size, int *dma_buffer_total_bytes)
{
int total_dma_data_written = 0;
u8 *p_dma_buffer = dma_buffer;
u8 header[SDW_CDNS_BRA_HDR];
unsigned int start_register;
unsigned int section_size;
int dma_data_written;
u8 *p_data = data;
u8 *p_data;
u8 counter;
int ret;
int i;
counter = CDNS_BPT_ROLLING_COUNTER_START;
@@ -2312,47 +2345,57 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,
header[0] |= GENMASK(7, 6); /* header is active */
header[0] |= (dev_num << 2);
while (data_size >= data_per_frame) {
header[1] = data_per_frame;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
for (i = 0; i < num_sec; i++) {
start_register = sec[i].addr;
section_size = sec[i].len;
p_data = sec[i].buf;
ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
p_data, data_per_frame,
p_dma_buffer, dma_buffer_size,
&dma_data_written, counter);
if (ret < 0)
return ret;
while (section_size >= data_per_frame) {
header[1] = data_per_frame;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
counter++;
ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
p_data, data_per_frame,
p_dma_buffer, dma_buffer_size,
&dma_data_written, counter);
if (ret < 0)
return ret;
p_data += data_per_frame;
data_size -= data_per_frame;
counter++;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
p_data += data_per_frame;
section_size -= data_per_frame;
start_register += data_per_frame;
}
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
if (data_size) {
header[1] = data_size;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
start_register += data_per_frame;
}
ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
p_data, data_size,
p_dma_buffer, dma_buffer_size,
&dma_data_written, counter);
if (ret < 0)
return ret;
if (section_size) {
header[1] = section_size;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
total_dma_data_written += dma_data_written;
ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
p_data, section_size,
p_dma_buffer, dma_buffer_size,
&dma_data_written, counter);
if (ret < 0)
return ret;
counter++;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
}
}
*dma_buffer_total_bytes = total_dma_data_written;
@@ -2361,16 +2404,19 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,
}
EXPORT_SYMBOL(sdw_cdns_prepare_write_dma_buffer);
int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size,
int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
int *dma_buffer_total_bytes)
int *dma_buffer_total_bytes, unsigned int fake_size)
{
int total_dma_data_written = 0;
u8 *p_dma_buffer = dma_buffer;
u8 header[SDW_CDNS_BRA_HDR];
unsigned int start_register;
unsigned int data_size;
int dma_data_written;
u8 counter;
int ret;
int i;
counter = CDNS_BPT_ROLLING_COUNTER_START;
@@ -2378,13 +2424,58 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
header[0] |= GENMASK(7, 6); /* header is active */
header[0] |= (dev_num << 2);
while (data_size >= data_per_frame) {
header[1] = data_per_frame;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
for (i = 0; i < num_sec; i++) {
start_register = sec[i].addr;
data_size = sec[i].len;
while (data_size >= data_per_frame) {
header[1] = data_per_frame;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR,
p_dma_buffer, dma_buffer_size,
&dma_data_written, counter);
if (ret < 0)
return ret;
counter++;
data_size -= data_per_frame;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
start_register += data_per_frame;
}
if (data_size) {
header[1] = data_size;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR,
p_dma_buffer, dma_buffer_size,
&dma_data_written, counter);
if (ret < 0)
return ret;
counter++;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
}
}
/* Add fake frame */
header[0] &= ~GENMASK(7, 6); /* Set inactive flag in BPT/BRA frame heade */
while (fake_size >= data_per_frame) {
header[1] = data_per_frame;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written,
counter);
@@ -2393,28 +2484,24 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
counter++;
data_size -= data_per_frame;
fake_size -= data_per_frame;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
start_register += data_per_frame;
}
if (data_size) {
header[1] = data_size;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
if (fake_size) {
header[1] = fake_size;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written,
counter);
if (ret < 0)
return ret;
counter++;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
}
@@ -2495,14 +2582,14 @@ int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
ret = check_frame_start(header, counter);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d start header %x\n",
__func__, i, num_frames, header);
__func__, i + 1, num_frames, header);
return ret;
}
ret = check_frame_end(footer);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d end footer %x\n",
__func__, i, num_frames, footer);
__func__, i + 1, num_frames, footer);
return ret;
}
@@ -2549,9 +2636,12 @@ static u8 extract_read_data(u32 *data, int num_bytes, u8 *buffer)
}
int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size,
u8 *buffer, int buffer_size, int num_frames, int data_per_frame)
struct sdw_bpt_section *sec, int num_sec, int num_frames,
int data_per_frame)
{
int total_num_bytes = 0;
int buffer_size = 0;
int sec_index;
u32 *p_data;
u8 *p_buf;
int counter;
@@ -2565,7 +2655,10 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
counter = CDNS_BPT_ROLLING_COUNTER_START;
p_data = (u32 *)dma_buffer;
p_buf = buffer;
sec_index = 0;
p_buf = sec[sec_index].buf;
buffer_size = sec[sec_index].len;
for (i = 0; i < num_frames; i++) {
header = *p_data++;
@@ -2573,7 +2666,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
ret = check_frame_start(header, counter);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d start header %x\n",
__func__, i, num_frames, header);
__func__, i + 1, num_frames, header);
return ret;
}
@@ -2588,7 +2681,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
if (crc != expected_crc) {
dev_err(dev, "%s: bad frame %d/%d crc %#x expected %#x\n",
__func__, i, num_frames, crc, expected_crc);
__func__, i + 1, num_frames, crc, expected_crc);
return -EIO;
}
@@ -2599,12 +2692,24 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
ret = check_frame_end(footer);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d end footer %x\n",
__func__, i, num_frames, footer);
__func__, i + 1, num_frames, footer);
return ret;
}
counter++;
counter &= GENMASK(3, 0);
if (buffer_size == total_num_bytes && (i + 1) < num_frames) {
sec_index++;
if (sec_index >= num_sec) {
dev_err(dev, "%s: incorrect section index %d i %d\n",
__func__, sec_index, i);
return -EINVAL;
}
p_buf = sec[sec_index].buf;
buffer_size = sec[sec_index].len;
total_num_bytes = 0;
}
}
return 0;
}
+13 -6
View File
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/* Copyright(c) 2015-17 Intel Corporation. */
#include <sound/soc.h>
#include "bus.h"
#ifndef __SDW_CADENCE_H
#define __SDW_CADENCE_H
@@ -209,23 +210,29 @@ void sdw_cdns_config_update(struct sdw_cdns *cdns);
int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns);
/* SoundWire BPT/BRA helpers to format data */
int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */
int row, int col, int frame_rate,
unsigned int *tx_dma_bandwidth,
unsigned int *rx_dma_bandwidth);
int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
int row, int col, unsigned int data_bytes,
unsigned int requested_bytes_per_frame,
unsigned int *data_per_frame, unsigned int *pdi0_buffer_size,
unsigned int *pdi1_buffer_size, unsigned int *num_frames);
int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
int *dma_buffer_total_bytes);
int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer,
int dma_buffer_size, int *dma_buffer_total_bytes);
int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size,
int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
int *dma_buffer_total_bytes);
int *dma_buffer_total_bytes, unsigned int fake_size);
int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
int dma_buffer_size, int num_frames);
int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size,
u8 *buffer, int buffer_size, int num_frames, int data_per_frame);
struct sdw_bpt_section *sec, int num_sec, int num_frames,
int data_per_frame);
#endif /* __SDW_CADENCE_H */
+11 -3
View File
@@ -222,15 +222,23 @@ DEFINE_DEBUGFS_ATTRIBUTE(set_num_bytes_fops, NULL,
static int do_bpt_sequence(struct sdw_slave *slave, bool write, u8 *buffer)
{
struct sdw_bpt_msg msg = {0};
struct sdw_bpt_section *sec;
msg.addr = start_addr;
msg.len = num_bytes;
sec = kcalloc(1, sizeof(*sec), GFP_KERNEL);
if (!sec)
return -ENOMEM;
msg.sections = 1;
sec[0].addr = start_addr;
sec[0].len = num_bytes;
msg.sec = sec;
msg.dev_num = slave->dev_num;
if (write)
msg.flags = SDW_MSG_FLAG_WRITE;
else
msg.flags = SDW_MSG_FLAG_READ;
msg.buf = buffer;
sec[0].buf = buffer;
return sdw_bpt_send_sync(slave->bus, slave, &msg);
}
@@ -124,6 +124,9 @@ static void sdw_compute_dp0_port_params(struct sdw_bus *bus)
struct sdw_master_runtime *m_rt;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
/* DP0 is for BPT only */
if (m_rt->stream->type != SDW_STREAM_BPT)
continue;
sdw_compute_dp0_master_ports(m_rt);
sdw_compute_dp0_slave_ports(m_rt);
}
+89 -15
View File
@@ -44,6 +44,8 @@ static int sdw_slave_bpt_stream_add(struct sdw_slave *slave, struct sdw_stream_r
return ret;
}
#define READ_PDI1_MIN_SIZE 12
static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *slave,
struct sdw_bpt_msg *msg)
{
@@ -53,19 +55,31 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
struct sdw_stream_runtime *stream;
struct sdw_stream_config sconfig;
struct sdw_port_config *pconfig;
unsigned int pdi0_buf_size_pre_frame;
unsigned int pdi1_buf_size_pre_frame;
unsigned int pdi0_buffer_size_;
unsigned int pdi1_buffer_size_;
unsigned int pdi0_buffer_size;
unsigned int tx_dma_bandwidth;
unsigned int pdi1_buffer_size;
unsigned int rx_dma_bandwidth;
unsigned int fake_num_frames;
unsigned int data_per_frame;
unsigned int tx_total_bytes;
struct sdw_cdns_pdi *pdi0;
struct sdw_cdns_pdi *pdi1;
unsigned int rx_alignment;
unsigned int tx_alignment;
unsigned int num_frames_;
unsigned int num_frames;
unsigned int fake_size;
unsigned int tx_pad;
unsigned int rx_pad;
int command;
int ret1;
int ret;
int dir;
int len;
int i;
stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT);
@@ -138,23 +152,77 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1;
ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col,
msg->len, SDW_BPT_MSG_MAX_BYTES, &data_per_frame,
&pdi0_buffer_size, &pdi1_buffer_size, &num_frames);
ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row,
cdns->bus.params.col,
prop->default_frame_rate,
&tx_dma_bandwidth, &rx_dma_bandwidth);
if (ret < 0)
goto deprepare_stream;
len = 0;
pdi0_buffer_size = 0;
pdi1_buffer_size = 0;
num_frames = 0;
/* Add up pdi buffer size and frame numbers of each BPT sections */
for (i = 0; i < msg->sections; i++) {
ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row,
cdns->bus.params.col,
msg->sec[i].len, SDW_BPT_MSG_MAX_BYTES,
&data_per_frame, &pdi0_buffer_size_,
&pdi1_buffer_size_, &num_frames_);
if (ret < 0)
goto deprepare_stream;
len += msg->sec[i].len;
pdi0_buffer_size += pdi0_buffer_size_;
pdi1_buffer_size += pdi1_buffer_size_;
num_frames += num_frames_;
}
sdw->bpt_ctx.pdi0_buffer_size = pdi0_buffer_size;
sdw->bpt_ctx.pdi1_buffer_size = pdi1_buffer_size;
sdw->bpt_ctx.num_frames = num_frames;
sdw->bpt_ctx.data_per_frame = data_per_frame;
tx_dma_bandwidth = div_u64((u64)pdi0_buffer_size * 8 * (u64)prop->default_frame_rate,
num_frames);
rx_dma_bandwidth = div_u64((u64)pdi1_buffer_size * 8 * (u64)prop->default_frame_rate,
num_frames);
rx_alignment = hda_sdw_bpt_get_buf_size_alignment(rx_dma_bandwidth);
tx_alignment = hda_sdw_bpt_get_buf_size_alignment(tx_dma_bandwidth);
if (command) { /* read */
/* Get buffer size of a full frame */
ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row,
cdns->bus.params.col,
data_per_frame, SDW_BPT_MSG_MAX_BYTES,
&data_per_frame, &pdi0_buf_size_pre_frame,
&pdi1_buf_size_pre_frame, &fake_num_frames);
if (ret < 0)
goto deprepare_stream;
/* find fake pdi1 buffer size */
rx_pad = rx_alignment - (pdi1_buffer_size % rx_alignment);
while (rx_pad <= READ_PDI1_MIN_SIZE)
rx_pad += rx_alignment;
pdi1_buffer_size += rx_pad;
/* It is fine if we request more than enough byte to read */
fake_num_frames = DIV_ROUND_UP(rx_pad, pdi1_buf_size_pre_frame);
fake_size = fake_num_frames * data_per_frame;
/* find fake pdi0 buffer size */
pdi0_buffer_size += (fake_num_frames * pdi0_buf_size_pre_frame);
tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment);
pdi0_buffer_size += tx_pad;
} else { /* write */
/*
* For the write command, the rx data block is 4, and the rx buffer size of a frame
* is 8. So the rx buffer size (pdi0_buffer_size) is always a multiple of rx
* alignment.
*/
tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment);
pdi0_buffer_size += tx_pad;
}
dev_dbg(cdns->dev, "Message len %d transferred in %d frames (%d per frame)\n",
msg->len, num_frames, data_per_frame);
len, num_frames, data_per_frame);
dev_dbg(cdns->dev, "sizes pdi0 %d pdi1 %d tx_bandwidth %d rx_bandwidth %d\n",
pdi0_buffer_size, pdi1_buffer_size, tx_dma_bandwidth, rx_dma_bandwidth);
@@ -169,15 +237,16 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
}
if (!command) {
ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->addr, msg->buf,
msg->len, data_per_frame,
ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->sec, msg->sections,
data_per_frame,
sdw->bpt_ctx.dmab_tx_bdl.area,
pdi0_buffer_size, &tx_total_bytes);
} else {
ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->addr, msg->len,
ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->sec, msg->sections,
data_per_frame,
sdw->bpt_ctx.dmab_tx_bdl.area,
pdi0_buffer_size, &tx_total_bytes);
pdi0_buffer_size, &tx_total_bytes,
fake_size);
}
if (!ret)
@@ -252,11 +321,16 @@ static int intel_ace2x_bpt_send_async(struct sdw_intel *sdw, struct sdw_slave *s
struct sdw_bpt_msg *msg)
{
struct sdw_cdns *cdns = &sdw->cdns;
int len = 0;
int ret;
int i;
if (msg->len < INTEL_BPT_MSG_BYTE_MIN) {
for (i = 0; i < msg->sections; i++)
len += msg->sec[i].len;
if (len < INTEL_BPT_MSG_BYTE_MIN) {
dev_err(cdns->dev, "BPT message length %d is less than the minimum bytes %d\n",
msg->len, INTEL_BPT_MSG_BYTE_MIN);
len, INTEL_BPT_MSG_BYTE_MIN);
return -EINVAL;
}
@@ -316,7 +390,7 @@ static int intel_ace2x_bpt_wait(struct sdw_intel *sdw, struct sdw_slave *slave,
} else {
ret = sdw_cdns_check_read_response(cdns->dev, sdw->bpt_ctx.dmab_rx_bdl.area,
sdw->bpt_ctx.pdi1_buffer_size,
msg->buf, msg->len, sdw->bpt_ctx.num_frames,
msg->sec, msg->sections, sdw->bpt_ctx.num_frames,
sdw->bpt_ctx.data_per_frame);
if (ret < 0)
dev_err(cdns->dev, "%s: BPT Read failed %d\n", __func__, ret);
+154 -103
View File
@@ -31,6 +31,7 @@
#define SWRM_VERSION_1_5_1 0x01050001
#define SWRM_VERSION_1_7_0 0x01070000
#define SWRM_VERSION_2_0_0 0x02000000
#define SWRM_VERSION_3_1_0 0x03010000
#define SWRM_COMP_HW_VERSION 0x00
#define SWRM_COMP_CFG_ADDR 0x04
#define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1)
@@ -40,6 +41,9 @@
#define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15)
#define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0)
#define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5)
#define SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(17, 10)
#define SWRM_V3_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(23, 18)
#define SWRM_COMP_MASTER_ID 0x104
#define SWRM_V1_3_INTERRUPT_STATUS 0x200
#define SWRM_V2_0_INTERRUPT_STATUS 0x5000
@@ -99,14 +103,15 @@
#define SWRM_MCP_SLV_STATUS 0x1090
#define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0)
#define SWRM_MCP_SLV_STATUS_SZ 2
#define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1))
#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_SAMPLECTRL2_BANK(n, m) (0x113C + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1))
#define SWRM_DPn_PORT_CTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DPn_PORT_CTRL_2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DPn_BLOCK_CTRL_1(offset, n) (offset + 0x100 * (n - 1))
#define SWRM_DPn_BLOCK_CTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DPn_PORT_HCTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DPn_BLOCK_CTRL3_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DPn_SAMPLECTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWR_V1_3_MSTR_MAX_REG_ADDR 0x1740
#define SWR_V2_0_MSTR_MAX_REG_ADDR 0x50ac
@@ -128,7 +133,6 @@
#define MAX_FREQ_NUM 1
#define TIMEOUT_MS 100
#define QCOM_SWRM_MAX_RD_LEN 0x1
#define QCOM_SDW_MAX_PORTS 14
#define DEFAULT_CLK_FREQ 9600000
#define SWRM_MAX_DAIS 0xF
#define SWR_INVALID_PARAM 0xFF
@@ -172,6 +176,13 @@ enum {
SWRM_REG_CMD_FIFO_RD_CMD,
SWRM_REG_CMD_FIFO_STATUS,
SWRM_REG_CMD_FIFO_RD_FIFO_ADDR,
SWRM_OFFSET_DP_PORT_CTRL_BANK,
SWRM_OFFSET_DP_PORT_CTRL_2_BANK,
SWRM_OFFSET_DP_BLOCK_CTRL_1,
SWRM_OFFSET_DP_BLOCK_CTRL2_BANK,
SWRM_OFFSET_DP_PORT_HCTRL_BANK,
SWRM_OFFSET_DP_BLOCK_CTRL3_BANK,
SWRM_OFFSET_DP_SAMPLECTRL2_BANK,
};
struct qcom_swrm_ctrl {
@@ -195,6 +206,7 @@ struct qcom_swrm_ctrl {
int wake_irq;
int num_din_ports;
int num_dout_ports;
int nports;
int cols_index;
int rows_index;
unsigned long port_mask;
@@ -202,14 +214,13 @@ struct qcom_swrm_ctrl {
u8 rcmd_id;
u8 wcmd_id;
/* Port numbers are 1 - 14 */
struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS + 1];
struct qcom_swrm_port_config *pconfig;
struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
u32 slave_status;
u32 wr_fifo_depth;
u32 rd_fifo_depth;
bool clock_stop_not_supported;
};
@@ -231,6 +242,13 @@ static const unsigned int swrm_v1_3_reg_layout[] = {
[SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V1_3_CMD_FIFO_RD_CMD,
[SWRM_REG_CMD_FIFO_STATUS] = SWRM_V1_3_CMD_FIFO_STATUS,
[SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V1_3_CMD_FIFO_RD_FIFO_ADDR,
[SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124,
[SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128,
[SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c,
[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130,
[SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134,
[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138,
[SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c,
};
static const struct qcom_swrm_data swrm_v1_3_data = {
@@ -265,6 +283,13 @@ static const unsigned int swrm_v2_0_reg_layout[] = {
[SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD,
[SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS,
[SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR,
[SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124,
[SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128,
[SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c,
[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130,
[SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134,
[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138,
[SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c,
};
static const struct qcom_swrm_data swrm_v2_0_data = {
@@ -275,6 +300,32 @@ static const struct qcom_swrm_data swrm_v2_0_data = {
.reg_layout = swrm_v2_0_reg_layout,
};
static const unsigned int swrm_v3_0_reg_layout[] = {
[SWRM_REG_FRAME_GEN_ENABLED] = SWRM_V2_0_LINK_STATUS,
[SWRM_REG_INTERRUPT_STATUS] = SWRM_V2_0_INTERRUPT_STATUS,
[SWRM_REG_INTERRUPT_MASK_ADDR] = 0, /* Not present */
[SWRM_REG_INTERRUPT_CLEAR] = SWRM_V2_0_INTERRUPT_CLEAR,
[SWRM_REG_INTERRUPT_CPU_EN] = SWRM_V2_0_INTERRUPT_CPU_EN,
[SWRM_REG_CMD_FIFO_WR_CMD] = SWRM_V2_0_CMD_FIFO_WR_CMD,
[SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD,
[SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS,
[SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR,
[SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1224,
[SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1228,
[SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x122c,
[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1230,
[SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1234,
[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1238,
[SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x123c,
};
static const struct qcom_swrm_data swrm_v3_0_data = {
.default_rows = 50,
.default_cols = 16,
.sw_clk_gate_required = true,
.max_reg = SWR_V2_0_MSTR_MAX_REG_ADDR,
.reg_layout = swrm_v3_0_reg_layout,
};
#define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
@@ -898,8 +949,11 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
swrm_wait_for_frame_gen_enabled(ctrl);
ctrl->slave_status = 0;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
ctrl->rd_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_RD_FIFO_DEPTH, val);
ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val);
if (ctrl->version >= SWRM_VERSION_3_1_0)
ctrl->wr_fifo_depth = FIELD_GET(SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH, val);
else
ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val);
return 0;
}
@@ -966,10 +1020,10 @@ static int qcom_swrm_port_params(struct sdw_bus *bus,
unsigned int bank)
{
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL_1];
return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num),
p_params->bps - 1);
return ctrl->reg_write(ctrl, SWRM_DPn_BLOCK_CTRL_1(offset, p_params->num),
p_params->bps - 1);
}
static int qcom_swrm_transport_params(struct sdw_bus *bus,
@@ -979,9 +1033,11 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
struct qcom_swrm_port_config *pcfg;
u32 value;
int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank);
int reg, offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK];
int ret;
reg = SWRM_DPn_PORT_CTRL_BANK(offset, params->port_num, bank);
pcfg = &ctrl->pconfig[params->port_num];
value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
@@ -993,15 +1049,19 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
goto err;
if (pcfg->si > 0xff) {
offset = ctrl->reg_layout[SWRM_OFFSET_DP_SAMPLECTRL2_BANK];
value = (pcfg->si >> 8) & 0xff;
reg = SWRM_DP_SAMPLECTRL2_BANK(params->port_num, bank);
reg = SWRM_DPn_SAMPLECTRL2_BANK(offset, params->port_num, bank);
ret = ctrl->reg_write(ctrl, reg, value);
if (ret)
goto err;
}
if (pcfg->lane_control != SWR_INVALID_PARAM) {
reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank);
offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_2_BANK];
reg = SWRM_DPn_PORT_CTRL_2_BANK(offset, params->port_num, bank);
value = pcfg->lane_control;
ret = ctrl->reg_write(ctrl, reg, value);
if (ret)
@@ -1009,20 +1069,23 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
}
if (pcfg->blk_group_count != SWR_INVALID_PARAM) {
reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank);
offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK];
reg = SWRM_DPn_BLOCK_CTRL2_BANK(offset, params->port_num, bank);
value = pcfg->blk_group_count;
ret = ctrl->reg_write(ctrl, reg, value);
if (ret)
goto err;
}
if (pcfg->hstart != SWR_INVALID_PARAM
&& pcfg->hstop != SWR_INVALID_PARAM) {
reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_HCTRL_BANK];
reg = SWRM_DPn_PORT_HCTRL_BANK(offset, params->port_num, bank);
if (pcfg->hstart != SWR_INVALID_PARAM && pcfg->hstop != SWR_INVALID_PARAM) {
value = (pcfg->hstop << 4) | pcfg->hstart;
ret = ctrl->reg_write(ctrl, reg, value);
} else {
reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
ret = ctrl->reg_write(ctrl, reg, value);
}
@@ -1031,7 +1094,8 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
goto err;
if (pcfg->bp_mode != SWR_INVALID_PARAM) {
reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK];
reg = SWRM_DPn_BLOCK_CTRL3_BANK(offset, params->port_num, bank);
ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode);
}
@@ -1043,9 +1107,12 @@ static int qcom_swrm_port_enable(struct sdw_bus *bus,
struct sdw_enable_ch *enable_ch,
unsigned int bank)
{
u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank);
u32 reg;
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
u32 val;
u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK];
reg = SWRM_DPn_PORT_CTRL_BANK(offset, enable_ch->port_num, bank);
ctrl->reg_read(ctrl, reg, &val);
@@ -1155,7 +1222,6 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
struct snd_pcm_hw_params *params,
int direction)
{
struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS];
struct sdw_stream_config sconfig;
struct sdw_master_runtime *m_rt;
struct sdw_slave_runtime *s_rt;
@@ -1164,6 +1230,10 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
unsigned long *port_mask;
int maxport, pn, nports = 0, ret = 0;
unsigned int m_port;
struct sdw_port_config *pconfig __free(kfree) = kcalloc(ctrl->nports,
sizeof(*pconfig), GFP_KERNEL);
if (!pconfig)
return -ENOMEM;
if (direction == SNDRV_PCM_STREAM_CAPTURE)
sconfig.direction = SDW_DATA_DIR_TX;
@@ -1188,8 +1258,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
continue;
port_mask = &ctrl->port_mask;
maxport = ctrl->num_dout_ports + ctrl->num_din_ports;
maxport = ctrl->nports;
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave = s_rt->slave;
@@ -1349,17 +1418,8 @@ static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl)
static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
{
struct device_node *np = ctrl->dev->of_node;
u8 off1[QCOM_SDW_MAX_PORTS];
u8 off2[QCOM_SDW_MAX_PORTS];
u16 si[QCOM_SDW_MAX_PORTS];
u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, };
u8 hstart[QCOM_SDW_MAX_PORTS];
u8 hstop[QCOM_SDW_MAX_PORTS];
u8 word_length[QCOM_SDW_MAX_PORTS];
u8 blk_group_count[QCOM_SDW_MAX_PORTS];
u8 lane_control[QCOM_SDW_MAX_PORTS];
int i, ret, nports, val;
bool si_16 = false;
struct qcom_swrm_port_config *pcfg;
int i, ret, val;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
@@ -1367,88 +1427,78 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
ctrl->num_din_ports = FIELD_GET(SWRM_COMP_PARAMS_DIN_PORTS_MASK, val);
ret = of_property_read_u32(np, "qcom,din-ports", &val);
if (ret)
return ret;
if (!ret) { /* only if present */
if (val != ctrl->num_din_ports) {
dev_err(ctrl->dev, "din-ports (%d) mismatch with controller (%d)",
val, ctrl->num_din_ports);
}
if (val > ctrl->num_din_ports)
return -EINVAL;
ctrl->num_din_ports = val;
ctrl->num_din_ports = val;
}
ret = of_property_read_u32(np, "qcom,dout-ports", &val);
if (ret)
return ret;
if (!ret) { /* only if present */
if (val != ctrl->num_dout_ports) {
dev_err(ctrl->dev, "dout-ports (%d) mismatch with controller (%d)",
val, ctrl->num_dout_ports);
}
if (val > ctrl->num_dout_ports)
return -EINVAL;
ctrl->num_dout_ports = val;
}
ctrl->num_dout_ports = val;
ctrl->nports = ctrl->num_dout_ports + ctrl->num_din_ports;
nports = ctrl->num_dout_ports + ctrl->num_din_ports;
if (nports > QCOM_SDW_MAX_PORTS)
return -EINVAL;
ctrl->pconfig = devm_kcalloc(ctrl->dev, ctrl->nports + 1,
sizeof(*ctrl->pconfig), GFP_KERNEL);
if (!ctrl->pconfig)
return -ENOMEM;
/* Valid port numbers are from 1-14, so mask out port 0 explicitly */
set_bit(0, &ctrl->port_mask);
/* Valid port numbers are from 1, so mask out port 0 explicitly */
for (i = 0; i < ctrl->nports; i++) {
pcfg = &ctrl->pconfig[i + 1];
ret = of_property_read_u8_array(np, "qcom,ports-offset1",
off1, nports);
if (ret)
return ret;
ret = of_property_read_u8_array(np, "qcom,ports-offset2",
off2, nports);
if (ret)
return ret;
ret = of_property_read_u8_array(np, "qcom,ports-sinterval-low",
(u8 *)si, nports);
if (ret) {
ret = of_property_read_u16_array(np, "qcom,ports-sinterval",
si, nports);
ret = of_property_read_u8_index(np, "qcom,ports-offset1", i, &pcfg->off1);
if (ret)
return ret;
si_16 = true;
}
ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode",
bp_mode, nports);
if (ret) {
if (ctrl->version <= SWRM_VERSION_1_3_0)
memset(bp_mode, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
else
ret = of_property_read_u8_index(np, "qcom,ports-offset2", i, &pcfg->off2);
if (ret)
return ret;
}
memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports);
ret = of_property_read_u8_index(np, "qcom,ports-sinterval-low", i, (u8 *)&pcfg->si);
if (ret) {
ret = of_property_read_u16_index(np, "qcom,ports-sinterval", i, &pcfg->si);
if (ret)
return ret;
}
memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports);
ret = of_property_read_u8_index(np, "qcom,ports-block-pack-mode",
i, &pcfg->bp_mode);
if (ret) {
if (ctrl->version <= SWRM_VERSION_1_3_0)
pcfg->bp_mode = SWR_INVALID_PARAM;
else
return ret;
}
memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports);
/* Optional properties */
pcfg->hstart = SWR_INVALID_PARAM;
pcfg->hstop = SWR_INVALID_PARAM;
pcfg->word_length = SWR_INVALID_PARAM;
pcfg->blk_group_count = SWR_INVALID_PARAM;
pcfg->lane_control = SWR_INVALID_PARAM;
memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports);
of_property_read_u8_index(np, "qcom,ports-hstart", i, &pcfg->hstart);
memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports);
of_property_read_u8_index(np, "qcom,ports-hstop", i, &pcfg->hstop);
for (i = 0; i < nports; i++) {
/* Valid port number range is from 1-14 */
if (si_16)
ctrl->pconfig[i + 1].si = si[i];
else
ctrl->pconfig[i + 1].si = ((u8 *)si)[i];
ctrl->pconfig[i + 1].off1 = off1[i];
ctrl->pconfig[i + 1].off2 = off2[i];
ctrl->pconfig[i + 1].bp_mode = bp_mode[i];
ctrl->pconfig[i + 1].hstart = hstart[i];
ctrl->pconfig[i + 1].hstop = hstop[i];
ctrl->pconfig[i + 1].word_length = word_length[i];
ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i];
ctrl->pconfig[i + 1].lane_control = lane_control[i];
of_property_read_u8_index(np, "qcom,ports-word-length", i, &pcfg->word_length);
of_property_read_u8_index(np, "qcom,ports-block-group-count",
i, &pcfg->blk_group_count);
of_property_read_u8_index(np, "qcom,ports-lane-control", i, &pcfg->lane_control);
}
return 0;
@@ -1769,6 +1819,7 @@ static const struct of_device_id qcom_swrm_of_match[] = {
{ .compatible = "qcom,soundwire-v1.6.0", .data = &swrm_v1_6_data },
{ .compatible = "qcom,soundwire-v1.7.0", .data = &swrm_v1_5_data },
{ .compatible = "qcom,soundwire-v2.0.0", .data = &swrm_v2_0_data },
{ .compatible = "qcom,soundwire-v3.1.0", .data = &swrm_v3_0_data },
{/* sentinel */},
};
+1
View File
@@ -23,6 +23,7 @@ const struct device_type sdw_slave_type = {
.release = sdw_slave_release,
.uevent = sdw_slave_uevent,
};
EXPORT_SYMBOL_GPL(sdw_slave_type);
int sdw_slave_add(struct sdw_bus *bus,
struct sdw_slave_id *id, struct fwnode_handle *fwnode)
+21
View File
@@ -51,6 +51,7 @@
#define ACPI_SIG_SDEI "SDEI" /* Software Delegated Exception Interface Table */
#define ACPI_SIG_SDEV "SDEV" /* Secure Devices table */
#define ACPI_SIG_SVKL "SVKL" /* Storage Volume Key Location Table */
#define ACPI_SIG_SWFT "SWFT" /* SoundWire File Table */
#define ACPI_SIG_TDEL "TDEL" /* TD Event Log Table */
/*
@@ -2569,6 +2570,26 @@ enum acpi_svkl_format {
ACPI_SVKL_FORMAT_RESERVED = 1 /* 1 and greater are reserved */
};
/*******************************************************************************
* SWFT - SoundWire File Table
*
* Conforms to "Discovery and Configuration (DisCo) Specification for SoundWire"
* Version 2.1, 2 October 2023
*
******************************************************************************/
struct acpi_sw_file {
u16 vendor_id;
u32 file_id;
u16 file_version;
u32 file_length;
u8 data[];
};
struct acpi_table_swft {
struct acpi_table_header header;
struct acpi_sw_file files[];
};
/*******************************************************************************
*
* TDEL - TD-Event Log
+3 -3
View File
@@ -104,7 +104,7 @@ struct cs_dsp_coeff_ctl {
struct list_head list;
void *cache;
unsigned int offset;
size_t len;
unsigned int len;
unsigned int set:1;
unsigned int flags;
unsigned int type;
@@ -188,8 +188,8 @@ struct cs_dsp {
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
char *wmfw_file_name;
char *bin_file_name;
const char *wmfw_file_name;
const char *bin_file_name;
#endif
};
+1
View File
@@ -3049,6 +3049,7 @@
#define PCI_DEVICE_ID_INTEL_5100_22 0x65f6
#define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff
#define PCI_DEVICE_ID_INTEL_HDA_FCL 0x67a8
#define PCI_DEVICE_ID_INTEL_HDA_NVL_S 0x6e50
#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
+11 -10
View File
@@ -669,7 +669,7 @@ struct regmap *__regmap_init_sdw(struct sdw_slave *sdw,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
struct regmap *__regmap_init_sdw_mbq(struct device *dev, struct sdw_slave *sdw,
const struct regmap_config *config,
const struct regmap_sdw_mbq_cfg *mbq_config,
struct lock_class_key *lock_key,
@@ -731,7 +731,7 @@ struct regmap *__devm_regmap_init_sdw(struct sdw_slave *sdw,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
struct regmap *__devm_regmap_init_sdw_mbq(struct device *dev, struct sdw_slave *sdw,
const struct regmap_config *config,
const struct regmap_sdw_mbq_cfg *mbq_config,
struct lock_class_key *lock_key,
@@ -963,7 +963,7 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
*/
#define regmap_init_sdw_mbq(sdw, config) \
__regmap_lockdep_wrapper(__regmap_init_sdw_mbq, #config, \
sdw, config, NULL)
&sdw->dev, sdw, config, NULL)
/**
* regmap_init_sdw_mbq_cfg() - Initialise MBQ SDW register map with config
@@ -976,9 +976,9 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
#define regmap_init_sdw_mbq_cfg(sdw, config, mbq_config) \
#define regmap_init_sdw_mbq_cfg(dev, sdw, config, mbq_config) \
__regmap_lockdep_wrapper(__regmap_init_sdw_mbq, #config, \
sdw, config, mbq_config)
dev, sdw, config, mbq_config)
/**
* regmap_init_spi_avmm() - Initialize register map for Intel SPI Slave
@@ -1191,12 +1191,13 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
*/
#define devm_regmap_init_sdw_mbq(sdw, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_sdw_mbq, #config, \
sdw, config, NULL)
&sdw->dev, sdw, config, NULL)
/**
* devm_regmap_init_sdw_mbq_cfg() - Initialise managed MBQ SDW register map with config
*
* @sdw: Device that will be interacted with
* @dev: Device that will be interacted with
* @sdw: SoundWire Device that will be interacted with
* @config: Configuration for register map
* @mbq_config: Properties for the MBQ registers
*
@@ -1204,9 +1205,9 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
#define devm_regmap_init_sdw_mbq_cfg(sdw, config, mbq_config) \
__regmap_lockdep_wrapper(__devm_regmap_init_sdw_mbq, \
#config, sdw, config, mbq_config)
#define devm_regmap_init_sdw_mbq_cfg(dev, sdw, config, mbq_config) \
__regmap_lockdep_wrapper(__devm_regmap_init_sdw_mbq, \
#config, dev, sdw, config, mbq_config)
/**
* devm_regmap_init_slimbus() - Initialise managed register map
+2
View File
@@ -355,4 +355,6 @@
/* Check the reserved and fixed bits in address */
#define SDW_SDCA_VALID_CTL(reg) (((reg) & (GENMASK(31, 25) | BIT(18) | BIT(13))) == BIT(30))
#define SDW_SDCA_MAX_REGISTER 0x47FFFFFF
#endif /* __SDW_REGISTERS_H */
+9
View File
@@ -12,6 +12,15 @@
* Digital audio interface *
* *
****************************************************************************/
/* IEC958 subframe format */
#define IEC958_SUBFRAME_PREAMBLE_MASK (0xfU)
#define IEC958_SUBFRAME_AUXILIARY_MASK (0xfU << 4)
#define IEC958_SUBFRAME_SAMPLE_24_MASK (0xffffffU << 4)
#define IEC958_SUBFRAME_SAMPLE_20_MASK (0xfffffU << 8)
#define IEC958_SUBFRAME_VALIDITY (0x1U << 28)
#define IEC958_SUBFRAME_USER_DATA (0x1U << 29)
#define IEC958_SUBFRAME_CHANNEL_STATUS (0x1U << 30)
#define IEC958_SUBFRAME_PARITY (0x1U << 31)
/* AES/IEC958 channel status bits */
#define IEC958_AES0_PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */
+24 -1
View File
@@ -47,21 +47,44 @@ struct cirrus_amp_cal_controls {
int cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
const struct cirrus_amp_cal_controls *controls,
const struct cirrus_amp_cal_data *data);
int cs_amp_read_cal_coeffs(struct cs_dsp *dsp,
const struct cirrus_amp_cal_controls *controls,
struct cirrus_amp_cal_data *data);
int cs_amp_write_ambient_temp(struct cs_dsp *dsp,
const struct cirrus_amp_cal_controls *controls,
u32 temp);
int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index,
struct cirrus_amp_cal_data *out_data);
int cs_amp_set_efi_calibration_data(struct device *dev, int amp_index, int num_amps,
const struct cirrus_amp_cal_data *in_data);
int cs_amp_get_vendor_spkid(struct device *dev);
struct dentry *cs_amp_create_debugfs(struct device *dev);
static inline u64 cs_amp_cal_target_u64(const struct cirrus_amp_cal_data *data)
{
return ((u64)data->calTarget[1] << 32) | data->calTarget[0];
}
struct cs_amp_test_hooks {
efi_status_t (*get_efi_variable)(efi_char16_t *name,
efi_guid_t *guid,
u32 *returned_attr,
unsigned long *size,
void *buf);
efi_status_t (*set_efi_variable)(efi_char16_t *name,
efi_guid_t *guid,
u32 attr,
unsigned long size,
void *buf);
int (*write_cal_coeff)(struct cs_dsp *dsp,
const struct cirrus_amp_cal_controls *controls,
const char *ctl_name, u32 val);
};
int (*read_cal_coeff)(struct cs_dsp *dsp,
const struct cirrus_amp_cal_controls *controls,
const char *ctl_name, u32 *val);
};
extern const struct cs_amp_test_hooks * const cs_amp_test_hooks;
#endif /* CS_AMP_LIB_H */
+50
View File
@@ -9,12 +9,15 @@
#ifndef __CS35L56_H
#define __CS35L56_H
#include <linux/debugfs.h>
#include <linux/firmware/cirrus/cs_dsp.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <sound/cs-amp-lib.h>
struct snd_ctl_elem_value;
#define CS35L56_DEVID 0x0000000
#define CS35L56_REVID 0x0000004
#define CS35L56_RELID 0x000000C
@@ -62,6 +65,8 @@
#define CS35L56_IRQ1_MASK_8 0x000E0AC
#define CS35L56_IRQ1_MASK_18 0x000E0D4
#define CS35L56_IRQ1_MASK_20 0x000E0DC
#define CS35L56_MIXER_NGATE_CH1_CFG 0x0010004
#define CS35L56_MIXER_NGATE_CH2_CFG 0x0010008
#define CS35L56_DSP_MBOX_1_RAW 0x0011000
#define CS35L56_DSP_VIRTUAL1_MBOX_1 0x0011020
#define CS35L56_DSP_VIRTUAL1_MBOX_2 0x0011024
@@ -175,6 +180,9 @@
/* IRQ1_EINT_8 */
#define CS35L56_TEMP_ERR_EINT1_MASK 0x80000000
/* MIXER_NGATE_CHn_CFG */
#define CS35L56_AUX_NGATE_CHn_EN 0x00000001
/* Mixer input sources */
#define CS35L56_INPUT_SRC_NONE 0x00
#define CS35L56_INPUT_SRC_ASP1RX1 0x08
@@ -241,6 +249,7 @@
#define CS35L56_MBOX_CMD_AUDIO_PLAY 0x0B000001
#define CS35L56_MBOX_CMD_AUDIO_PAUSE 0x0B000002
#define CS35L56_MBOX_CMD_AUDIO_REINIT 0x0B000003
#define CS35L56_MBOX_CMD_AUDIO_CALIBRATION 0x0B000006
#define CS35L56_MBOX_CMD_HIBERNATE_NOW 0x02000001
#define CS35L56_MBOX_CMD_WAKEUP 0x02000002
#define CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE 0x02000003
@@ -256,12 +265,22 @@
#define CS35L56_PS3_POLL_US 500
#define CS35L56_PS3_TIMEOUT_US 300000
#define CS35L56_CAL_STATUS_SUCCESS 1
#define CS35L56_CAL_STATUS_OUT_OF_RANGE 3
#define CS35L56_CAL_SET_STATUS_UNKNOWN 0
#define CS35L56_CAL_SET_STATUS_DEFAULT 1
#define CS35L56_CAL_SET_STATUS_SET 2
#define CS35L56_CONTROL_PORT_READY_US 2200
#define CS35L56_HALO_STATE_POLL_US 1000
#define CS35L56_HALO_STATE_TIMEOUT_US 250000
#define CS35L56_RESET_PULSE_MIN_US 1100
#define CS35L56_WAKE_HOLD_TIME_US 1000
#define CS35L56_CALIBRATION_POLL_US (100 * USEC_PER_MSEC)
#define CS35L56_CALIBRATION_TIMEOUT_US (5 * USEC_PER_SEC)
#define CS35L56_SDW1_PLAYBACK_PORT 1
#define CS35L56_SDW1_CAPTURE_PORT 3
@@ -289,9 +308,16 @@ struct cs35l56_fw_reg {
unsigned int posture_number;
};
struct cs35l56_cal_debugfs_fops {
const struct debugfs_short_fops calibrate;
const struct debugfs_short_fops cal_temperature;
const struct debugfs_short_fops cal_data;
};
struct cs35l56_base {
struct device *dev;
struct regmap *regmap;
struct cs_dsp *dsp;
int irq;
struct mutex irq_lock;
u8 type;
@@ -302,11 +328,14 @@ struct cs35l56_base {
bool can_hibernate;
bool cal_data_valid;
s8 cal_index;
u8 num_amps;
struct cirrus_amp_cal_data cal_data;
struct gpio_desc *reset_gpio;
struct cs35l56_spi_payload *spi_payload_buf;
const struct cs35l56_fw_reg *fw_reg;
const struct cirrus_amp_cal_controls *calibration_controls;
struct dentry *debugfs;
u64 silicon_uid;
};
static inline bool cs35l56_is_otp_register(unsigned int reg)
@@ -338,6 +367,7 @@ extern const struct regmap_config cs35l63_regmap_i2c;
extern const struct regmap_config cs35l63_regmap_sdw;
extern const struct cirrus_amp_cal_controls cs35l56_calibration_controls;
extern const char * const cs35l56_cal_set_status_text[3];
extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
@@ -356,8 +386,28 @@ int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base);
int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire);
void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base);
int cs35l56_stash_calibration(struct cs35l56_base *cs35l56_base,
const struct cirrus_amp_cal_data *data);
ssize_t cs35l56_calibrate_debugfs_write(struct cs35l56_base *cs35l56_base,
const char __user *from, size_t count,
loff_t *ppos);
ssize_t cs35l56_cal_ambient_debugfs_write(struct cs35l56_base *cs35l56_base,
const char __user *from, size_t count,
loff_t *ppos);
ssize_t cs35l56_cal_data_debugfs_read(struct cs35l56_base *cs35l56_base,
char __user *to, size_t count,
loff_t *ppos);
ssize_t cs35l56_cal_data_debugfs_write(struct cs35l56_base *cs35l56_base,
const char __user *from, size_t count,
loff_t *ppos);
void cs35l56_create_cal_debugfs(struct cs35l56_base *cs35l56_base,
const struct cs35l56_cal_debugfs_fops *fops);
void cs35l56_remove_cal_debugfs(struct cs35l56_base *cs35l56_base);
int cs35l56_cal_set_status_get(struct cs35l56_base *cs35l56_base,
struct snd_ctl_elem_value *uvalue);
int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
bool *fw_missing, unsigned int *fw_version);
void cs35l56_warn_if_firmware_missing(struct cs35l56_base *cs35l56_base);
void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
int cs35l56_hw_init(struct cs35l56_base *cs35l56_base);
int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base);
+7
View File
@@ -30,6 +30,8 @@ int hda_sdw_bpt_wait(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
struct snd_dma_buffer *dmab_tx_bdl, struct hdac_ext_stream *bpt_rx_stream,
struct snd_dma_buffer *dmab_rx_bdl);
unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth);
#else
static inline int hda_sdw_bpt_open(struct device *dev, int link_id,
struct hdac_ext_stream **bpt_tx_stream,
@@ -64,6 +66,11 @@ static inline int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *
WARN_ONCE(1, "SoundWire BPT is disabled");
return -EOPNOTSUPP;
}
static inline unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth)
{
return 0;
}
#endif
#endif /* __HDA_SDW_BPT_H */
+3
View File
@@ -380,6 +380,9 @@ struct hdac_bus {
/* factor used to derive STRIPE control value */
unsigned int sdo_limit;
/* address offset between host and hadc */
dma_addr_t addr_offset;
};
int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
+1 -1
View File
@@ -1402,7 +1402,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s
#define snd_pcm_lib_mmap_iomem NULL
#endif
void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime);
int snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime);
/**
* snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer
+19
View File
@@ -12,19 +12,24 @@
#include <linux/types.h>
#include <linux/kconfig.h>
struct acpi_table_swft;
struct fwnode_handle;
struct sdw_slave;
struct sdca_dev;
#define SDCA_MAX_FUNCTION_COUNT 8
/**
* struct sdca_function_desc - short descriptor for an SDCA Function
* @node: firmware node for the Function.
* @func_dev: pointer to SDCA function device.
* @name: Human-readable string.
* @type: Function topology type.
* @adr: ACPI address (used for SDCA register access).
*/
struct sdca_function_desc {
struct fwnode_handle *node;
struct sdca_dev *func_dev;
const char *name;
u32 type;
u8 adr;
@@ -37,11 +42,13 @@ struct sdca_function_desc {
* @num_functions: Total number of supported SDCA functions. Invalid/unsupported
* functions will be skipped.
* @function: Array of function descriptors.
* @swft: Pointer to the SWFT table, if available.
*/
struct sdca_device_data {
u32 interface_revision;
int num_functions;
struct sdca_function_desc function[SDCA_MAX_FUNCTION_COUNT];
struct acpi_table_swft *swft;
};
enum sdca_quirk {
@@ -52,17 +59,29 @@ enum sdca_quirk {
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA)
void sdca_lookup_functions(struct sdw_slave *slave);
void sdca_lookup_swft(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);
int sdca_dev_register_functions(struct sdw_slave *slave);
void sdca_dev_unregister_functions(struct sdw_slave *slave);
#else
static inline void sdca_lookup_functions(struct sdw_slave *slave) {}
static inline void sdca_lookup_swft(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;
}
static inline int sdca_dev_register_functions(struct sdw_slave *slave)
{
return 0;
}
static inline void sdca_dev_unregister_functions(struct sdw_slave *slave) {}
#endif
#endif
+105
View File
@@ -0,0 +1,105 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* The MIPI SDCA specification is available for public downloads at
* https://www.mipi.org/mipi-sdca-v1-0-download
*
* Copyright (C) 2025 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
*/
#ifndef __SDCA_FDL_H__
#define __SDCA_FDL_H__
#include <linux/completion.h>
#include <linux/workqueue.h>
struct device;
struct regmap;
struct sdca_fdl_set;
struct sdca_function_data;
struct sdca_interrupt;
struct sdca_interrupt_info;
/**
* struct fdl_state - FDL state structure to keep data between interrupts
* @begin: Completion indicating the start of an FDL download cycle.
* @done: Completion indicating the end of an FDL download cycle.
* @timeout: Delayed work used for timing out UMP transactions.
* @lock: Mutex to protect between the timeout work and IRQ handlers.
* @interrupt: Pointer to the interrupt struct to which this FDL is attached.
* @set: Pointer to the FDL set currently being downloaded.
* @file_index: Index of the current file being processed.
*/
struct fdl_state {
struct completion begin;
struct completion done;
struct delayed_work timeout;
struct mutex lock;
struct sdca_interrupt *interrupt;
struct sdca_fdl_set *set;
int file_index;
};
#define SDCA_CTL_XU_FDLH_COMPLETE 0
#define SDCA_CTL_XU_FDLH_MORE_FILES SDCA_CTL_XU_FDLH_SET_IN_PROGRESS
#define SDCA_CTL_XU_FDLH_FILE_AVAILABLE (SDCA_CTL_XU_FDLH_TRANSFERRED_FILE | \
SDCA_CTL_XU_FDLH_SET_IN_PROGRESS)
#define SDCA_CTL_XU_FDLH_MASK (SDCA_CTL_XU_FDLH_TRANSFERRED_CHUNK | \
SDCA_CTL_XU_FDLH_TRANSFERRED_FILE | \
SDCA_CTL_XU_FDLH_SET_IN_PROGRESS | \
SDCA_CTL_XU_FDLH_RESET_ACK | \
SDCA_CTL_XU_FDLH_REQ_ABORT)
#define SDCA_CTL_XU_FDLD_COMPLETE 0
#define SDCA_CTL_XU_FDLD_FILE_OK (SDCA_CTL_XU_FDLH_TRANSFERRED_FILE | \
SDCA_CTL_XU_FDLH_SET_IN_PROGRESS | \
SDCA_CTL_XU_FDLD_ACK_TRANSFER | \
SDCA_CTL_XU_FDLD_NEEDS_SET)
#define SDCA_CTL_XU_FDLD_MORE_FILES_OK (SDCA_CTL_XU_FDLH_SET_IN_PROGRESS | \
SDCA_CTL_XU_FDLD_ACK_TRANSFER | \
SDCA_CTL_XU_FDLD_NEEDS_SET)
#define SDCA_CTL_XU_FDLD_MASK (SDCA_CTL_XU_FDLD_REQ_RESET | \
SDCA_CTL_XU_FDLD_REQ_ABORT | \
SDCA_CTL_XU_FDLD_ACK_TRANSFER | \
SDCA_CTL_XU_FDLD_NEEDS_SET)
#if IS_ENABLED(CONFIG_SND_SOC_SDCA_FDL)
int sdca_fdl_alloc_state(struct sdca_interrupt *interrupt);
int sdca_fdl_process(struct sdca_interrupt *interrupt);
int sdca_fdl_sync(struct device *dev, struct sdca_function_data *function,
struct sdca_interrupt_info *info);
int sdca_reset_function(struct device *dev, struct sdca_function_data *function,
struct regmap *regmap);
#else
static inline int sdca_fdl_alloc_state(struct sdca_interrupt *interrupt)
{
return 0;
}
static inline int sdca_fdl_process(struct sdca_interrupt *interrupt)
{
return 0;
}
static inline int sdca_fdl_sync(struct device *dev,
struct sdca_function_data *function,
struct sdca_interrupt_info *info)
{
return 0;
}
static inline int sdca_reset_function(struct device *dev,
struct sdca_function_data *function,
struct regmap *regmap)
{
return 0;
}
#endif // CONFIG_SND_SOC_SDCA_FDL
#endif // __SDCA_FDL_H__
+124 -2
View File
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/hid.h>
struct acpi_table_swft;
struct device;
struct sdca_entity;
struct sdca_function_desc;
@@ -63,6 +64,7 @@ struct sdca_function_desc;
* @SDCA_FUNCTION_TYPE_RJ: Retaskable jack.
* @SDCA_FUNCTION_TYPE_SIMPLE_JACK: Subset of UAJ.
* @SDCA_FUNCTION_TYPE_HID: Human Interface Device, for e.g. buttons.
* @SDCA_FUNCTION_TYPE_COMPANION_AMP: Sources audio from another amp.
* @SDCA_FUNCTION_TYPE_IMP_DEF: Implementation-defined function.
*
* SDCA Function Types from SDCA specification v1.0a Section 5.1.2
@@ -82,6 +84,7 @@ enum sdca_function_type {
SDCA_FUNCTION_TYPE_RJ = 0x07,
SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08,
SDCA_FUNCTION_TYPE_HID = 0x0A,
SDCA_FUNCTION_TYPE_COMPANION_AMP = 0x0B,
SDCA_FUNCTION_TYPE_IMP_DEF = 0x1F,
};
@@ -95,6 +98,7 @@ enum sdca_function_type {
#define SDCA_FUNCTION_TYPE_RJ_NAME "RJ"
#define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack"
#define SDCA_FUNCTION_TYPE_HID_NAME "HID"
#define SDCA_FUNCTION_TYPE_COMPANION_AMP_NAME "CompanionAmp"
#define SDCA_FUNCTION_TYPE_IMP_DEF_NAME "ImplementationDefined"
/**
@@ -133,6 +137,32 @@ struct sdca_init_write {
#define SDCA_CTL_TYPE_S(ent, sel) SDCA_CTL_TYPE(SDCA_ENTITY_TYPE_##ent, \
SDCA_CTL_##ent##_##sel)
/**
* enum sdca_messageoffset_range - Column definitions UMP MessageOffset
*/
enum sdca_messageoffset_range {
SDCA_MESSAGEOFFSET_BUFFER_START_ADDRESS = 0,
SDCA_MESSAGEOFFSET_BUFFER_LENGTH = 1,
SDCA_MESSAGEOFFSET_UMP_MODE = 2,
SDCA_MESSAGEOFFSET_NCOLS = 3,
};
/**
* enum sdca_ump_mode - SDCA UMP Mode
*/
enum sdca_ump_mode {
SDCA_UMP_MODE_DIRECT = 0x00,
SDCA_UMP_MODE_INDIRECT = 0x01,
};
/**
* enum sdca_ump_owner - SDCA UMP Owner
*/
enum sdca_ump_owner {
SDCA_UMP_OWNER_HOST = 0x00,
SDCA_UMP_OWNER_DEVICE = 0x01,
};
/**
* enum sdca_it_controls - SDCA Controls for Input Terminal
*
@@ -258,6 +288,27 @@ enum sdca_xu_controls {
SDCA_CTL_XU_FDL_STATUS = 0x14,
SDCA_CTL_XU_FDL_SET_INDEX = 0x15,
SDCA_CTL_XU_FDL_HOST_REQUEST = 0x16,
/* FDL Status Host->Device bit definitions */
SDCA_CTL_XU_FDLH_TRANSFERRED_CHUNK = BIT(0),
SDCA_CTL_XU_FDLH_TRANSFERRED_FILE = BIT(1),
SDCA_CTL_XU_FDLH_SET_IN_PROGRESS = BIT(2),
SDCA_CTL_XU_FDLH_RESET_ACK = BIT(4),
SDCA_CTL_XU_FDLH_REQ_ABORT = BIT(5),
/* FDL Status Device->Host bit definitions */
SDCA_CTL_XU_FDLD_REQ_RESET = BIT(4),
SDCA_CTL_XU_FDLD_REQ_ABORT = BIT(5),
SDCA_CTL_XU_FDLD_ACK_TRANSFER = BIT(6),
SDCA_CTL_XU_FDLD_NEEDS_SET = BIT(7),
};
/**
* enum sdca_set_index_range - Column definitions UMP SetIndex
*/
enum sdca_fdl_set_index_range {
SDCA_FDL_SET_INDEX_SET_NUMBER = 0,
SDCA_FDL_SET_INDEX_FILE_SET_ID = 1,
SDCA_FDL_SET_INDEX_NCOLS = 2,
};
/**
@@ -542,6 +593,9 @@ enum sdca_entity0_controls {
SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION = BIT(5),
SDCA_CTL_ENTITY_0_FUNCTION_HAS_BEEN_RESET = BIT(6),
SDCA_CTL_ENTITY_0_FUNCTION_BUSY = BIT(7),
/* Function Action Bits */
SDCA_CTL_ENTITY_0_RESET_FUNCTION_NOW = BIT(0),
};
#define SDCA_CTL_MIC_BIAS_NAME "Mic Bias"
@@ -557,7 +611,7 @@ enum sdca_entity0_controls {
#define SDCA_CTL_NDAI_PACKETTYPE_NAME "NDAI Packet Type"
#define SDCA_CTL_MIXER_NAME "Mixer"
#define SDCA_CTL_SELECTOR_NAME "Selector"
#define SDCA_CTL_MUTE_NAME "Mute"
#define SDCA_CTL_MUTE_NAME "Channel"
#define SDCA_CTL_CHANNEL_VOLUME_NAME "Channel Volume"
#define SDCA_CTL_AGC_NAME "AGC"
#define SDCA_CTL_BASS_BOOST_NAME "Bass Boost"
@@ -771,6 +825,7 @@ struct sdca_control {
u8 layers;
bool deferrable;
bool is_volatile;
bool has_default;
bool has_fixed;
};
@@ -1089,6 +1144,27 @@ struct sdca_entity_hide {
struct hid_descriptor hid_desc;
};
/**
* enum sdca_xu_reset_machanism - SDCA FDL Resets
*/
enum sdca_xu_reset_mechanism {
SDCA_XU_RESET_FUNCTION = 0x0,
SDCA_XU_RESET_DEVICE = 0x1,
SDCA_XU_RESET_BUS = 0x2,
};
/**
* struct sdca_entity_xu - information specific to XU Entities
* @max_delay: the maximum time in microseconds allowed for the Device
* to change the ownership from Device to Host
* @reset_mechanism: indicates the type of reset that can be requested
* the end of an FDL.
*/
struct sdca_entity_xu {
unsigned int max_delay;
enum sdca_xu_reset_mechanism reset_mechanism;
};
/**
* struct sdca_entity - information for one SDCA Entity
* @label: String such as "OT 12".
@@ -1105,6 +1181,7 @@ struct sdca_entity_hide {
* @pde: Power Domain Entity specific Entity properties.
* @ge: Group Entity specific Entity properties.
* @hide: HIDE Entity specific Entity properties.
* @xu: XU Entity specific Entity properties.
*/
struct sdca_entity {
const char *label;
@@ -1122,6 +1199,7 @@ struct sdca_entity {
struct sdca_entity_pde pde;
struct sdca_entity_ge ge;
struct sdca_entity_hide hide;
struct sdca_entity_xu xu;
};
};
@@ -1288,6 +1366,42 @@ enum sdca_cluster_range {
SDCA_CLUSTER_NCOLS = 2,
};
/**
* struct sdca_fdl_file - information about a file from a fileset used in FDL
* @vendor_id: Vendor ID of the file.
* @file_id: File ID of the file.
* @fdl_offset: Offset information for FDL.
*/
struct sdca_fdl_file {
u16 vendor_id;
u32 file_id;
u32 fdl_offset;
};
/**
* struct sdca_fdl_set - information about a set of files used in FDL
* @files: Array of files in this FDL set.
* @num_files: Number of files in this FDL set.
* @id: ID of the FDL set.
*/
struct sdca_fdl_set {
struct sdca_fdl_file *files;
int num_files;
u32 id;
};
/**
* struct sdca_fdl_data - information about a function's FDL data
* @swft: Pointer to the SoundWire File Table.
* @sets: Array of FDL sets used by this function.
* @num_sets: Number of FDL sets used by this function.
*/
struct sdca_fdl_data {
struct acpi_table_swft *swft;
struct sdca_fdl_set *sets;
int num_sets;
};
/**
* struct sdca_function_data - top-level information for one SDCA function
* @desc: Pointer to short descriptor from initial parsing.
@@ -1299,6 +1413,9 @@ enum sdca_cluster_range {
* @num_clusters: Number of Channel Clusters reported in this Function.
* @busy_max_delay: Maximum Function busy delay in microseconds, before an
* error should be reported.
* @reset_max_delay: Maximum Function reset delay in microseconds, before an
* error should be reported.
* @fdl_data: FDL data for this Function, if available.
*/
struct sdca_function_data {
struct sdca_function_desc *desc;
@@ -1311,6 +1428,9 @@ struct sdca_function_data {
int num_clusters;
unsigned int busy_max_delay;
unsigned int reset_max_delay;
struct sdca_fdl_data fdl_data;
};
static inline u32 sdca_range(struct sdca_control_range *range,
@@ -1332,10 +1452,12 @@ static inline u32 sdca_range_search(struct sdca_control_range *range,
return 0;
}
int sdca_parse_function(struct device *dev,
int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
struct sdca_function_desc *desc,
struct sdca_function_data *function);
const char *sdca_find_terminal_name(enum sdca_terminal_type type);
struct sdca_control *sdca_selector_find_control(struct device *dev,
struct sdca_entity *entity,
const int sel);
+17 -4
View File
@@ -8,14 +8,27 @@
#ifndef __SDCA_HID_H__
#define __SDCA_HID_H__
#include <linux/types.h>
#include <linux/hid.h>
struct device;
struct sdw_slave;
struct sdca_entity;
struct sdca_interrupt;
#if IS_ENABLED(CONFIG_SND_SOC_SDCA_HID)
int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity);
int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
struct sdca_entity *entity);
int sdca_hid_process_report(struct sdca_interrupt *interrupt);
#else
static inline int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity)
static inline int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
struct sdca_entity *entity)
{
return 0;
}
static inline int sdca_hid_process_report(struct sdca_interrupt *interrupt)
{
return 0;
}
+14 -5
View File
@@ -23,18 +23,23 @@ struct sdca_function_data;
/**
* struct sdca_interrupt - contains information about a single SDCA interrupt
* @name: The name of the interrupt.
* @dev: Pointer to the Function device.
* @device_regmap: Pointer to the IRQ regmap.
* @function_regmap: Pointer to the SDCA Function regmap.
* @component: Pointer to the ASoC component owns the interrupt.
* @function: Pointer to the Function that the interrupt is associated with.
* @entity: Pointer to the Entity that the interrupt is associated with.
* @control: Pointer to the Control that the interrupt is associated with.
* @priv: Pointer to private data for use by the handler.
* @externally_requested: Internal flag used to check if a client driver has
* already requested the interrupt, for custom handling, allowing the core to
* skip handling this interrupt.
* @irq: IRQ number allocated to this interrupt, also used internally to track
* the IRQ being assigned.
*/
struct sdca_interrupt {
const char *name;
struct device *dev;
struct regmap *device_regmap;
struct regmap *function_regmap;
struct snd_soc_component *component;
struct sdca_function_data *function;
struct sdca_entity *entity;
@@ -42,7 +47,7 @@ struct sdca_interrupt {
void *priv;
bool externally_requested;
int irq;
};
/**
@@ -64,11 +69,15 @@ struct sdca_interrupt_info {
int sdca_irq_request(struct device *dev, struct sdca_interrupt_info *interrupt_info,
int sdca_irq, const char *name, irq_handler_t handler,
void *data);
int sdca_irq_data_populate(struct snd_soc_component *component,
int sdca_irq_data_populate(struct device *dev, struct regmap *function_regmap,
struct snd_soc_component *component,
struct sdca_function_data *function,
struct sdca_entity *entity,
struct sdca_control *control,
struct sdca_interrupt *interrupt);
int sdca_irq_populate_early(struct device *dev, struct regmap *function_regmap,
struct sdca_function_data *function,
struct sdca_interrupt_info *info);
int sdca_irq_populate(struct sdca_function_data *function,
struct snd_soc_component *component,
struct sdca_interrupt_info *info);
+2
View File
@@ -27,5 +27,7 @@ int sdca_regmap_populate_constants(struct device *dev, struct sdca_function_data
int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
struct sdca_function_data *function);
int sdca_regmap_write_init(struct device *dev, struct regmap *regmap,
struct sdca_function_data *function);
#endif // __SDCA_REGMAP_H__
+50
View File
@@ -0,0 +1,50 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* The MIPI SDCA specification is available for public downloads at
* https://www.mipi.org/mipi-sdca-v1-0-download
*
* Copyright (C) 2025 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
*/
#ifndef __SDCA_UMP_H__
#define __SDCA_UMP_H__
struct regmap;
struct sdca_control;
struct sdca_entity;
struct sdca_function_data;
struct snd_soc_component;
struct delayed_work;
int sdca_ump_get_owner_host(struct device *dev,
struct regmap *function_regmap,
struct sdca_function_data *function,
struct sdca_entity *entity,
struct sdca_control *control);
int sdca_ump_set_owner_device(struct device *dev,
struct regmap *function_regmap,
struct sdca_function_data *function,
struct sdca_entity *entity,
struct sdca_control *control);
int sdca_ump_read_message(struct device *dev,
struct regmap *device_regmap,
struct regmap *function_regmap,
struct sdca_function_data *function,
struct sdca_entity *entity,
unsigned int offset_sel, unsigned int length_sel,
void **msg);
int sdca_ump_write_message(struct device *dev,
struct regmap *device_regmap,
struct regmap *function_regmap,
struct sdca_function_data *function,
struct sdca_entity *entity,
unsigned int offset_sel, unsigned int msg_offset,
unsigned int length_sel,
void *msg, int msg_len);
void sdca_ump_cancel_timeout(struct delayed_work *work);
void sdca_ump_schedule_timeout(struct delayed_work *work,
unsigned int timeout_us);
#endif // __SDCA_UMP_H__
+2
View File
@@ -34,6 +34,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[];
@@ -46,6 +47,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_nvl_sdw_machines[];
/*
* generic table used for HDA codec-based platforms, possibly with
+8 -5
View File
@@ -116,8 +116,8 @@ struct snd_soc_acpi_endpoint {
* @name_prefix: string used for codec controls
*/
struct snd_soc_acpi_adr_device {
const u64 adr;
const u8 num_endpoints;
u64 adr;
u8 num_endpoints;
const struct snd_soc_acpi_endpoint *endpoints;
const char *name_prefix;
};
@@ -133,8 +133,8 @@ struct snd_soc_acpi_adr_device {
*/
struct snd_soc_acpi_link_adr {
const u32 mask;
const u32 num_adr;
u32 mask;
u32 num_adr;
const struct snd_soc_acpi_adr_device *adr_d;
};
@@ -205,6 +205,8 @@ struct snd_soc_acpi_link_adr {
* @mach: the pointer of the machine driver
* @prefix: the prefix of the topology file name. Typically, it is the path.
* @tplg_files: the pointer of the array of the topology file names.
* @best_effort: ignore non supported links and try to build the card in best effort
* with supported links
*/
/* Descriptor for SST ASoC machine driver */
struct snd_soc_acpi_mach {
@@ -226,7 +228,8 @@ struct snd_soc_acpi_mach {
const u32 tplg_quirk_mask;
int (*get_function_tplg_files)(struct snd_soc_card *card,
const struct snd_soc_acpi_mach *mach,
const char *prefix, const char ***tplg_files);
const char *prefix, const char ***tplg_files,
bool best_effort);
};
#define SND_SOC_ACPI_MAX_CODECS 3
+18 -20
View File
@@ -319,6 +319,13 @@ struct platform_device;
#define SOC_VALUE_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put)
#define SOC_ENUM_EXT_ACC(xname, xenum, xhandler_get, xhandler_put, xaccess) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.access = xaccess, \
.info = snd_soc_info_enum_double, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&xenum }
#define SND_SOC_BYTES(xname, xbase, xregs) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
@@ -331,6 +338,13 @@ struct platform_device;
.put = xhandler_put, .private_value = \
((unsigned long)&(struct soc_bytes) \
{.base = xbase, .num_regs = xregs }) }
#define SND_SOC_BYTES_E_ACC(xname, xbase, xregs, xhandler_get, xhandler_put, xaccess) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.access = xaccess, \
.info = snd_soc_bytes_info, .get = xhandler_get, \
.put = xhandler_put, .private_value = \
((unsigned long)&(struct soc_bytes) \
{.base = xbase, .num_regs = xregs }) }
#define SND_SOC_BYTES_MASK(xname, xbase, xregs, xmask) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -1296,22 +1310,6 @@ static inline unsigned int snd_soc_enum_item_to_val(const struct soc_enum *e,
return e->values[item];
}
/**
* snd_soc_kcontrol_component() - Returns the component that registered the
* control
* @kcontrol: The control for which to get the component
*
* Note: This function will work correctly if the control has been registered
* for a component. With snd_soc_add_codec_controls() or via table based
* setup for either a CODEC or component driver. Otherwise the behavior is
* undefined.
*/
static inline struct snd_soc_component *snd_soc_kcontrol_component(
struct snd_kcontrol *kcontrol)
{
return snd_kcontrol_chip(kcontrol);
}
int snd_soc_util_init(void);
void snd_soc_util_exit(void);
@@ -1473,22 +1471,22 @@ static inline void _snd_soc_dapm_mutex_assert_held_c(struct snd_soc_card *card)
static inline void _snd_soc_dapm_mutex_lock_root_d(struct snd_soc_dapm_context *dapm)
{
_snd_soc_dapm_mutex_lock_root_c(dapm->card);
_snd_soc_dapm_mutex_lock_root_c(snd_soc_dapm_to_card(dapm));
}
static inline void _snd_soc_dapm_mutex_lock_d(struct snd_soc_dapm_context *dapm)
{
_snd_soc_dapm_mutex_lock_c(dapm->card);
_snd_soc_dapm_mutex_lock_c(snd_soc_dapm_to_card(dapm));
}
static inline void _snd_soc_dapm_mutex_unlock_d(struct snd_soc_dapm_context *dapm)
{
_snd_soc_dapm_mutex_unlock_c(dapm->card);
_snd_soc_dapm_mutex_unlock_c(snd_soc_dapm_to_card(dapm));
}
static inline void _snd_soc_dapm_mutex_assert_held_d(struct snd_soc_dapm_context *dapm)
{
_snd_soc_dapm_mutex_assert_held_c(dapm->card);
_snd_soc_dapm_mutex_assert_held_c(snd_soc_dapm_to_card(dapm));
}
#define snd_soc_dapm_mutex_lock_root(x) _Generic((x), \
+16 -3
View File
@@ -13,6 +13,7 @@
#include <sound/soc-acpi.h>
#define SOC_SDW_MAX_DAI_NUM 8
#define SOC_SDW_MAX_AUX_NUM 2
#define SOC_SDW_MAX_NO_PROPS 2
#define SOC_SDW_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0))
@@ -45,6 +46,7 @@ struct asoc_sdw_codec_info;
struct asoc_sdw_dai_info {
const bool direction[2]; /* playback & capture support */
const char *codec_name;
const char *dai_name;
const char *component_name;
const int dai_type;
@@ -64,16 +66,22 @@ struct asoc_sdw_dai_info {
bool quirk_exclude;
};
struct asoc_sdw_aux_info {
const char *codec_name;
};
struct asoc_sdw_codec_info {
const int part_id;
const int version_id;
const char *codec_name;
const char *name_prefix;
int amp_num;
const u8 acpi_id[ACPI_ID_LEN];
const bool ignore_internal_dmic;
const struct snd_soc_ops *ops;
struct asoc_sdw_dai_info dais[SOC_SDW_MAX_DAI_NUM];
const int dai_num;
struct asoc_sdw_aux_info auxs[SOC_SDW_MAX_AUX_NUM];
const int aux_num;
int (*codec_card_late_probe)(struct snd_soc_card *card);
@@ -130,7 +138,7 @@ int asoc_sdw_hw_free(struct snd_pcm_substream *substream);
void asoc_sdw_shutdown(struct snd_pcm_substream *substream);
const char *asoc_sdw_get_codec_name(struct device *dev,
const struct asoc_sdw_codec_info *codec_info,
const struct asoc_sdw_dai_info *dai_info,
const struct snd_soc_acpi_link_adr *adr_link,
int adr_index);
@@ -164,12 +172,15 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d
int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd),
const struct snd_soc_ops *ops);
int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends);
int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card,
int *num_devs, int *num_ends, int *num_aux);
struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
const struct snd_soc_acpi_endpoint *new);
int asoc_sdw_get_dai_type(u32 type);
int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
struct snd_soc_aux_dev *soc_aux,
struct asoc_sdw_dailink *soc_dais,
struct asoc_sdw_endpoint *soc_ends,
int *num_devs);
@@ -246,6 +257,8 @@ int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_da
int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l45_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l45_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
/* TI */
+6
View File
@@ -117,14 +117,20 @@ enum audio_device {
TAS2120,
TAS2320,
TAS2563,
TAS2568,
TAS2570,
TAS2572,
TAS2574,
TAS2781,
TAS5802,
TAS5806M,
TAS5806MD,
TAS5815,
TAS5822,
TAS5825,
TAS5827,
TAS5828,
TAS5830,
TAS_OTHERS,
};
+3
View File
@@ -151,6 +151,9 @@ struct wm8904_pdata {
int num_retune_mobile_cfgs;
struct wm8904_retune_mobile_cfg *retune_mobile_cfgs;
bool in1l_as_dmicdat1;
bool in1r_as_dmicdat2;
u32 gpio_cfg[WM8904_GPIO_REGS];
u32 mic_cfg[WM8904_MIC_REGS];
};
+6
View File
@@ -21,6 +21,7 @@ enum avs_tplg_token {
AVS_TKN_MANIFEST_NUM_BINDINGS_U32 = 8,
AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32 = 9,
AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32 = 10,
AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32 = 11,
/* struct avs_tplg_library */
AVS_TKN_LIBRARY_ID_U32 = 101,
@@ -124,6 +125,7 @@ enum avs_tplg_token {
AVS_TKN_MOD_KCONTROL_ID_U32 = 1707,
AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32 = 1708,
AVS_TKN_MOD_INIT_CONFIG_ID_U32 = 1709,
AVS_TKN_MOD_NHLT_CONFIG_ID_U32 = 1710,
/* struct avs_tplg_path_template */
AVS_TKN_PATH_TMPL_ID_U32 = 1801,
@@ -160,6 +162,10 @@ enum avs_tplg_token {
AVS_TKN_INIT_CONFIG_ID_U32 = 2401,
AVS_TKN_INIT_CONFIG_PARAM_U8 = 2402,
AVS_TKN_INIT_CONFIG_LENGTH_U32 = 2403,
/* struct avs_tplg_nhlt_config */
AVS_TKN_NHLT_CONFIG_ID_U32 = 2501,
AVS_TKN_NHLT_CONFIG_SIZE_U32 = 2502,
};
#endif
@@ -0,0 +1 @@
# CONFIG_SND_HDA_SCODEC_CS35L56_CAL_DEBUGFS is not set
@@ -0,0 +1 @@
# CONFIG_SND_SOC_CS35L56_CAL_DEBUGFS is not set
@@ -0,0 +1 @@
# CONFIG_SND_SOC_CS35L56_CAL_SET_CTRL is not set
@@ -0,0 +1 @@
CONFIG_SND_SOC_CS35L56_TEST=m
@@ -0,0 +1 @@
CONFIG_SND_SOC_SDCA_CLASS=m
@@ -0,0 +1 @@
CONFIG_SND_SOC_SDCA_FDL=y
@@ -0,0 +1 @@
# CONFIG_SND_SOC_SOF_NOVALAKE is not set
@@ -0,0 +1 @@
CONFIG_SND_SOC_SOF_NOVALAKE=m
+5 -5
View File
@@ -298,6 +298,7 @@ static void ac97_adapter_release(struct device *dev)
idr_remove(&ac97_adapter_idr, ac97_ctrl->nr);
dev_dbg(&ac97_ctrl->adap, "adapter unregistered by %s\n",
dev_name(ac97_ctrl->parent));
kfree(ac97_ctrl);
}
static const struct device_type ac97_adapter_type = {
@@ -319,7 +320,9 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)
ret = device_register(&ac97_ctrl->adap);
if (ret)
put_device(&ac97_ctrl->adap);
}
} else
kfree(ac97_ctrl);
if (!ret) {
list_add(&ac97_ctrl->controllers, &ac97_controllers);
dev_dbg(&ac97_ctrl->adap, "adapter registered by %s\n",
@@ -361,14 +364,11 @@ struct ac97_controller *snd_ac97_controller_register(
ret = ac97_add_adapter(ac97_ctrl);
if (ret)
goto err;
return ERR_PTR(ret);
ac97_bus_reset(ac97_ctrl);
ac97_bus_scan(ac97_ctrl);
return ac97_ctrl;
err:
kfree(ac97_ctrl);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(snd_ac97_controller_register);
+8 -5
View File
@@ -46,11 +46,14 @@ static bool snd_ac97_check_id(struct snd_ac97 *ac97, unsigned int id,
* @id_mask: Mask that is applied to the device ID before comparing to @id
*
* This function resets the AC'97 device. If @try_warm is true the function
* first performs a warm reset. If the warm reset is successful the function
* returns 1. Otherwise or if @try_warm is false the function issues cold reset
* followed by a warm reset. If this is successful the function returns 0,
* otherwise a negative error code. If @id is 0 any valid device ID will be
* accepted, otherwise only the ID that matches @id and @id_mask is accepted.
* first performs a warm reset. If @try_warm is false the function issues
* cold reset followed by a warm reset. If @id is 0 any valid device ID
* will be accepted, otherwise only the ID that matches @id and @id_mask
* is accepted.
* Returns:
* * %1 - if warm reset is successful
* * %0 - if cold reset and warm reset is successful
* * %-ENODEV - if @id and @id_mask not matching
*/
int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
unsigned int id_mask)
+3 -1
View File
@@ -1074,7 +1074,9 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
runtime->oss.params = 0;
runtime->oss.prepare = 1;
runtime->oss.buffer_used = 0;
snd_pcm_runtime_buffer_set_silence(runtime);
err = snd_pcm_runtime_buffer_set_silence(runtime);
if (err < 0)
goto failure;
runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
+1 -1
View File
@@ -379,7 +379,7 @@ int snd_parse_eld(struct device *dev, struct snd_parsed_hdmi_eld *e,
* in console or for audio devices. Assume the highest speakers
* configuration, to _not_ prohibit multi-channel audio playback.
*/
if (!e->spk_alloc)
if (!e->spk_alloc && e->sad_count)
e->spk_alloc = 0xffff;
return 0;
+7 -2
View File
@@ -730,13 +730,18 @@ static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime)
}
/* fill the PCM buffer with the current silence format; called from pcm_oss.c */
void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime)
int snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime)
{
snd_pcm_buffer_access_lock(runtime);
int err;
err = snd_pcm_buffer_access_lock(runtime);
if (err < 0)
return err;
if (runtime->dma_area)
snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
bytes_to_samples(runtime, runtime->dma_bytes));
snd_pcm_buffer_access_unlock(runtime);
return 0;
}
EXPORT_SYMBOL_GPL(snd_pcm_runtime_buffer_set_silence);
+1 -4
View File
@@ -2107,13 +2107,11 @@ EXPORT_SYMBOL(snd_rawmidi_set_ops);
static int __init alsa_rawmidi_init(void)
{
snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
#ifdef CONFIG_SND_OSSEMUL
{ int i;
/* check device map table */
for (i = 0; i < SNDRV_CARDS; i++) {
for (int i = 0; i < SNDRV_CARDS; i++) {
if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n",
i, midi_map[i]);
@@ -2125,7 +2123,6 @@ static int __init alsa_rawmidi_init(void)
amidi_map[i] = 1;
}
}
}
#endif /* CONFIG_SND_OSSEMUL */
return 0;
}
+2 -2
View File
@@ -696,10 +696,10 @@ static int setup_patt_bufs(void)
size_t i;
for (i = 0; i < ARRAY_SIZE(patt_bufs); i++) {
patt_bufs[i].buf = kzalloc(MAX_PATTERN_LEN, GFP_KERNEL);
patt_bufs[i].buf = kmalloc(MAX_PATTERN_LEN, GFP_KERNEL);
if (!patt_bufs[i].buf)
break;
strcpy(patt_bufs[i].buf, DEFAULT_PATTERN);
strscpy_pad(patt_bufs[i].buf, DEFAULT_PATTERN, MAX_PATTERN_LEN);
patt_bufs[i].len = DEFAULT_PATTERN_LEN;
}
+11 -10
View File
@@ -282,20 +282,22 @@ static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
struct amdtp_stream *stream)
{
struct fw_iso_resources *resources;
int speed;
int err;
if (stream == &tscm->tx_stream)
if (stream == &tscm->tx_stream) {
resources = &tscm->tx_resources;
else
speed = fw_parent_device(tscm->unit)->max_speed;
} else {
resources = &tscm->rx_resources;
speed = SCODE_400;
}
err = amdtp_tscm_set_parameters(stream, rate);
if (err < 0)
return err;
return fw_iso_resources_allocate(resources,
amdtp_stream_get_max_payload(stream),
fw_parent_device(tscm->unit)->max_speed);
return fw_iso_resources_allocate(resources, amdtp_stream_get_max_payload(stream), speed);
}
static int init_stream(struct snd_tscm *tscm, struct amdtp_stream *s)
@@ -455,7 +457,6 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
}
if (!amdtp_stream_running(&tscm->rx_stream)) {
int spd = fw_parent_device(tscm->unit)->max_speed;
unsigned int tx_init_skip_cycles;
err = set_stream_formats(tscm, rate);
@@ -466,13 +467,13 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
if (err < 0)
goto error;
err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream,
tscm->rx_resources.channel, spd);
err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream, tscm->rx_resources.channel,
fw_parent_device(tscm->unit)->max_speed);
if (err < 0)
goto error;
err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream,
tscm->tx_resources.channel, spd);
err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream, tscm->tx_resources.channel,
SCODE_400);
if (err < 0)
goto error;
+1
View File
@@ -793,6 +793,7 @@ static const struct hda_device_id snd_hda_id_intelhdmi[] = {
HDA_CODEC_ID_MODEL(0x80862820, "Lunar Lake HDMI", MODEL_ADLP),
HDA_CODEC_ID_MODEL(0x80862822, "Panther Lake HDMI", MODEL_ADLP),
HDA_CODEC_ID_MODEL(0x80862823, "Wildcat Lake HDMI", MODEL_ADLP),
HDA_CODEC_ID_MODEL(0x80862824, "Nova Lake HDMI", MODEL_ADLP),
HDA_CODEC_ID_MODEL(0x80862882, "Valleyview2 HDMI", MODEL_BYT),
HDA_CODEC_ID_MODEL(0x80862883, "Braswell HDMI", MODEL_BYT),
{} /* terminator */
+62 -1
View File
@@ -3430,11 +3430,22 @@ static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream,
int action)
{
static const struct coef_fw dis_coefs[] = {
WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203),
WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023),
}; /* Disable AMP silence detection */
static const struct coef_fw en_coefs[] = {
WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203),
WRITE_COEF(0x28, 0x0084), WRITE_COEF(0x29, 0xb023),
}; /* Enable AMP silence detection */
switch (action) {
case HDA_GEN_PCM_ACT_OPEN:
alc_process_coef_fw(codec, dis_coefs);
alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */
break;
case HDA_GEN_PCM_ACT_CLOSE:
alc_process_coef_fw(codec, en_coefs);
alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
break;
}
@@ -3783,6 +3794,7 @@ enum {
ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
ALC298_FIXUP_LENOVO_C940_DUET7,
ALC287_FIXUP_LENOVO_YOGA_BOOK_9I,
ALC287_FIXUP_13S_GEN2_SPEAKERS,
ALC256_FIXUP_SET_COEF_DEFAULTS,
ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
@@ -3871,6 +3883,23 @@ static void alc298_fixup_lenovo_c940_duet7(struct hda_codec *codec,
__snd_hda_apply_fixup(codec, id, action, 0);
}
/* A special fixup for Lenovo Yoga 9i and Yoga Book 9i 13IRU8
* both have the very same PCI SSID and vendor ID, so we need
* to apply different fixups depending on the subsystem ID
*/
static void alc287_fixup_lenovo_yoga_book_9i(struct hda_codec *codec,
const struct hda_fixup *fix,
int action)
{
int id;
if (codec->core.subsystem_id == 0x17aa3881)
id = ALC287_FIXUP_TAS2781_I2C; /* Yoga Book 9i 13IRU8 */
else
id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP; /* Yoga 9i */
__snd_hda_apply_fixup(codec, id, action, 0);
}
static const struct hda_fixup alc269_fixups[] = {
[ALC269_FIXUP_GPIO2] = {
.type = HDA_FIXUP_FUNC,
@@ -5882,6 +5911,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc298_fixup_lenovo_c940_duet7,
},
[ALC287_FIXUP_LENOVO_YOGA_BOOK_9I] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc287_fixup_lenovo_yoga_book_9i,
},
[ALC287_FIXUP_13S_GEN2_SPEAKERS] = {
.type = HDA_FIXUP_VERBS,
.v.verbs = (const struct hda_verb[]) {
@@ -6372,7 +6405,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1539, "Acer Nitro 5 AN515-57", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
@@ -6560,6 +6595,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x863e, "HP Spectre x360 15-df1xxx", ALC285_FIXUP_HP_SPECTRE_X360_DF1),
SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8706, "HP Laptop 15s-eq1xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
@@ -6663,10 +6699,13 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8a34, "HP Pavilion x360 2-in-1 Laptop 14-ek0xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8a4f, "HP Victus 15-fa0xxx (MB 8A4F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a75, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a76, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a77, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
@@ -6764,6 +6803,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8c8c, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c8d, "HP ProBook 440 G11", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c8e, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c8f, "HP EliteBook 630 G11", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c90, "HP EliteBook 640", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
@@ -6837,19 +6877,35 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8e8a, "HP NexusX", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8e9c, "HP 16 Clipper OmniBook X X360", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8e9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8e9e, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8eb6, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8eb8, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8ec1, "HP 200 G2i", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8ec4, "HP Bantie I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8ec5, "HP Bantie I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8ece, "HP Abe I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8ecf, "HP Abe I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8ed2, "HP Abe I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8ed5, "HP EliteBook 8 Flip G2i 13", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8ed6, "HP EliteBook 8 G2i 13", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8ed7, "HP EliteBook 8 G2i 14", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8ed8, "HP EliteBook 8 G2i 16", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8ed9, "HP ZBook Firefly 14W", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8eda, "HP ZBook Firefly 16W", ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8ee4, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8ee5, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8ee7, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x8f0c, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f0e, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f40, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f41, "HP ZBook 8 G2a 16", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f42, "HP ZBook 8 G2a 14W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f57, "HP Trekker G7JC", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8f62, "HP ZBook 8 G2a 16W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x1043, 0x1024, "ASUS Zephyrus G14 2025", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1032, "ASUS VivoBook X513EA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
@@ -6899,6 +6955,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1584, "ASUS UM3406GA ", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1652, "ASUS ROG Zephyrus Do 15 SE", ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
@@ -7043,6 +7100,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
SND_PCI_QUIRK(0x144d, 0xc876, "Samsung 730QED (NP730QED-KA2US)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
SND_PCI_QUIRK(0x144d, 0xca03, "Samsung Galaxy Book2 Pro 360 (NP930QED)", ALC298_FIXUP_SAMSUNG_AMP),
SND_PCI_QUIRK(0x144d, 0xca06, "Samsung Galaxy Book3 360 (NP730QFG)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
SND_PCI_QUIRK(0x144d, 0xc868, "Samsung Galaxy Book2 Pro (NP930XED)", ALC298_FIXUP_SAMSUNG_AMP),
@@ -7226,7 +7284,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF),
SND_PCI_QUIRK(0x17aa, 0x3834, "Lenovo IdeaPad Slim 9i 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x383d, "Legion Y9000X 2019", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3843, "Yoga 9i", ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP),
SND_PCI_QUIRK(0x17aa, 0x3843, "Lenovo Yoga 9i / Yoga Book 9i", ALC287_FIXUP_LENOVO_YOGA_BOOK_9I),
SND_PCI_QUIRK(0x17aa, 0x3847, "Legion 7 16ACHG6", ALC287_FIXUP_LEGION_16ACHG6),
SND_PCI_QUIRK(0x17aa, 0x384a, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
@@ -7348,15 +7406,18 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d05, 0x1409, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d05, 0x300f, "TongFang X6AR5xxY", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d05, 0x3019, "TongFang X6FR5xxY", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d05, 0x3031, "TongFang X6AR55xU", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1e39, 0xca14, "MEDION NM14LNL", ALC233_FIXUP_MEDION_MTL_SPK),
SND_PCI_QUIRK(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2039, 0x0001, "Inspur S14-G1", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13),
SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO),
+6 -3
View File
@@ -19,6 +19,9 @@
#include "hda_jack.h"
#include "generic.h"
/* GPIO node ID */
#define SENARY_GPIO_NODE 0x01
struct senary_spec {
struct hda_gen_spec gen;
@@ -120,11 +123,11 @@ static void senary_init_gpio_led(struct hda_codec *codec)
unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
if (mask) {
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
snd_hda_codec_write(codec, SENARY_GPIO_NODE, 0, AC_VERB_SET_GPIO_MASK,
mask);
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
snd_hda_codec_write(codec, SENARY_GPIO_NODE, 0, AC_VERB_SET_GPIO_DIRECTION,
mask);
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
snd_hda_codec_write(codec, SENARY_GPIO_NODE, 0, AC_VERB_SET_GPIO_DATA,
spec->gpio_led);
}
}
+15
View File
@@ -88,6 +88,21 @@ config SND_HDA_SCODEC_CS35L56_SPI
Say Y or M here to include CS35L56 amplifier support with
SPI control.
menu "CS35L56 driver options"
depends on SND_HDA_SCODEC_CS35L56
config SND_HDA_SCODEC_CS35L56_CAL_DEBUGFS
bool "CS35L56 create debugfs for factory calibration"
default N
depends on DEBUG_FS
select SND_SOC_CS35L56_CAL_DEBUGFS_COMMON
help
Create debugfs entries used during factory-line manufacture
for factory calibration.
If unsure select "N".
endmenu
config SND_HDA_SCODEC_TAS2781
tristate
select SND_HDA_GENERIC
@@ -102,6 +102,7 @@ static int cirrus_scodec_test_gpio_probe(struct platform_device *pdev)
/* GPIO core modifies our struct gpio_chip so use a copy */
gpio_priv->chip = cirrus_scodec_test_gpio_chip;
gpio_priv->chip.parent = &pdev->dev;
ret = devm_gpiochip_add_data(&pdev->dev, &gpio_priv->chip, gpio_priv);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Failed to add gpiochip\n");
@@ -318,7 +319,7 @@ static struct kunit_case cirrus_scodec_test_cases[] = {
};
static struct kunit_suite cirrus_scodec_test_suite = {
.name = "snd-hda-scodec-cs35l56-test",
.name = "snd-hda-cirrus-scodec-test",
.init = cirrus_scodec_test_case_init,
.test_cases = cirrus_scodec_test_cases,
};
+110 -11
View File
@@ -403,10 +403,6 @@ static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56)
snd_ctl_remove(cs35l56->codec->card, cs35l56->volume_ctl);
}
static const struct cs_dsp_client_ops cs35l56_hda_client_ops = {
/* cs_dsp requires the client to provide this even if it is empty */
};
static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
const struct firmware **firmware, char **filename,
const char *base_name, const char *system_name,
@@ -548,20 +544,24 @@ static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmw
kfree(coeff_filename);
}
static void cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
static int cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
{
int ret;
if (!cs35l56->base.cal_data_valid || cs35l56->base.secured)
return;
return -EACCES;
ret = cs_amp_write_cal_coeffs(&cs35l56->cs_dsp,
&cs35l56_calibration_controls,
&cs35l56->base.cal_data);
if (ret < 0)
if (ret < 0) {
dev_warn(cs35l56->base.dev, "Failed to write calibration: %d\n", ret);
else
dev_info(cs35l56->base.dev, "Calibration applied\n");
return ret;
}
dev_info(cs35l56->base.dev, "Calibration applied\n");
return 0;
}
static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
@@ -669,7 +669,9 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
if (ret)
dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
/* Don't need to check return code, it's not fatal if this fails */
cs35l56_hda_apply_calibration(cs35l56);
ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
if (ret)
cs_dsp_stop(&cs35l56->cs_dsp);
@@ -695,6 +697,100 @@ static void cs35l56_hda_dsp_work(struct work_struct *work)
cs35l56_hda_fw_load(cs35l56);
}
static ssize_t cs35l56_hda_debugfs_calibrate_write(struct file *file,
const char __user *from,
size_t count, loff_t *ppos)
{
struct cs35l56_base *cs35l56_base = file->private_data;
ssize_t ret;
ret = pm_runtime_resume_and_get(cs35l56_base->dev);
if (ret)
return ret;
ret = cs35l56_calibrate_debugfs_write(cs35l56_base, from, count, ppos);
pm_runtime_autosuspend(cs35l56_base->dev);
return ret;
}
static ssize_t cs35l56_hda_debugfs_cal_temperature_write(struct file *file,
const char __user *from,
size_t count, loff_t *ppos)
{
struct cs35l56_base *cs35l56_base = file->private_data;
ssize_t ret;
ret = pm_runtime_resume_and_get(cs35l56_base->dev);
if (ret)
return ret;
ret = cs35l56_cal_ambient_debugfs_write(cs35l56_base, from, count, ppos);
pm_runtime_autosuspend(cs35l56_base->dev);
return ret;
}
static ssize_t cs35l56_hda_debugfs_cal_data_read(struct file *file,
char __user *to,
size_t count, loff_t *ppos)
{
struct cs35l56_base *cs35l56_base = file->private_data;
ssize_t ret;
ret = pm_runtime_resume_and_get(cs35l56_base->dev);
if (ret)
return ret;
ret = cs35l56_cal_data_debugfs_read(cs35l56_base, to, count, ppos);
pm_runtime_autosuspend(cs35l56_base->dev);
return ret;
}
static ssize_t cs35l56_hda_debugfs_cal_data_write(struct file *file,
const char __user *from,
size_t count, loff_t *ppos)
{
struct cs35l56_base *cs35l56_base = file->private_data;
struct cs35l56_hda *cs35l56 = cs35l56_hda_from_base(cs35l56_base);
ssize_t ret;
ret = cs35l56_cal_data_debugfs_write(cs35l56_base, from, count, ppos);
if (ret == -ENODATA)
return count; /* Ignore writes of empty cal blobs */
if (ret < 0)
return ret;
ret = pm_runtime_resume_and_get(cs35l56_base->dev);
if (ret)
return ret;
ret = cs35l56_hda_apply_calibration(cs35l56);
if (ret == 0)
cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_AUDIO_REINIT);
else
count = -EIO;
pm_runtime_autosuspend(cs35l56_base->dev);
return count;
}
static const struct cs35l56_cal_debugfs_fops cs35l56_hda_cal_debugfs_fops = {
.calibrate = {
.write = cs35l56_hda_debugfs_calibrate_write,
},
.cal_temperature = {
.write = cs35l56_hda_debugfs_cal_temperature_write,
},
.cal_data = {
.read = cs35l56_hda_debugfs_cal_data_read,
.write = cs35l56_hda_debugfs_cal_data_write,
},
};
static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)
{
struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
@@ -722,6 +818,9 @@ static int cs35l56_hda_bind(struct device *dev, struct device *master, void *mas
cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root);
#endif
if (IS_ENABLED(CONFIG_SND_HDA_SCODEC_CS35L56_CAL_DEBUGFS))
cs35l56_create_cal_debugfs(&cs35l56->base, &cs35l56_hda_cal_debugfs_fops);
dev_dbg(cs35l56->base.dev, "Bound\n");
return 0;
@@ -735,6 +834,7 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *
cancel_work_sync(&cs35l56->dsp_work);
cs35l56_remove_cal_debugfs(&cs35l56->base);
cs35l56_hda_remove_controls(cs35l56);
#if IS_ENABLED(CONFIG_SND_DEBUG)
@@ -1050,10 +1150,9 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
}
cs35l56->base.type = hid & 0xff;
cs35l56->base.cal_index = -1;
cs35l56->base.cal_index = cs35l56->index;
cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);
cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;
if (cs35l56->base.reset_gpio) {
dev_dbg(cs35l56->base.dev, "Hard reset\n");
@@ -9,6 +9,7 @@
#ifndef __CS35L56_HDA_H__
#define __CS35L56_HDA_H__
#include <linux/container_of.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/firmware/cirrus/cs_dsp.h>
@@ -42,6 +43,11 @@ struct cs35l56_hda {
#endif
};
static inline struct cs35l56_hda *cs35l56_hda_from_base(struct cs35l56_base *cs35l56_base)
{
return container_of(cs35l56_base, struct cs35l56_hda, base);
}
extern const struct dev_pm_ops cs35l56_hda_pm_ops;
int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id);
+16 -2
View File
@@ -2,7 +2,7 @@
//
// TAS2781 HDA I2C driver
//
// Copyright 2023 - 2025 Texas Instruments, Inc.
// Copyright 2023 - 2026 Texas Instruments, Inc.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
// Current maintainer: Baojun Xu <baojun.xu@ti.com>
@@ -60,6 +60,7 @@ struct tas2781_hda_i2c_priv {
int (*save_calibration)(struct tas2781_hda *h);
int hda_chip_id;
bool skip_calibration;
};
static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
@@ -491,7 +492,8 @@ static void tasdevice_dspfw_init(void *context)
/* If calibrated data occurs error, dsp will still works with default
* calibrated data inside algo.
*/
hda_priv->save_calibration(tas_hda);
if (!hda_priv->skip_calibration)
hda_priv->save_calibration(tas_hda);
}
static void tasdev_fw_ready(const struct firmware *fmw, void *context)
@@ -548,6 +550,7 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
void *master_data)
{
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
struct hda_component_parent *parent = master_data;
struct hda_component *comp;
struct hda_codec *codec;
@@ -568,11 +571,22 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
case 0x1028:
tas_hda->catlog_id = DELL;
break;
case 0x103C:
tas_hda->catlog_id = HP;
break;
default:
tas_hda->catlog_id = LENOVO;
break;
}
/*
* Using ASUS ROG Xbox Ally X (RC73XA) UEFI calibration data
* causes audio dropouts during playback, use fallback data
* from DSP firmware as a workaround.
*/
if (codec->core.subsystem_id == 0x10431384)
hda_priv->skip_calibration = true;
pm_runtime_get_sync(dev);
comp->dev = dev;
+14
View File
@@ -30,6 +30,20 @@ config SND_HDA_TEGRA
To compile this driver as a module, choose M here: the module
will be called snd-hda-tegra.
config SND_HDA_CIX_IPBLOQ
tristate "CIX IPBLOQ HD Audio"
depends on ARCH_CIX || COMPILE_TEST
select SND_HDA
select SND_HDA_ALIGNED_MMIO
help
Say Y here to support the HDA controller present in CIX SoCs
This options enables support for the HD Audio controller
present in some CIX SoCs.
To compile this driver as a module, choose M here: the module
will be called snd-hda-cix-ipbloq.
config SND_HDA_ACPI
tristate "HD Audio ACPI"
depends on ACPI
+2
View File
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
snd-hda-intel-y := intel.o
snd-hda-tegra-y := tegra.o
snd-hda-cix-ipbloq-y := cix-ipbloq.o
snd-hda-acpi-y := acpi.o
subdir-ccflags-y += -I$(src)/../common
@@ -10,4 +11,5 @@ CFLAGS_intel.o := -I$(src)
obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o
obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o
obj-$(CONFIG_SND_HDA_CIX_IPBLOQ) += snd-hda-cix-ipbloq.o
obj-$(CONFIG_SND_HDA_ACPI) += snd-hda-acpi.o
+434
View File
@@ -0,0 +1,434 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright 2025 Cix Technology Group Co., Ltd.
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/string.h>
#include <sound/hda_codec.h>
#include "hda_controller.h"
#define CIX_IPBLOQ_JACKPOLL_DEFAULT_TIME_MS 1000
#define CIX_IPBLOQ_POWER_SAVE_DEFAULT_TIME_MS 100
#define CIX_IPBLOQ_SKY1_ADDR_HOST_TO_HDAC_OFFSET (-0x90000000ULL)
struct cix_ipbloq_hda {
struct azx chip;
struct device *dev;
void __iomem *regs;
struct reset_control *reset;
struct clk_bulk_data clocks[2];
unsigned int nclocks;
};
static const struct hda_controller_ops cix_ipbloq_hda_ops;
static int cix_ipbloq_hda_dev_disconnect(struct snd_device *device)
{
struct azx *chip = device->device_data;
chip->bus.shutdown = 1;
return 0;
}
static int cix_ipbloq_hda_dev_free(struct snd_device *device)
{
struct azx *chip = device->device_data;
if (azx_bus(chip)->chip_init) {
azx_stop_all_streams(chip);
azx_stop_chip(chip);
}
azx_free_stream_pages(chip);
azx_free_streams(chip);
snd_hdac_bus_exit(azx_bus(chip));
return 0;
}
static int cix_ipbloq_hda_probe_codec(struct cix_ipbloq_hda *hda)
{
struct azx *chip = &hda->chip;
struct hdac_bus *bus = azx_bus(chip);
int err;
to_hda_bus(bus)->bus_probing = 1;
/* create codec instances */
err = azx_probe_codecs(chip, 8);
if (err < 0) {
dev_err(hda->dev, "probe codecs failed: %d\n", err);
return err;
}
err = azx_codec_configure(chip);
if (err < 0) {
dev_err(hda->dev, "codec configure failed: %d\n", err);
return err;
}
err = snd_card_register(chip->card);
if (err < 0) {
dev_err(hda->dev, "card register failed: %d\n", err);
return err;
}
chip->running = 1;
to_hda_bus(bus)->bus_probing = 0;
snd_hda_set_power_save(&chip->bus, CIX_IPBLOQ_POWER_SAVE_DEFAULT_TIME_MS);
return 0;
}
static int cix_ipbloq_hda_init(struct cix_ipbloq_hda *hda,
struct azx *chip,
struct platform_device *pdev)
{
const char *sname = NULL, *drv_name = "cix-ipbloq-hda";
struct hdac_bus *bus = azx_bus(chip);
struct snd_card *card = chip->card;
struct resource *res;
unsigned short gcap;
int irq_id, err;
hda->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(hda->regs)) {
dev_err(hda->dev, "failed to get and ioremap resource\n");
return PTR_ERR(hda->regs);
}
bus->remap_addr = hda->regs;
bus->addr = res->start;
irq_id = platform_get_irq(pdev, 0);
if (irq_id < 0)
return irq_id;
err = devm_request_irq(hda->dev, irq_id, azx_interrupt,
0, KBUILD_MODNAME, chip);
if (err < 0)
return dev_err_probe(hda->dev, err,
"unable to request IRQ %d : err = %d\n", irq_id, err);
bus->irq = irq_id;
card->sync_irq = bus->irq;
gcap = azx_readw(chip, GCAP);
chip->capture_streams = (gcap >> 8) & 0x0f;
chip->playback_streams = (gcap >> 12) & 0x0f;
chip->capture_index_offset = 0;
chip->playback_index_offset = chip->capture_streams;
chip->num_streams = chip->playback_streams + chip->capture_streams;
/* initialize streams */
err = azx_init_streams(chip);
if (err < 0) {
dev_err(hda->dev, "failed to initialize streams: %d\n", err);
return err;
}
err = azx_alloc_stream_pages(chip);
if (err < 0) {
dev_err(hda->dev, "failed to allocate stream pages: %d\n", err);
return err;
}
/* initialize chip */
azx_init_chip(chip, 1);
/* codec detection */
if (!bus->codec_mask) {
dev_err(hda->dev, "no codecs found\n");
return -ENODEV;
}
dev_dbg(card->dev, "codec detection mask = 0x%lx\n", bus->codec_mask);
/* driver name */
strscpy(card->driver, drv_name, sizeof(card->driver));
/* shortname for card */
sname = of_get_property(pdev->dev.of_node, "model", NULL);
if (!sname)
sname = drv_name;
if (strlen(sname) > sizeof(card->shortname))
dev_dbg(card->dev, "truncating shortname for card\n");
strscpy(card->shortname, sname, sizeof(card->shortname));
/* longname for card */
snprintf(card->longname, sizeof(card->longname),
"%s at 0x%lx irq %i",
card->shortname, bus->addr, bus->irq);
return 0;
}
static int cix_ipbloq_hda_create(struct cix_ipbloq_hda *hda,
struct snd_card *card,
unsigned int driver_caps)
{
static const struct snd_device_ops ops = {
.dev_disconnect = cix_ipbloq_hda_dev_disconnect,
.dev_free = cix_ipbloq_hda_dev_free,
};
struct azx *chip;
int err;
chip = &hda->chip;
chip->card = card;
chip->ops = &cix_ipbloq_hda_ops;
chip->driver_caps = driver_caps;
chip->driver_type = driver_caps & 0xff;
chip->dev_index = 0;
chip->single_cmd = 0;
chip->codec_probe_mask = -1;
chip->align_buffer_size = 1;
chip->jackpoll_interval = msecs_to_jiffies(CIX_IPBLOQ_JACKPOLL_DEFAULT_TIME_MS);
mutex_init(&chip->open_mutex);
INIT_LIST_HEAD(&chip->pcm_list);
/*
* HD-audio controllers appear pretty inaccurate about the update-IRQ timing.
* The IRQ is issued before actually the data is processed. So use stream
* link position by default instead of dma position buffer.
*/
chip->get_position[0] = chip->get_position[1] = azx_get_pos_lpib;
err = azx_bus_init(chip, NULL);
if (err < 0) {
dev_err(hda->dev, "failed to init bus, err = %d\n", err);
return err;
}
/* RIRBSTS.RINTFL cannot be cleared, cause interrupt storm */
chip->bus.core.polling_mode = 1;
chip->bus.core.not_use_interrupts = 1;
chip->bus.core.aligned_mmio = 1;
chip->bus.core.dma_stop_delay = 100;
chip->bus.core.addr_offset = (dma_addr_t)CIX_IPBLOQ_SKY1_ADDR_HOST_TO_HDAC_OFFSET;
chip->bus.jackpoll_in_suspend = 1;
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err < 0) {
dev_err(card->dev, "failed to create device, err = %d\n", err);
return err;
}
return 0;
}
static int cix_ipbloq_hda_probe(struct platform_device *pdev)
{
const unsigned int driver_flags = AZX_DCAPS_PM_RUNTIME;
struct cix_ipbloq_hda *hda;
struct snd_card *card;
struct azx *chip;
int err;
hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL);
if (!hda)
return -ENOMEM;
hda->dev = &pdev->dev;
hda->reset = devm_reset_control_get(hda->dev, NULL);
if (IS_ERR(hda->reset))
return dev_err_probe(hda->dev, PTR_ERR(hda->reset),
"failed to get reset, err = %ld\n", PTR_ERR(hda->reset));
hda->clocks[hda->nclocks++].id = "ipg";
hda->clocks[hda->nclocks++].id = "per";
err = devm_clk_bulk_get(hda->dev, hda->nclocks, hda->clocks);
if (err < 0)
return dev_err_probe(hda->dev, err, "failed to get clk, err = %d\n", err);
dma_set_mask_and_coherent(hda->dev, DMA_BIT_MASK(32));
err = of_reserved_mem_device_init(hda->dev);
if (err < 0 && err != -ENODEV) {
dev_err(hda->dev,
"failed to init reserved mem for DMA, err = %d\n", err);
return err;
}
err = snd_card_new(hda->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, 0, &card);
if (err < 0)
return dev_err_probe(hda->dev, err, "failed to crate card, err = %d\n", err);
err = cix_ipbloq_hda_create(hda, card, driver_flags);
if (err < 0)
goto out_free_card;
chip = &hda->chip;
card->private_data = chip;
dev_set_drvdata(hda->dev, card);
pm_runtime_enable(hda->dev);
if (!azx_has_pm_runtime(chip))
pm_runtime_forbid(hda->dev);
err = pm_runtime_resume_and_get(hda->dev);
if (err < 0) {
dev_err(hda->dev, "runtime resume and get failed, err = %d\n", err);
goto out_free_device;
}
err = cix_ipbloq_hda_init(hda, chip, pdev);
if (err < 0)
goto out_free_device;
err = cix_ipbloq_hda_probe_codec(hda);
if (err < 0)
goto out_free_device;
pm_runtime_put(hda->dev);
return 0;
out_free_device:
snd_device_free(card, chip);
out_free_card:
snd_card_free(card);
return err;
}
static void cix_ipbloq_hda_remove(struct platform_device *pdev)
{
struct snd_card *card = dev_get_drvdata(&pdev->dev);
struct azx *chip = card->private_data;
snd_device_free(card, chip);
snd_card_free(card);
pm_runtime_disable(&pdev->dev);
}
static void cix_ipbloq_hda_shutdown(struct platform_device *pdev)
{
struct snd_card *card = dev_get_drvdata(&pdev->dev);
struct azx *chip;
if (!card)
return;
chip = card->private_data;
if (chip && chip->running)
azx_stop_chip(chip);
}
static int cix_ipbloq_hda_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
int rc;
rc = pm_runtime_force_suspend(dev);
if (rc < 0)
return rc;
snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
return 0;
}
static int cix_ipbloq_hda_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
int rc;
rc = pm_runtime_force_resume(dev);
if (rc < 0)
return rc;
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
static int cix_ipbloq_hda_runtime_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
struct cix_ipbloq_hda *hda = container_of(chip, struct cix_ipbloq_hda, chip);
if (chip && chip->running) {
azx_stop_chip(chip);
azx_enter_link_reset(chip);
}
clk_bulk_disable_unprepare(hda->nclocks, hda->clocks);
return 0;
}
static int cix_ipbloq_hda_runtime_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
struct cix_ipbloq_hda *hda = container_of(chip, struct cix_ipbloq_hda, chip);
int rc;
rc = clk_bulk_prepare_enable(hda->nclocks, hda->clocks);
if (rc) {
dev_err(dev, "failed to enable clk bulk, rc: %d\n", rc);
return rc;
}
rc = reset_control_assert(hda->reset);
if (rc) {
dev_err(dev, "failed to assert reset, rc: %d\n", rc);
return rc;
}
rc = reset_control_deassert(hda->reset);
if (rc) {
dev_err(dev, "failed to deassert reset, rc: %d\n", rc);
return rc;
}
if (chip && chip->running)
azx_init_chip(chip, 1);
return 0;
}
static const struct dev_pm_ops cix_ipbloq_hda_pm = {
SYSTEM_SLEEP_PM_OPS(cix_ipbloq_hda_suspend,
cix_ipbloq_hda_resume)
RUNTIME_PM_OPS(cix_ipbloq_hda_runtime_suspend,
cix_ipbloq_hda_runtime_resume, NULL)
};
static const struct of_device_id cix_ipbloq_hda_match[] = {
{ .compatible = "cix,sky1-ipbloq-hda" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, cix_ipbloq_hda_match);
static struct platform_driver cix_ipbloq_hda_driver = {
.driver = {
.name = "cix-ipbloq-hda",
.pm = pm_ptr(&cix_ipbloq_hda_pm),
.of_match_table = cix_ipbloq_hda_match,
},
.probe = cix_ipbloq_hda_probe,
.remove = cix_ipbloq_hda_remove,
.shutdown = cix_ipbloq_hda_shutdown,
};
module_platform_driver(cix_ipbloq_hda_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CIX IPBLOQ HDA bus driver");
MODULE_AUTHOR("Joakim Zhang <joakim.zhang@cixtech.com>");
+2
View File
@@ -2549,6 +2549,8 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE_DATA(INTEL, HDA_PTL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
/* Wildcat Lake */
{ PCI_DEVICE_DATA(INTEL, HDA_WCL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
/* Nova Lake */
{ PCI_DEVICE_DATA(INTEL, HDA_NVL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
/* Apollolake (Broxton-P) */
{ PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) },
/* Gemini-Lake */
+1
View File
@@ -47,6 +47,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
INIT_LIST_HEAD(&bus->hlink_list);
init_waitqueue_head(&bus->rirb_wq);
bus->irq = -1;
bus->addr_offset = 0;
/*
* Default value of '8' is as per the HD audio specification (Rev 1.0a).
+6 -6
View File
@@ -48,8 +48,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
/* CORB set up */
bus->corb.addr = bus->rb.addr;
bus->corb.buf = (__le32 *)bus->rb.area;
snd_hdac_chip_writel(bus, CORBLBASE, (u32)bus->corb.addr);
snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr));
snd_hdac_chip_writel(bus, CORBLBASE, (u32)(bus->corb.addr + bus->addr_offset));
snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr + bus->addr_offset));
/* set the corb size to 256 entries (ULI requires explicitly) */
snd_hdac_chip_writeb(bus, CORBSIZE, 0x02);
@@ -70,8 +70,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
bus->rirb.buf = (__le32 *)(bus->rb.area + 2048);
bus->rirb.wp = bus->rirb.rp = 0;
memset(bus->rirb.cmds, 0, sizeof(bus->rirb.cmds));
snd_hdac_chip_writel(bus, RIRBLBASE, (u32)bus->rirb.addr);
snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr));
snd_hdac_chip_writel(bus, RIRBLBASE, (u32)(bus->rirb.addr + bus->addr_offset));
snd_hdac_chip_writel(bus, RIRBUBASE, upper_32_bits(bus->rirb.addr + bus->addr_offset));
/* set the rirb size to 256 entries (ULI requires explicitly) */
snd_hdac_chip_writeb(bus, RIRBSIZE, 0x02);
@@ -625,8 +625,8 @@ bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset)
/* program the position buffer */
if (bus->use_posbuf && bus->posbuf.addr) {
snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr);
snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr));
snd_hdac_chip_writel(bus, DPLBASE, (u32)(bus->posbuf.addr + bus->addr_offset));
snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr + bus->addr_offset));
}
bus->chip_init = true;
+10 -1
View File
@@ -574,6 +574,14 @@ static const struct config_entry config_table[] = {
#endif
/* Nova Lake */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOVALAKE)
{
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
.device = PCI_DEVICE_ID_INTEL_HDA_NVL_S,
},
#endif
};
static const struct config_entry *snd_intel_dsp_find_config
@@ -706,7 +714,8 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
/* find the configuration for the specific device */
cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
if (!cfg)
return SND_INTEL_DSP_DRIVER_ANY;
return IS_ENABLED(CONFIG_SND_HDA_INTEL) ?
SND_INTEL_DSP_DRIVER_LEGACY : SND_INTEL_DSP_DRIVER_ANY;
if (cfg->flags & FLAG_SOF) {
if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
+5 -5
View File
@@ -288,16 +288,16 @@ int snd_hdac_stream_setup(struct hdac_stream *azx_dev, bool code_loading)
/* program the BDL address */
/* lower BDL address */
snd_hdac_stream_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr);
snd_hdac_stream_writel(azx_dev, SD_BDLPL, (u32)(azx_dev->bdl.addr + bus->addr_offset));
/* upper BDL address */
snd_hdac_stream_writel(azx_dev, SD_BDLPU,
upper_32_bits(azx_dev->bdl.addr));
upper_32_bits(azx_dev->bdl.addr + bus->addr_offset));
/* enable the position buffer */
if (bus->use_posbuf && bus->posbuf.addr) {
if (!(snd_hdac_chip_readl(bus, DPLBASE) & AZX_DPLBASE_ENABLE))
snd_hdac_chip_writel(bus, DPLBASE,
(u32)bus->posbuf.addr | AZX_DPLBASE_ENABLE);
(u32)(bus->posbuf.addr + bus->addr_offset) | AZX_DPLBASE_ENABLE);
}
/* set the interrupt enable bits in the descriptor control register */
@@ -464,8 +464,8 @@ static int setup_bdle(struct hdac_bus *bus,
addr = snd_sgbuf_get_addr(dmab, ofs);
/* program the address field of the BDL entry */
bdl[0] = cpu_to_le32((u32)addr);
bdl[1] = cpu_to_le32(upper_32_bits(addr));
bdl[0] = cpu_to_le32((u32)(addr + bus->addr_offset));
bdl[1] = cpu_to_le32(upper_32_bits(addr + bus->addr_offset));
/* program the size field of the BDL entry */
chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size);
/* one BDLE cannot cross 4K boundary on CTHDA chips */
-3
View File
@@ -9,9 +9,6 @@
#include <sound/core.h>
#include <sound/gus.h>
extern int snd_gf1_synth_init(struct snd_gus_card * gus);
extern void snd_gf1_synth_done(struct snd_gus_card * gus);
/*
* ok.. default interrupt handlers...
*/
+1 -1
View File
@@ -568,7 +568,7 @@ static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex)
eqlzr_t *eq = &(vortex->eq);
vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130);
vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10]));
vortex_EqHw_SetRightGainsTarget(vortex, eq->this130 + eq->this10);
return 0;
}
+2
View File
@@ -205,6 +205,7 @@ static int amixer_rsc_init(struct amixer *amixer,
/* Set amixer specific operations */
amixer->rsc.ops = &amixer_basic_rsc_ops;
amixer->rsc.conj = 0;
amixer->ops = &amixer_ops;
amixer->input = NULL;
amixer->sum = NULL;
@@ -367,6 +368,7 @@ static int sum_rsc_init(struct sum *sum,
return err;
sum->rsc.ops = &sum_basic_rsc_ops;
sum->rsc.conj = 0;
return 0;
}
+71 -26
View File
@@ -25,6 +25,9 @@
#include <sound/control.h>
#include <sound/asoundef.h>
#define NUM_ATC_SRCS 6
#define NUM_ATC_PCM (2 * 4)
#define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */
#define MAX_MULTI_CHN 8
@@ -60,6 +63,7 @@ static const struct snd_pci_quirk subsys_20k2_list[] = {
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000,
PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX",
CTHENDRIX),
SND_PCI_QUIRK(0x160b, 0x0101, "OK0010", CTOK0010),
{ } /* terminator */
};
@@ -75,6 +79,7 @@ static const char *ct_subsys_name[NUM_CTCARDS] = {
[CTHENDRIX] = "Hendrix",
[CTSB0880] = "SB0880",
[CTSB1270] = "SB1270",
[CTOK0010] = "OK0010",
[CT20K2_UNKNOWN] = "Unknown",
};
@@ -984,6 +989,24 @@ static struct capabilities atc_capabilities(struct ct_atc *atc)
return hw->capabilities(hw);
}
static void atc_dedicated_rca_select(struct ct_atc *atc)
{
struct dao *dao;
struct ct_mixer *mixer = atc->mixer;
struct rsc *rscs[2] = {NULL};
dao = container_of(atc->daios[atc->rca_state ? RCA : LINEO1],
struct dao, daio);
dao->ops->clear_left_input(dao);
dao->ops->clear_right_input(dao);
mixer->get_output_ports(mixer, MIX_WAVE_FRONT, &rscs[0], &rscs[1]);
dao = container_of(atc->daios[atc->rca_state ? LINEO1 : RCA],
struct dao, daio);
dao->ops->set_left_input(dao, rscs[0]);
dao->ops->set_right_input(dao, rscs[1]);
}
static int atc_output_switch_get(struct ct_atc *atc)
{
struct hw *hw = atc->hw;
@@ -1085,6 +1108,11 @@ static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
return atc_daio_unmute(atc, state, MIC);
}
static int atc_rca_unmute(struct ct_atc *atc, unsigned char state)
{
return atc_daio_unmute(atc, state, RCA);
}
static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
{
return atc_daio_unmute(atc, state, SPDIFOO);
@@ -1161,9 +1189,11 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->daios) {
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
for (i = 0; i < atc->n_daio; i++) {
for (i = 0; i < NUM_DAIOTYP; i++) {
daio = atc->daios[i];
if (daio->type < LINEIM) {
if (!daio)
continue;
if (daio->output) {
dao = container_of(daio, struct dao, daio);
dao->ops->clear_left_input(dao);
dao->ops->clear_right_input(dao);
@@ -1176,8 +1206,9 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->pcm) {
sum_mgr = atc->rsc_mgrs[SUM];
for (i = 0; i < atc->n_pcm; i++)
sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
for (i = 0; i < NUM_ATC_PCM; i++)
if (atc->pcm[i])
sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
kfree(atc->pcm);
atc->pcm = NULL;
@@ -1185,8 +1216,9 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->srcs) {
src_mgr = atc->rsc_mgrs[SRC];
for (i = 0; i < atc->n_src; i++)
src_mgr->put_src(src_mgr, atc->srcs[i]);
for (i = 0; i < NUM_ATC_SRCS; i++)
if (atc->srcs[i])
src_mgr->put_src(src_mgr, atc->srcs[i]);
kfree(atc->srcs);
atc->srcs = NULL;
@@ -1194,7 +1226,9 @@ static int atc_release_resources(struct ct_atc *atc)
if (atc->srcimps) {
srcimp_mgr = atc->rsc_mgrs[SRCIMP];
for (i = 0; i < atc->n_srcimp; i++) {
for (i = 0; i < NUM_ATC_SRCS; i++) {
if (!atc->srcimps[i])
continue;
srcimp = atc->srcimps[i];
srcimp->ops->unmap(srcimp);
srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
@@ -1294,6 +1328,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid)
dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n",
atc->chip_name, atc->model_name,
vendor_id, device_id);
atc->rca_state = 0;
return 0;
}
@@ -1367,32 +1402,35 @@ static int atc_get_resources(struct ct_atc *atc)
struct srcimp_mgr *srcimp_mgr;
struct sum_desc sum_dsc = {0};
struct sum_mgr *sum_mgr;
int err, i, num_srcs, num_daios;
struct capabilities cap;
int err, i;
num_daios = ((atc->model == CTSB1270) ? 8 : 7);
num_srcs = ((atc->model == CTSB1270) ? 6 : 4);
cap = atc->capabilities(atc);
atc->daios = kcalloc(num_daios, sizeof(void *), GFP_KERNEL);
atc->daios = kcalloc(NUM_DAIOTYP, sizeof(void *), GFP_KERNEL);
if (!atc->daios)
return -ENOMEM;
atc->srcs = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
atc->srcs = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
if (!atc->srcs)
return -ENOMEM;
atc->srcimps = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
atc->srcimps = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL);
if (!atc->srcimps)
return -ENOMEM;
atc->pcm = kcalloc(2 * 4, sizeof(void *), GFP_KERNEL);
atc->pcm = kcalloc(NUM_ATC_PCM, sizeof(void *), GFP_KERNEL);
if (!atc->pcm)
return -ENOMEM;
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
da_desc.msr = atc->msr;
for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
for (i = 0; i < NUM_DAIOTYP; i++) {
if (((i == MIC) && !cap.dedicated_mic) || ((i == RCA) && !cap.dedicated_rca))
continue;
da_desc.type = (atc->model != CTSB073X) ? i :
((i == SPDIFIO) ? SPDIFI1 : i);
da_desc.output = (i < LINEIM) || (i == RCA);
err = daio_mgr->get_daio(daio_mgr, &da_desc,
(struct daio **)&atc->daios[i]);
if (err) {
@@ -1401,42 +1439,39 @@ static int atc_get_resources(struct ct_atc *atc)
i);
return err;
}
atc->n_daio++;
}
src_mgr = atc->rsc_mgrs[SRC];
src_dsc.multi = 1;
src_dsc.msr = atc->msr;
src_dsc.mode = ARCRW;
for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
for (i = 0; i < NUM_ATC_SRCS; i++) {
if (((i > 3) && !cap.dedicated_mic))
continue;
err = src_mgr->get_src(src_mgr, &src_dsc,
(struct src **)&atc->srcs[i]);
if (err)
return err;
atc->n_src++;
}
srcimp_mgr = atc->rsc_mgrs[SRCIMP];
srcimp_dsc.msr = 8;
for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
for (i = 0; i < NUM_ATC_SRCS; i++) {
if (((i > 3) && !cap.dedicated_mic))
continue;
err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
(struct srcimp **)&atc->srcimps[i]);
if (err)
return err;
atc->n_srcimp++;
}
sum_mgr = atc->rsc_mgrs[SUM];
sum_dsc.msr = atc->msr;
for (i = 0, atc->n_pcm = 0; i < (2*4); i++) {
for (i = 0; i < NUM_ATC_PCM; i++) {
err = sum_mgr->get_sum(sum_mgr, &sum_dsc,
(struct sum **)&atc->pcm[i]);
if (err)
return err;
atc->n_pcm++;
}
return 0;
@@ -1489,9 +1524,11 @@ static void atc_connect_resources(struct ct_atc *atc)
struct sum *sum;
struct ct_mixer *mixer;
struct rsc *rscs[2] = {NULL};
struct capabilities cap;
int i, j;
mixer = atc->mixer;
cap = atc->capabilities(atc);
for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) {
mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]);
@@ -1500,6 +1537,11 @@ static void atc_connect_resources(struct ct_atc *atc)
dao->ops->set_right_input(dao, rscs[1]);
}
if (cap.dedicated_rca) {
/* SE-300PCIE has a dedicated DAC for the RCA. */
atc_dedicated_rca_select(atc);
}
dai = container_of(atc->daios[LINEIM], struct dai, daio);
atc_connect_dai(atc->rsc_mgrs[SRC], dai,
(struct src **)&atc->srcs[2],
@@ -1509,8 +1551,9 @@ static void atc_connect_resources(struct ct_atc *atc)
src = atc->srcs[3];
mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
if (atc->model == CTSB1270) {
if (cap.dedicated_mic) {
/* Titanium HD has a dedicated ADC for the Mic. */
/* SE-300PCIE has a 4-channel ADC. */
dai = container_of(atc->daios[MIC], struct dai, daio);
atc_connect_dai(atc->rsc_mgrs[SRC], dai,
(struct src **)&atc->srcs[4],
@@ -1632,12 +1675,14 @@ static const struct ct_atc atc_preset = {
.line_rear_unmute = atc_line_rear_unmute,
.line_in_unmute = atc_line_in_unmute,
.mic_unmute = atc_mic_unmute,
.rca_unmute = atc_rca_unmute,
.spdif_out_unmute = atc_spdif_out_unmute,
.spdif_in_unmute = atc_spdif_in_unmute,
.spdif_out_get_status = atc_spdif_out_get_status,
.spdif_out_set_status = atc_spdif_out_set_status,
.spdif_out_passthru = atc_spdif_out_passthru,
.capabilities = atc_capabilities,
.dedicated_rca_select = atc_dedicated_rca_select,
.output_switch_get = atc_output_switch_get,
.output_switch_put = atc_output_switch_put,
.mic_source_switch_get = atc_mic_source_switch_get,
+4 -4
View File
@@ -82,6 +82,8 @@ struct ct_atc {
const char *chip_name;
const char *model_name;
unsigned char rca_state; /* 0 = dedicated RCA, 1 = 7.1ch Front */
struct ct_vm *vm; /* device virtual memory manager for this card */
int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
@@ -113,12 +115,14 @@ struct ct_atc {
int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
int (*mic_unmute)(struct ct_atc *atc, unsigned char state);
int (*rca_unmute)(struct ct_atc *atc, unsigned char state);
int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
struct capabilities (*capabilities)(struct ct_atc *atc);
void (*dedicated_rca_select)(struct ct_atc *atc);
int (*output_switch_get)(struct ct_atc *atc);
int (*output_switch_put)(struct ct_atc *atc, int position);
int (*mic_source_switch_get)(struct ct_atc *atc);
@@ -132,10 +136,6 @@ struct ct_atc {
void **pcm; /* SUMs for collecting all pcm stream */
void **srcs; /* Sample Rate Converters for input signal */
void **srcimps; /* input mappers for SRCs */
unsigned char n_daio;
unsigned char n_src;
unsigned char n_srcimp;
unsigned char n_pcm;
struct ct_timer *timer;
+10 -8
View File
@@ -18,8 +18,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#define DAIO_OUT_MAX SPDIFOO
struct daio_usage {
unsigned short data;
};
@@ -47,6 +45,7 @@ static const struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
[LINEO4] = {.left = 0x70, .right = 0x71},
[LINEIM] = {.left = 0x45, .right = 0xc5},
[MIC] = {.left = 0x55, .right = 0xd5},
[RCA] = {.left = 0x30, .right = 0x31},
[SPDIFOO] = {.left = 0x00, .right = 0x01},
[SPDIFIO] = {.left = 0x05, .right = 0x85},
};
@@ -125,6 +124,7 @@ static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
case LINEO4: return 6;
case LINEIM: return 4;
case MIC: return 5;
case RCA: return 3;
default: return -EINVAL;
}
default:
@@ -329,7 +329,7 @@ static int daio_rsc_init(struct daio *daio,
goto error1;
/* Set daio->rscl/r->ops to daio specific ones */
if (desc->type <= DAIO_OUT_MAX) {
if (desc->output) {
daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
} else {
switch (hw->chip_type) {
@@ -344,6 +344,7 @@ static int daio_rsc_init(struct daio *daio,
}
}
daio->type = desc->type;
daio->output = desc->output;
return 0;
@@ -390,7 +391,7 @@ static int dao_rsc_init(struct dao *dao,
hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
conf = (desc->msr & 0x7) | (desc->passthru << 3);
hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk,
hw->daio_mgr_dao_init(hw, mgr->mgr.ctrl_blk,
daio_device_index(dao->daio.type, hw), conf);
hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
daio_device_index(dao->daio.type, hw));
@@ -433,6 +434,7 @@ static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc)
dsc.type = dao->daio.type;
dsc.msr = desc->msr;
dsc.passthru = desc->passthru;
dsc.output = dao->daio.output;
dao_rsc_uninit(dao);
return dao_rsc_init(dao, &dsc, mgr);
}
@@ -518,7 +520,7 @@ static int get_daio_rsc(struct daio_mgr *mgr,
err = -ENOMEM;
/* Allocate mem for daio resource */
if (desc->type <= DAIO_OUT_MAX) {
if (desc->output) {
struct dao *dao = kzalloc(sizeof(*dao), GFP_KERNEL);
if (!dao)
goto error;
@@ -565,7 +567,7 @@ static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)
daio_mgr_put_rsc(&mgr->mgr, daio->type);
}
if (daio->type <= DAIO_OUT_MAX) {
if (daio->output) {
dao_rsc_uninit(container_of(daio, struct dao, daio));
kfree(container_of(daio, struct dao, daio));
} else {
@@ -580,7 +582,7 @@ static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
if (DAIO_OUT_MAX >= daio->type) {
if (daio->output) {
hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
} else {
@@ -594,7 +596,7 @@ static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
if (DAIO_OUT_MAX >= daio->type) {
if (daio->output) {
hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
} else {
+3
View File
@@ -31,6 +31,7 @@ enum DAIOTYP {
LINEIM,
SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */
MIC, /* Dedicated mic on Titanium HD */
RCA, /* Dedicated RCA on SE-300PCIE */
SPDIFI1, /* S/PDIF In on internal Drive Bay */
NUM_DAIOTYP
};
@@ -43,6 +44,7 @@ struct daio {
struct rsc rscl; /* Basic resource info for left TX/RX */
struct rsc rscr; /* Basic resource info for right TX/RX */
enum DAIOTYP type;
unsigned char output;
};
struct dao {
@@ -91,6 +93,7 @@ struct daio_desc {
unsigned int type:4;
unsigned int msr:4;
unsigned int passthru:1;
unsigned int output:1;
};
struct daio_mgr {
+3 -1
View File
@@ -38,6 +38,7 @@ enum CTCARDS {
CTHENDRIX,
CTSB0880,
CTSB1270,
CTOK0010,
CT20K2_UNKNOWN,
NUM_CTCARDS /* This should always be the last */
};
@@ -62,6 +63,7 @@ struct card_conf {
struct capabilities {
unsigned int digit_io_switch:1;
unsigned int dedicated_mic:1;
unsigned int dedicated_rca:1;
unsigned int output_switch:1;
unsigned int mic_source_switch:1;
};
@@ -167,7 +169,7 @@ struct hw {
int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx);
int (*daio_mgr_enb_dao)(void *blk, unsigned int idx);
int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx);
int (*daio_mgr_dao_init)(void *blk, unsigned int idx,
int (*daio_mgr_dao_init)(struct hw *hw, void *blk, unsigned int idx,
unsigned int conf);
int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot);
int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next);
+2 -1
View File
@@ -1031,7 +1031,7 @@ static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
return 0;
}
static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
static int daio_mgr_dao_init(struct hw *hw __maybe_unused, void *blk, unsigned int idx, unsigned int conf)
{
struct daio_mgr_ctrl_blk *ctl = blk;
@@ -1775,6 +1775,7 @@ static struct capabilities hw_capabilities(struct hw *hw)
/* SB073x and Vista compatible cards have no digit IO switch */
cap.digit_io_switch = !(hw->model == CTSB073X || hw->model == CTUAA);
cap.dedicated_mic = 0;
cap.dedicated_rca = 0;
cap.output_switch = 0;
cap.mic_source_switch = 0;
+62 -19
View File
@@ -910,7 +910,7 @@ static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk)
struct dao_ctrl_blk *ctl = blk;
if (ctl->dirty.bf.atxcsl) {
if (idx < 4) {
if ((idx < 4) && ((hw->model != CTOK0010) || (idx < 3))) {
/* S/PDIF SPOSx */
hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx,
ctl->atxcsl);
@@ -985,11 +985,12 @@ static int daio_mgr_dsb_dao(void *blk, unsigned int idx)
return 0;
}
static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf)
static int daio_mgr_dao_init(struct hw *hw, void *blk, unsigned int idx, unsigned int conf)
{
struct daio_mgr_ctrl_blk *ctl = blk;
if (idx < 4) {
/* Port 3 is dedicated to RCA on SE-300PCIE */
if ((idx < 4) && ((hw->model != CTOK0010) || (idx < 3))) {
/* S/PDIF output */
switch ((conf & 0xf)) {
case 1:
@@ -1176,6 +1177,10 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21011111);
hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
} else if ((4 == info->msr) && (hw->model == CTOK0010)) {
hw_write_20kx(hw, AUDIO_IO_MCLK, 0x21212121);
hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x21212121);
hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0);
} else {
dev_alert(hw->card->dev,
"ERROR!!! Invalid sampling rate!!!\n");
@@ -1183,7 +1188,8 @@ static int hw_daio_init(struct hw *hw, const struct daio_conf *info)
}
for (i = 0; i < 8; i++) {
if (i <= 3) {
/* Port 3 is configured as I2S on SE-300PCIE */
if ((i < 4) && ((hw->model != CTOK0010) || (i < 3))) {
/* This comment looks wrong since loop is over 4 */
/* channels and emu20k2 supports 4 spdif IOs. */
/* 1st 3 channels are SPDIFs (SB0960) */
@@ -1637,6 +1643,13 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
hw_write_20kx(hw, GPIO_DATA, data);
hw_dac_start(hw);
return 0;
} else if (hw->model == CTOK0010) {
hw_dac_stop(hw);
data = hw_read_20kx(hw, GPIO_DATA);
data |= 0x1000;
hw_write_20kx(hw, GPIO_DATA, data);
hw_dac_start(hw);
return 0;
}
/* Set DAC reset bit as output */
@@ -1756,9 +1769,11 @@ End:
static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
{
u32 data;
if (hw->model == CTSB1270) {
if ((hw->model == CTSB1270) || (hw->model == CTOK0010)) {
/* Titanium HD has two ADC chips, one for line in and one */
/* for MIC. We don't need to switch the ADC input. */
/* for MIC. Also, SE-300PCIE has a single ADC chip that */
/* simultaneously supports 4-channel input. We don't need */
/* to switch the ADC input. */
return 1;
}
data = hw_read_20kx(hw, GPIO_DATA);
@@ -1826,6 +1841,32 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
return 0;
}
static void hw_adc_stop(struct hw *hw)
{
u32 data;
/* Reset the ADC (reset is active low). */
data = hw_read_20kx(hw, GPIO_DATA);
data &= ~(0x1 << 15);
hw_write_20kx(hw, GPIO_DATA, data);
usleep_range(10000, 11000);
}
static void hw_adc_start(struct hw *hw)
{
u32 data;
/* Return the ADC to normal operation. */
data = hw_read_20kx(hw, GPIO_DATA);
data |= (0x1 << 15);
hw_write_20kx(hw, GPIO_DATA, data);
msleep(50);
}
static void hw_adc_reset(struct hw *hw)
{
hw_adc_stop(hw);
hw_adc_start(hw);
}
static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
{
int err;
@@ -1836,6 +1877,12 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
data |= (0x1 << 15);
hw_write_20kx(hw, GPIO_CTRL, data);
if (hw->model == CTOK0010) {
/* Manual ADC setup for SE-300PCIE is not needed. */
hw_adc_reset(hw);
return 0;
}
/* Initialize I2C */
err = hw20k2_i2c_init(hw, 0x1A, 1, 1);
if (err < 0) {
@@ -1843,10 +1890,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
goto error;
}
/* Reset the ADC (reset is active low). */
data = hw_read_20kx(hw, GPIO_DATA);
data &= ~(0x1 << 15);
hw_write_20kx(hw, GPIO_DATA, data);
hw_adc_stop(hw);
if (hw->model == CTSB1270) {
/* Set up the PCM4220 ADC on Titanium HD */
@@ -1860,11 +1904,7 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
hw_write_20kx(hw, GPIO_DATA, data);
}
usleep_range(10000, 11000);
/* Return the ADC to normal operation. */
data |= (0x1 << 15);
hw_write_20kx(hw, GPIO_DATA, data);
msleep(50);
hw_adc_start(hw);
/* I2C write to register offset 0x0B to set ADC LRCLK polarity */
/* invert bit, interface format to I2S, word length to 24-bit, */
@@ -1910,7 +1950,8 @@ static struct capabilities hw_capabilities(struct hw *hw)
struct capabilities cap;
cap.digit_io_switch = 0;
cap.dedicated_mic = hw->model == CTSB1270;
cap.dedicated_mic = (hw->model == CTSB1270) || (hw->model == CTOK0010);
cap.dedicated_rca = hw->model == CTOK0010;
cap.output_switch = hw->model == CTSB1270;
cap.mic_source_switch = hw->model == CTSB1270;
@@ -2147,15 +2188,17 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
/* Reset all SRC pending interrupts */
hw_write_20kx(hw, SRC_IP, 0);
if (hw->model != CTSB1270) {
if (hw->model == CTSB1270) {
hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
} else if (hw->model == CTOK0010) {
hw_write_20kx(hw, GPIO_CTRL, 0x9902);
} else {
/* TODO: detect the card ID and configure GPIO accordingly. */
/* Configures GPIO (0xD802 0x98028) */
/*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/
/* Configures GPIO (SB0880) */
/*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/
hw_write_20kx(hw, GPIO_CTRL, 0xD802);
} else {
hw_write_20kx(hw, GPIO_CTRL, 0x9E5F);
}
/* Enable audio ring */
hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01);
+70 -3
View File
@@ -547,8 +547,14 @@ static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
atc->mic_unmute(atc, state);
else if (MIXER_SPDIFI_C_S == type)
atc->spdif_in_unmute(atc, state);
else if (MIXER_WAVEF_P_S == type)
atc->line_front_unmute(atc, state);
else if (MIXER_WAVEF_P_S == type) {
if (cap.dedicated_rca) {
atc->rca_unmute(atc, atc->rca_state ? 0 : state);
atc->line_front_unmute(atc, atc->rca_state ? state : 0);
} else {
atc->line_front_unmute(atc, state);
}
}
else if (MIXER_WAVES_P_S == type)
atc->line_surround_unmute(atc, state);
else if (MIXER_WAVEC_P_S == type)
@@ -612,6 +618,57 @@ static struct snd_kcontrol_new swh_ctl = {
.put = ct_alsa_mix_switch_put
};
static int dedicated_rca_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *info)
{
static const char *const names[2] = {
"RCA", "Front"
};
return snd_ctl_enum_info(info, 1, 2, names);
}
static int dedicated_rca_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
ucontrol->value.enumerated.item[0] = atc->rca_state;
return 0;
}
static int dedicated_rca_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
unsigned int rca_state = ucontrol->value.enumerated.item[0];
unsigned char state;
if (rca_state > 1)
return -EINVAL;
if (rca_state == atc->rca_state)
return 0;
state = get_switch_state(atc->mixer, MIXER_WAVEF_P_S);
do_switch(atc, MIXER_WAVEF_P_S, 0);
atc->rca_state = rca_state;
atc->dedicated_rca_select(atc);
do_switch(atc, MIXER_WAVEF_P_S, state);
return 1;
}
static struct snd_kcontrol_new rca_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Analog Playback Route",
.info = dedicated_rca_info,
.get = dedicated_rca_get,
.put = dedicated_rca_put,
};
static int ct_spdif_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -784,7 +841,17 @@ static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
if (err)
return err;
}
atc->line_front_unmute(atc, 1);
if (cap.dedicated_rca) {
err = ct_mixer_kcontrol_new(mixer, &rca_ctl);
if (err)
return err;
atc->line_front_unmute(atc, 0);
atc->rca_unmute(atc, 1);
} else {
atc->line_front_unmute(atc, 1);
}
set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
atc->line_surround_unmute(atc, 0);
set_switch_state(mixer, MIXER_WAVES_P_S, 0);
+3 -3
View File
@@ -2571,9 +2571,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
if (IS_ENABLED(CONFIG_PM_SLEEP)) {
chip->suspend_mem =
vmalloc(array_size(sizeof(u16),
REV_B_CODE_MEMORY_LENGTH +
REV_B_DATA_MEMORY_LENGTH));
vmalloc_array(REV_B_CODE_MEMORY_LENGTH +
REV_B_DATA_MEMORY_LENGTH,
sizeof(u16));
if (!chip->suspend_mem)
dev_warn(card->dev, "can't allocate apm buffer\n");
}
+7 -1
View File
@@ -284,7 +284,13 @@ static int vxpocket_probe(struct pcmcia_device *p_dev)
vxp->p_dev = p_dev;
return vxpocket_config(p_dev);
err = vxpocket_config(p_dev);
if (err < 0) {
card_alloc &= ~(1 << i);
snd_card_free(card);
return err;
}
return 0;
}
static void vxpocket_detach(struct pcmcia_device *link)
+23 -17
View File
@@ -116,6 +116,7 @@ static const struct snd_soc_dapm_route rt5682_map[] = {
static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
@@ -129,7 +130,7 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets,
ret = snd_soc_dapm_new_controls(dapm, rt5682_widgets,
ARRAY_SIZE(rt5682_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
@@ -166,7 +167,7 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682_map, ARRAY_SIZE(rt5682_map));
return snd_soc_dapm_add_routes(dapm, rt5682_map, ARRAY_SIZE(rt5682_map));
}
static int acp_card_hs_startup(struct snd_pcm_substream *substream)
@@ -357,6 +358,7 @@ static const struct snd_soc_dapm_route rt5682s_map[] = {
static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
@@ -372,7 +374,7 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
}
ret = snd_soc_dapm_new_controls(&card->dapm, rt5682s_widgets,
ret = snd_soc_dapm_new_controls(dapm, rt5682s_widgets,
ARRAY_SIZE(rt5682s_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
@@ -409,7 +411,7 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682s_map, ARRAY_SIZE(rt5682s_map));
return snd_soc_dapm_add_routes(dapm, rt5682s_map, ARRAY_SIZE(rt5682s_map));
}
static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream,
@@ -581,13 +583,14 @@ static struct snd_soc_codec_conf rt1019_conf[] = {
static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
int ret;
if (drvdata->amp_codec_id != RT1019)
return -EINVAL;
ret = snd_soc_dapm_new_controls(&card->dapm, rt1019_widgets,
ret = snd_soc_dapm_new_controls(dapm, rt1019_widgets,
ARRAY_SIZE(rt1019_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
@@ -601,7 +604,7 @@ static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr,
return snd_soc_dapm_add_routes(dapm, rt1019_map_lr,
ARRAY_SIZE(rt1019_map_lr));
}
@@ -746,13 +749,14 @@ static const struct snd_soc_dapm_route max98360a_map[] = {
static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
int ret;
if (drvdata->amp_codec_id != MAX98360A)
return -EINVAL;
ret = snd_soc_dapm_new_controls(&card->dapm, max98360a_widgets,
ret = snd_soc_dapm_new_controls(dapm, max98360a_widgets,
ARRAY_SIZE(max98360a_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
@@ -766,7 +770,7 @@ static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map,
return snd_soc_dapm_add_routes(dapm, max98360a_map,
ARRAY_SIZE(max98360a_map));
}
@@ -882,13 +886,14 @@ static int acp_card_max98388_startup(struct snd_pcm_substream *substream)
static int acp_card_max98388_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
int ret;
if (drvdata->amp_codec_id != MAX98388)
return -EINVAL;
ret = snd_soc_dapm_new_controls(&card->dapm, max98388_widgets,
ret = snd_soc_dapm_new_controls(dapm, max98388_widgets,
ARRAY_SIZE(max98388_widgets));
if (ret) {
@@ -904,7 +909,7 @@ static int acp_card_max98388_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
return snd_soc_dapm_add_routes(&rtd->card->dapm, max98388_map,
return snd_soc_dapm_add_routes(dapm, max98388_map,
ARRAY_SIZE(max98388_map));
}
@@ -966,6 +971,7 @@ static const struct snd_soc_dapm_route nau8825_map[] = {
static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
@@ -976,7 +982,7 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != NAU8825)
return -EINVAL;
ret = snd_soc_dapm_new_controls(&card->dapm, nau8825_widgets,
ret = snd_soc_dapm_new_controls(dapm, nau8825_widgets,
ARRAY_SIZE(nau8825_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
@@ -1013,7 +1019,7 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8825_map, ARRAY_SIZE(nau8825_map));
return snd_soc_dapm_add_routes(dapm, nau8825_map, ARRAY_SIZE(nau8825_map));
}
static int acp_nau8825_hw_params(struct snd_pcm_substream *substream,
@@ -1102,8 +1108,7 @@ static const struct snd_soc_ops acp_card_nau8825_ops = {
static int platform_clock_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
struct snd_soc_dai *codec_dai;
int ret = 0;
@@ -1181,13 +1186,14 @@ static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
static int acp_8821_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
int ret;
dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
ret = snd_soc_dapm_new_controls(&card->dapm, nau8821_widgets,
ret = snd_soc_dapm_new_controls(dapm, nau8821_widgets,
ARRAY_SIZE(nau8821_widgets));
if (ret) {
dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
@@ -1221,7 +1227,7 @@ static int acp_8821_init(struct snd_soc_pcm_runtime *rtd)
nau8821_enable_jack_detect(component, &nau8821_jack);
return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8821_audio_route,
return snd_soc_dapm_add_routes(dapm, nau8821_audio_route,
ARRAY_SIZE(nau8821_audio_route));
}
@@ -1340,7 +1346,7 @@ static int acp_rtk_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
struct snd_soc_component *component = dapm->component;
struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
struct acp_card_drvdata *drvdata = card->drvdata;
int ret = 0;
+19 -4
View File
@@ -360,20 +360,25 @@ static int soc_card_dai_links_create(struct snd_soc_card *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_aux_dev *soc_aux;
struct snd_soc_codec_conf *codec_conf;
struct snd_soc_dai_link *dai_links;
int num_devs = 0;
int num_ends = 0;
int num_aux = 0;
int num_confs;
int num_links;
int be_id = 0;
int ret;
ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends);
ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux);
if (ret < 0) {
dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
return ret;
}
num_confs = num_ends;
/* 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)
@@ -384,7 +389,11 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
if (!soc_ends)
return -ENOMEM;
ret = asoc_sdw_parse_sdw_endpoints(card, soc_dais, soc_ends, &num_devs);
soc_aux = devm_kcalloc(dev, num_aux, sizeof(*soc_aux), GFP_KERNEL);
if (!soc_aux)
return -ENOMEM;
ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, &num_confs);
if (ret < 0)
return ret;
@@ -396,7 +405,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num);
codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL);
if (!codec_conf)
return -ENOMEM;
@@ -407,9 +416,11 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
return -ENOMEM;
card->codec_conf = codec_conf;
card->num_configs = num_devs;
card->num_configs = num_confs;
card->dai_link = dai_links;
card->num_links = num_links;
card->aux_dev = soc_aux;
card->num_aux_devs = num_aux;
/* SDW */
if (sdw_be_num) {
@@ -463,6 +474,10 @@ static int mc_probe(struct platform_device *pdev)
card->late_probe = asoc_sdw_card_late_probe;
snd_soc_card_set_drvdata(card, ctx);
if (mach->mach_params.subsystem_id_set)
snd_soc_card_set_pci_ssid(card,
mach->mach_params.subsystem_vendor,
mach->mach_params.subsystem_device);
dmi_check_system(soc_sdw_quirk_table);
+10 -2
View File
@@ -272,15 +272,17 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
struct asoc_sdw_endpoint *sof_ends __free(kfree) = NULL;
struct asoc_sdw_dailink *sof_dais __free(kfree) = NULL;
struct snd_soc_aux_dev *sof_aux;
struct snd_soc_codec_conf *codec_conf;
struct snd_soc_dai_link *dai_links;
int num_devs = 0;
int num_ends = 0;
int num_aux = 0;
int num_links;
int be_id = 0;
int ret;
ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends);
ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux);
if (ret < 0) {
dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
return ret;
@@ -296,7 +298,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
if (!sof_ends)
return -ENOMEM;
ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs);
sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL);
if (!sof_aux)
return -ENOMEM;
ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_devs);
if (ret < 0)
return ret;
@@ -322,6 +328,8 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
card->num_configs = num_devs;
card->dai_link = dai_links;
card->num_links = num_links;
card->aux_dev = sof_aux;
card->num_aux_devs = num_aux;
/* SDW */
if (sdw_be_num) {

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