mirror of https://github.com/torvalds/linux.git
sound updates for 6.19-rc1
The majority of changes at this time were about ASoC with a lot of
code refactoring works. From the functionality POV, there aren't much
to see, but we have a wide range of device-specific fixes and updates.
Here are some highlights:
- Continued ASoC API clean works, spanned over many files
- Added a SoundWire SCDA generic class driver with regmap support
- Enhancements and fixes for Cirrus, Intel, Maxim and Qualcomm.
- Support for ASoC Allwinner A523, Mediatek MT8189, Qualcomm QCM2290,
QRB2210 and SM6115, SpacemiT K1, and TI TAS2568, TAS5802, TAS5806,
TAS5815, TAS5828 and TAS5830
- Usual HD-audio and USB-audio quirks and fixups
- Support for Onkyo SE-300PCIE, TASCAM IF-FW/DM MkII
Some gpiolib changes for shared GPIOs are included along with this PR
for covering ASoC drivers changes.
-----BEGIN PGP SIGNATURE-----
iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmkwQ2UOHHRpd2FpQHN1
c2UuZGUACgkQLtJE4w1nLE8tIRAAjCHdIlMejNTCzGRlhsRSQVD6bo1wASXcjfJ6
COH84akbnA0oT5z7H7JnzTOmfjzxLJpwC8j6IpZ/9CQazanT5IIVE41FZquXZ1JB
RhQVzuGw9Pl4MaYVdFuRqIXjiP+msY1jpbo9/QXQo8D/B41wpmVTgzkFVW2rxPMy
0aBOu4Wpu+11aBpNBy6dXDiKQ5kDqn7zOLoFGgcf5wlFIvOGZJ0Wg/i0kvCjl+ia
xYiP+/F6xKOyTY1c98iqExbKzSSy4ddGFUwrkevm6bWpu8hkXiL1O0zMWOe769x6
0wy0b5zvsbtOQOxbtK5+8gdjJw7ycgDa441hDtsaXBBROYZEV3D6+XZJCfq8Tz8F
+vLH5lfZeLg+59eqt3GOMGlwBfuhH91qzukIYG3q9EQGOkNkZ19ySJnFMLom68Ei
TCfNzh/ggSGXA9qAmfBcPoizgC/j9o+v4kbLRQteuRRWxES1FxqeN9Ba3d5JcHT3
BQpz1bhUli73477D6voPcwXLiQlM+Alv4QUKTFr2nUnWUQKwMvkZFwiv2jTqVdDf
f71Usv7xdyM7XijgmXuLg+3n0UvCwUPBB+bv3a1Bu7G4iTB1deNKU8t9k+sBJpcX
aRs5ych3MiU/zG+KRMB5FEx31KzpKu+Kk9NQ207/1HLaNhTgD3cg2wS3T3qdRUPv
Yf6wFHs=
=1JUI
-----END PGP SIGNATURE-----
Merge tag 'sound-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"The majority of changes at this time were about ASoC with a lot of
code refactoring works. From the functionality POV, there isn't much
to see, but we have a wide range of device-specific fixes and updates.
Here are some highlights:
- Continued ASoC API cleanup work, spanned over many files
- Added a SoundWire SCDA generic class driver with regmap support
- Enhancements and fixes for Cirrus, Intel, Maxim and Qualcomm.
- Support for ASoC Allwinner A523, Mediatek MT8189, Qualcomm QCM2290,
QRB2210 and SM6115, SpacemiT K1, and TI TAS2568, TAS5802, TAS5806,
TAS5815, TAS5828 and TAS5830
- Usual HD-audio and USB-audio quirks and fixups
- Support for Onkyo SE-300PCIE, TASCAM IF-FW/DM MkII
Some gpiolib changes for shared GPIOs are included along with this PR
for covering ASoC drivers changes"
* tag 'sound-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (739 commits)
ALSA: hda/realtek: Add PCI SSIDs to HP ProBook quirks
ALSA: usb-audio: Simplify with usb_endpoint_max_periodic_payload()
ALSA: hda/realtek: fix mute/micmute LEDs don't work for more HP laptops
ALSA: rawmidi: Fix inconsistent indenting warning reported by smatch
ALSA: dice: fix buffer overflow in detect_stream_formats()
ASoC: codecs: Modify awinic amplifier dsp read and write functions
ASoC: SDCA: Fixup some more Kconfig issues
ASoC: cs35l56: Log a message if firmware is missing
ASoC: nau8325: Delete a stray tab
firmware: cs_dsp: Add test cases for client_ops == NULL
firmware: cs_dsp: Don't require client to provide a struct cs_dsp_client_ops
ASoC: fsl_micfil: Set channel range control
ASoC: fsl_micfil: Add default quality for different platforms
ASoC: intel: sof_sdw: Add codec_info for cs42l45
ASoC: sdw_utils: Add cs42l45 support functions
ASoC: intel: sof_sdw: Add ability to have auxiliary devices
ASoC: sdw_utils: Move codec_name to dai info
ASoC: sdw_utils: Add codec_conf for every DAI
ASoC: SDCA: Add terminal type into input/output widget name
ASoC: SDCA: Align mute controls to ALSA expectations
...
This commit is contained in:
commit
2aa680df68
|
|
@ -1,60 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/adi,max98363.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices MAX98363 SoundWire Amplifier
|
||||
|
||||
maintainers:
|
||||
- Ryan Lee <ryans.lee@analog.com>
|
||||
|
||||
description:
|
||||
The MAX98363 is a SoundWire input Class D mono amplifier that
|
||||
supports MIPI SoundWire v1.2-compatible digital interface for
|
||||
audio and control data.
|
||||
SoundWire peripheral device ID of MAX98363 is 0x3*019f836300
|
||||
where * is the peripheral device unique ID decoded from pin.
|
||||
It supports up to 10 peripheral devices(0x0 to 0x9).
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sdw3019f836300
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#sound-dai-cells"
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
soundwire@3250000 {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x3250000 0x2000>;
|
||||
|
||||
speaker@0,0 {
|
||||
compatible = "sdw3019f836300";
|
||||
reg = <0 0>;
|
||||
#sound-dai-cells = <0>;
|
||||
sound-name-prefix = "Speaker Left";
|
||||
};
|
||||
|
||||
speaker@0,1 {
|
||||
compatible = "sdw3019f836300";
|
||||
reg = <0 1>;
|
||||
#sound-dai-cells = <0>;
|
||||
sound-name-prefix = "Speaker Right";
|
||||
};
|
||||
};
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
Analog Devices SSM2602, SSM2603 and SSM2604 I2S audio CODEC devices
|
||||
|
||||
SSM2602 support both I2C and SPI as the configuration interface,
|
||||
the selection is made by the MODE strap-in pin.
|
||||
SSM2603 and SSM2604 only support I2C as the configuration interface.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : One of "adi,ssm2602", "adi,ssm2603" or "adi,ssm2604"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
ssm2602: ssm2602@1a {
|
||||
compatible = "adi,ssm2602";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/adi,ssm3515.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices SSM3515 Audio Amplifier
|
||||
|
||||
maintainers:
|
||||
- Martin Povišer <povik+lin@cutebit.org>
|
||||
|
||||
description: |
|
||||
SSM3515 is a mono Class-D audio amplifier with digital input.
|
||||
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/SSM3515.pdf
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ssm3515
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
codec@14 {
|
||||
compatible = "adi,ssm3515";
|
||||
reg = <0x14>;
|
||||
#sound-dai-cells = <0>;
|
||||
sound-name-prefix = "Left Tweeter";
|
||||
};
|
||||
};
|
||||
|
|
@ -33,7 +33,9 @@ properties:
|
|||
- const: allwinner,sun50i-h6-i2s
|
||||
- const: allwinner,sun50i-r329-i2s
|
||||
- items:
|
||||
- const: allwinner,sun20i-d1-i2s
|
||||
- enum:
|
||||
- allwinner,sun20i-d1-i2s
|
||||
- allwinner,sun55i-a523-i2s
|
||||
- const: allwinner,sun50i-r329-i2s
|
||||
|
||||
reg:
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ properties:
|
|||
- const: allwinner,sun8i-h3-spdif
|
||||
- const: allwinner,sun50i-h6-spdif
|
||||
- const: allwinner,sun50i-h616-spdif
|
||||
- const: allwinner,sun55i-a523-spdif
|
||||
- items:
|
||||
- const: allwinner,sun8i-a83t-spdif
|
||||
- const: allwinner,sun8i-h3-spdif
|
||||
|
|
@ -37,14 +38,12 @@ properties:
|
|||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Bus Clock
|
||||
- description: Module Clock
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: spdif
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
# Even though it only applies to subschemas under the conditionals,
|
||||
# not listing them here will trigger a warning because of the
|
||||
|
|
@ -65,6 +64,7 @@ allOf:
|
|||
- allwinner,sun8i-h3-spdif
|
||||
- allwinner,sun50i-h6-spdif
|
||||
- allwinner,sun50i-h616-spdif
|
||||
- allwinner,sun55i-a523-spdif
|
||||
|
||||
then:
|
||||
required:
|
||||
|
|
@ -98,6 +98,38 @@ allOf:
|
|||
- const: rx
|
||||
- const: tx
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun55i-a523-spdif
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: Bus Clock
|
||||
- description: TX Clock
|
||||
- description: RX Clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: tx
|
||||
- const: rx
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: Bus Clock
|
||||
- description: Module Clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: spdif
|
||||
|
||||
required:
|
||||
- "#sound-dai-cells"
|
||||
- compatible
|
||||
|
|
|
|||
|
|
@ -25,6 +25,16 @@ properties:
|
|||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description:
|
||||
Master clock connected to the MCLK pin if MCLK is an input (i.e. no
|
||||
crystal used).
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: mclk
|
||||
|
||||
spi-cpha: true
|
||||
|
||||
spi-cpol: true
|
||||
|
|
|
|||
|
|
@ -15,10 +15,15 @@ description:
|
|||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- cirrus,cs4282
|
||||
- cirrus,cs4302
|
||||
- cirrus,cs4304
|
||||
- cirrus,cs4308
|
||||
- cirrus,cs5302
|
||||
- cirrus,cs5304
|
||||
- cirrus,cs5308
|
||||
|
|
@ -26,6 +31,9 @@ properties:
|
|||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 24000000
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
CS4265 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "cirrus,cs4265"
|
||||
|
||||
- reg : the I2C address of the device for I2C. The I2C address depends on
|
||||
the state of the AD0 pin. If AD0 is high, the i2c address is 0x4f.
|
||||
If it is low, the i2c address is 0x4e.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios : a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the codec starts.
|
||||
|
||||
Examples:
|
||||
|
||||
codec_ad0_high: cs4265@4f { /* AD0 Pin is high */
|
||||
compatible = "cirrus,cs4265";
|
||||
reg = <0x4f>;
|
||||
};
|
||||
|
||||
|
||||
codec_ad0_low: cs4265@4e { /* AD0 Pin is low */
|
||||
compatible = "cirrus,cs4265";
|
||||
reg = <0x4e>;
|
||||
};
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
Cirrus Logic CS4341 audio DAC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
- compatible: "cirrus,cs4341a"
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
For required properties on I2C-bus, please consult
|
||||
dtschema schemas/i2c/i2c-controller.yaml
|
||||
For required properties on SPI-bus, please consult
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
codec: cs4341@0 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "cirrus,cs4341a";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <6000000>;
|
||||
};
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
CS4349 audio CODEC
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "cirrus,cs4349"
|
||||
|
||||
- reg : the I2C address of the device for I2C
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios : a GPIO spec for the reset pin.
|
||||
|
||||
Example:
|
||||
|
||||
codec: cs4349@48 {
|
||||
compatible = "cirrus,cs4349";
|
||||
reg = <0x48>;
|
||||
reset-gpios = <&gpio 54 0>;
|
||||
};
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
* Dialog DA9055 Audio CODEC
|
||||
|
||||
DA9055 provides Audio CODEC support (I2C only).
|
||||
|
||||
The Audio CODEC device in DA9055 has its own I2C address which is configurable,
|
||||
so the device is instantiated separately from the PMIC (MFD) device.
|
||||
|
||||
For details on accompanying PMIC I2C device, see the following:
|
||||
Documentation/devicetree/bindings/mfd/da9055.txt
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "dlg,da9055-codec"
|
||||
- reg: Specifies the I2C slave address
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
codec: da9055-codec@1a {
|
||||
compatible = "dlg,da9055-codec";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
|
@ -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";
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/mediatek,mt8189-nau8825.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek MT8189 ASoC sound card
|
||||
|
||||
maintainers:
|
||||
- Darren Ye <darren.ye@mediatek.com>
|
||||
- Cyril Chao <cyril.chao@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: sound-card-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8189-nau8825
|
||||
- mediatek,mt8189-rt5650
|
||||
- mediatek,mt8189-rt5682s
|
||||
- mediatek,mt8189-rt5682i
|
||||
- mediatek,mt8189-es8326
|
||||
|
||||
mediatek,platform:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: The phandle of MT8189 ASoC platform.
|
||||
|
||||
patternProperties:
|
||||
"^dai-link-[0-9]+$":
|
||||
type: object
|
||||
description:
|
||||
Container for dai-link level properties and CODEC sub-nodes.
|
||||
|
||||
properties:
|
||||
link-name:
|
||||
description:
|
||||
This property corresponds to the name of the BE dai-link to which
|
||||
we are going to update parameters in this node.
|
||||
enum:
|
||||
- TDM_DPTX_BE
|
||||
- I2SOUT0_BE
|
||||
- I2SIN0_BE
|
||||
- I2SOUT1_BE
|
||||
|
||||
codec:
|
||||
description: Holds subnode which indicates codec dai.
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
sound-dai:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
required:
|
||||
- sound-dai
|
||||
|
||||
dai-format:
|
||||
description: audio format.
|
||||
enum:
|
||||
- i2s
|
||||
- right_j
|
||||
- left_j
|
||||
- dsp_a
|
||||
- dsp_b
|
||||
|
||||
mediatek,clk-provider:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: Indicates dai-link clock master.
|
||||
enum:
|
||||
- cpu
|
||||
- codec
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- link-name
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- mediatek,platform
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sound {
|
||||
compatible = "mediatek,mt8189-nau8825";
|
||||
model = "mt8189_rt9123_8825";
|
||||
mediatek,platform = <&afe>;
|
||||
dai-link-0 {
|
||||
link-name = "I2SOUT1_BE";
|
||||
dai-format = "i2s";
|
||||
mediatek,clk-provider = "cpu";
|
||||
codec {
|
||||
sound-dai = <&nau8825>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/nuvoton,nau8540.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Nuvoton Technology Corporation NAU85L40 Audio CODEC
|
||||
|
||||
maintainers:
|
||||
- John Hsu <KCHSU0@nuvoton.com>
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nuvoton,nau8540
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec@1c {
|
||||
compatible = "nuvoton,nau8540";
|
||||
reg = <0x1c>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/nuvoton,nau8810.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NAU8810/NAU8812/NAU8814 audio CODEC
|
||||
|
||||
maintainers:
|
||||
- David Lin <CTLIN0@nuvoton.com>
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nuvoton,nau8810
|
||||
- nuvoton,nau8812
|
||||
- nuvoton,nau8814
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
codec@1a {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "nuvoton,nau8810";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -67,12 +67,12 @@ properties:
|
|||
$ref: audio-graph-port.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
if:
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: nvidia,tegra210-admaif
|
||||
|
||||
then:
|
||||
properties:
|
||||
dmas:
|
||||
|
|
@ -92,7 +92,12 @@ then:
|
|||
interconnect-names: false
|
||||
iommus: false
|
||||
|
||||
else:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: nvidia,tegra186-admaif
|
||||
then:
|
||||
properties:
|
||||
dmas:
|
||||
description:
|
||||
|
|
@ -108,6 +113,27 @@ else:
|
|||
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
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/nxp,tfa9879.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP TFA9879 class-D audio amplifier
|
||||
|
||||
maintainers:
|
||||
- Peter Rosin <peda@axentia.se>
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nxp,tfa9879
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#sound-dai-cells'
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
amplifier@6c {
|
||||
compatible = "nxp,tfa9879";
|
||||
reg = <0x6c>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_i2c1>;
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/nxp,uda1342.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP uda1342 audio CODECs
|
||||
|
||||
maintainers:
|
||||
- Binbin Zhou <zhoubinbin@loongson.cn>
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nxp,uda1342
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#sound-dai-cells'
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec@1a {
|
||||
compatible = "nxp,uda1342";
|
||||
reg = <0x1a>;
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
Texas Instruments pcm1789 DT bindings
|
||||
|
||||
PCM1789 is a simple audio codec that can be connected via
|
||||
I2C or SPI. Currently, only I2C bus is supported.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "ti,pcm1789"
|
||||
|
||||
Required properties on I2C:
|
||||
|
||||
- reg: the I2C address
|
||||
- reset-gpios: GPIO to control the RESET pin
|
||||
|
||||
Examples:
|
||||
|
||||
audio-codec@4c {
|
||||
compatible = "ti,pcm1789";
|
||||
reg = <0x4c>;
|
||||
reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>;
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
Texas Instruments pcm179x DT bindings
|
||||
|
||||
This driver supports both the I2C and SPI bus.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "ti,pcm1792a"
|
||||
|
||||
For required properties on SPI, please consult
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Required properties on I2C:
|
||||
|
||||
- reg: the I2C address
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
codec_spi: 1792a@0 {
|
||||
compatible = "ti,pcm1792a";
|
||||
spi-max-frequency = <600000>;
|
||||
};
|
||||
|
||||
codec_i2c: 1792a@4c {
|
||||
compatible = "ti,pcm1792a";
|
||||
reg = <0x4c>;
|
||||
};
|
||||
|
|
@ -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 = <®_3v3_analog>;
|
||||
dvdd-supply = <®_3v3>;
|
||||
iovdd-supply = <®_1v8>;
|
||||
};
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
PCM5102a audio CODECs
|
||||
|
||||
These devices does not use I2C or SPI.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : set as "ti,pcm5102a"
|
||||
|
||||
Examples:
|
||||
|
||||
pcm5102a: pcm5102a {
|
||||
compatible = "ti,pcm5102a";
|
||||
};
|
||||
|
|
@ -14,12 +14,14 @@ properties:
|
|||
oneOf:
|
||||
- enum:
|
||||
- qcom,sc7280-lpass-rx-macro
|
||||
- qcom,sm6115-lpass-rx-macro
|
||||
- qcom,sm8250-lpass-rx-macro
|
||||
- qcom,sm8450-lpass-rx-macro
|
||||
- qcom,sm8550-lpass-rx-macro
|
||||
- qcom,sc8280xp-lpass-rx-macro
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,kaanapali-lpass-rx-macro
|
||||
- qcom,sm8650-lpass-rx-macro
|
||||
- qcom,sm8750-lpass-rx-macro
|
||||
- qcom,x1e80100-lpass-rx-macro
|
||||
|
|
@ -80,6 +82,23 @@ allOf:
|
|||
- const: npl
|
||||
- const: fsgen
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sm6115-lpass-rx-macro
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
clock-names:
|
||||
items:
|
||||
- const: mclk
|
||||
- const: npl
|
||||
- const: dcodec
|
||||
- const: fsgen
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ properties:
|
|||
- qcom,sc8280xp-lpass-tx-macro
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,kaanapali-lpass-tx-macro
|
||||
- qcom,sm8650-lpass-tx-macro
|
||||
- qcom,sm8750-lpass-tx-macro
|
||||
- qcom,x1e80100-lpass-tx-macro
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ properties:
|
|||
oneOf:
|
||||
- enum:
|
||||
- qcom,sc7280-lpass-va-macro
|
||||
- qcom,sm6115-lpass-va-macro
|
||||
- qcom,sm8250-lpass-va-macro
|
||||
- qcom,sm8450-lpass-va-macro
|
||||
- qcom,sm8550-lpass-va-macro
|
||||
|
|
@ -21,6 +22,7 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- qcom,glymur-lpass-va-macro
|
||||
- qcom,kaanapali-lpass-va-macro
|
||||
- qcom,sm8650-lpass-va-macro
|
||||
- qcom,sm8750-lpass-va-macro
|
||||
- qcom,x1e80100-lpass-va-macro
|
||||
|
|
@ -41,11 +43,7 @@ properties:
|
|||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: mclk
|
||||
- const: macro
|
||||
- const: dcodec
|
||||
- const: npl
|
||||
maxItems: 4
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
|
@ -90,16 +88,33 @@ allOf:
|
|||
clocks:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
maxItems: 1
|
||||
items:
|
||||
- const: mclk
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
items:
|
||||
- const: mclk
|
||||
- const: macro
|
||||
- const: dcodec
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: qcom,sm6115-lpass-va-macro
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: mclk
|
||||
- const: dcodec
|
||||
- const: npl
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
|
@ -111,8 +126,10 @@ allOf:
|
|||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
items:
|
||||
- const: mclk
|
||||
- const: macro
|
||||
- const: dcodec
|
||||
|
||||
- if:
|
||||
properties:
|
||||
|
|
@ -127,8 +144,11 @@ allOf:
|
|||
minItems: 4
|
||||
maxItems: 4
|
||||
clock-names:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: mclk
|
||||
- const: macro
|
||||
- const: dcodec
|
||||
- const: npl
|
||||
|
||||
- if:
|
||||
properties:
|
||||
|
|
@ -142,8 +162,10 @@ allOf:
|
|||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
items:
|
||||
- const: mclk
|
||||
- const: macro
|
||||
- const: dcodec
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- qcom,glymur-lpass-wsa-macro
|
||||
- qcom,kaanapali-lpass-wsa-macro
|
||||
- qcom,sm8650-lpass-wsa-macro
|
||||
- qcom,sm8750-lpass-wsa-macro
|
||||
- qcom,x1e80100-lpass-wsa-macro
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ properties:
|
|||
- const: qcom,sdm845-sndcard
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,kaanapali-sndcard
|
||||
- qcom,sm8550-sndcard
|
||||
- qcom,sm8650-sndcard
|
||||
- qcom,sm8750-sndcard
|
||||
|
|
@ -38,6 +39,7 @@ properties:
|
|||
- qcom,qcs8275-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
|
||||
additionalProperties: true
|
||||
description: |
|
||||
|
|
|
|||
|
|
@ -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 = <®_3v3_analog>;
|
||||
dvdd-supply = <®_3v3>;
|
||||
iovdd-supply = <®_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:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/trivial-codec.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Trivial Audio Codec
|
||||
|
||||
maintainers:
|
||||
- Rob Herring <robh@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
# Analog Devices SSM2602 I2S audio CODEC devices
|
||||
- adi,ssm2602
|
||||
- adi,ssm2603
|
||||
- adi,ssm2604
|
||||
- adi,ssm3515
|
||||
# Cirrus Logic CS4265 audio DAC
|
||||
- cirrus,cs4265
|
||||
- cirrus,cs4341a
|
||||
- cirrus,cs4349
|
||||
- dlg,da9055-codec
|
||||
# Nuvoton Technology Corporation NAU85L40 Audio CODEC
|
||||
- nuvoton,nau8540
|
||||
- nuvoton,nau8810
|
||||
- nuvoton,nau8812
|
||||
- nuvoton,nau8814
|
||||
# NXP TFA9879 class-D audio amplifier
|
||||
- nxp,tfa9879
|
||||
- nxp,uda1342
|
||||
- sdw3019f836300
|
||||
- ti,pcm1789
|
||||
- ti,pcm1792a
|
||||
- ti,pcm5102a
|
||||
- wlf,wm8510
|
||||
- wlf,wm8523
|
||||
- wlf,wm8580
|
||||
- wlf,wm8581
|
||||
- wlf,wm8711
|
||||
- wlf,wm8728
|
||||
- wlf,wm8737
|
||||
- wlf,wm8750
|
||||
- wlf,wm8753
|
||||
- wlf,wm8770
|
||||
- wlf,wm8776
|
||||
- wlf,wm8961
|
||||
- wlf,wm8974
|
||||
- wlf,wm8987
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8523";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8510.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8510 audio CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: wlf,wm8510
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8510";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8523.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8523 audio CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: wlf,wm8523
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8523";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8580.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8580 and WM8581 audio CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- wlf,wm8580
|
||||
- wlf,wm8581
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8580";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8711.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8711 audio CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: wlf,wm8711
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8711";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8728.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8728 audio CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: wlf,wm8728
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8728";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8737.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8737 audio CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: wlf,wm8737
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8737";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8750.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8750 and WM8987 audio CODECs
|
||||
|
||||
description: |
|
||||
These devices support both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
maintainers:
|
||||
- Mark Brown <broonie@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- wlf,wm8750
|
||||
- wlf,wm8987
|
||||
|
||||
reg:
|
||||
description:
|
||||
The I2C address of the device for I2C, the chip select number for SPI
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8750";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8753.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8753 audio CODEC
|
||||
|
||||
description: |
|
||||
Pins on the device (for linking into audio routes):
|
||||
* LOUT1
|
||||
* LOUT2
|
||||
* ROUT1
|
||||
* ROUT2
|
||||
* MONO1
|
||||
* MONO2
|
||||
* OUT3
|
||||
* OUT4
|
||||
* LINE1
|
||||
* LINE2
|
||||
* RXP
|
||||
* RXN
|
||||
* ACIN
|
||||
* ACOP
|
||||
* MIC1N
|
||||
* MIC1
|
||||
* MIC2N
|
||||
* MIC2
|
||||
* Mic Bias
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: wlf,wm8753
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8753";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8776.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8776 audio CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: wlf,wm8776
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8776";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8961.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Wolfson WM8961 Ultra-Low Power Stereo CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: wlf,wm8961
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#sound-dai-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#sound-dai-cells'
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
wm8961: codec@4a {
|
||||
compatible = "wlf,wm8961";
|
||||
reg = <0x4a>;
|
||||
#sound-dai-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/wlf,wm8974.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: WM8974 audio CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: wlf,wm8974
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
codec@1a {
|
||||
compatible = "wlf,wm8974";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
WM8770 audio CODEC
|
||||
|
||||
This device supports SPI.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8770"
|
||||
|
||||
- reg : the chip select number.
|
||||
|
||||
Example:
|
||||
|
||||
wm8770: codec@1 {
|
||||
compatible = "wlf,wm8770";
|
||||
reg = <1>;
|
||||
};
|
||||
|
|
@ -1758,6 +1758,7 @@ S: Supported
|
|||
W: http://wiki.analog.com/
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/sound/adi,*
|
||||
F: Documentation/devicetree/bindings/sound/trivial-codec.yaml
|
||||
F: sound/soc/codecs/ad1*
|
||||
F: sound/soc/codecs/ad7*
|
||||
F: sound/soc/codecs/adau*
|
||||
|
|
@ -2421,9 +2422,9 @@ M: Martin Povišer <povik+lin@cutebit.org>
|
|||
L: asahi@lists.linux.dev
|
||||
L: linux-sound@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/adi,ssm3515.yaml
|
||||
F: Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml
|
||||
F: Documentation/devicetree/bindings/sound/apple,*
|
||||
F: Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml
|
||||
F: Documentation/devicetree/bindings/sound/trivial-codec.yaml
|
||||
F: sound/soc/apple/*
|
||||
F: sound/soc/codecs/cs42l83-i2c.c
|
||||
F: sound/soc/codecs/cs42l84.*
|
||||
|
|
@ -18749,7 +18750,7 @@ NXP TFA9879 DRIVER
|
|||
M: Peter Rosin <peda@axentia.se>
|
||||
L: linux-sound@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/nxp,tfa9879.yaml
|
||||
F: Documentation/devicetree/bindings/sound/trivial-codec.yaml
|
||||
F: sound/soc/codecs/tfa9879*
|
||||
|
||||
NXP-NCI NFC DRIVER
|
||||
|
|
@ -27799,6 +27800,7 @@ F: Documentation/devicetree/bindings/extcon/wlf,arizona.yaml
|
|||
F: Documentation/devicetree/bindings/mfd/wlf,arizona.yaml
|
||||
F: Documentation/devicetree/bindings/mfd/wm831x.txt
|
||||
F: Documentation/devicetree/bindings/regulator/wlf,arizona.yaml
|
||||
F: Documentation/devicetree/bindings/sound/trivial-codec.yaml
|
||||
F: Documentation/devicetree/bindings/sound/wlf,*.yaml
|
||||
F: Documentation/devicetree/bindings/sound/wm*
|
||||
F: Documentation/hwmon/wm83??.rst
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
struct regmap_mbq_context {
|
||||
struct device *dev;
|
||||
struct sdw_slave *sdw;
|
||||
|
||||
struct regmap_sdw_mbq_cfg cfg;
|
||||
|
||||
|
|
@ -46,7 +47,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 +97,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 +156,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 +207,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 +218,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 +229,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 +242,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, ®map_sdw_mbq, ctx,
|
||||
return __regmap_init(dev, ®map_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 +264,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, ®map_sdw_mbq, ctx,
|
||||
return __devm_regmap_init(dev, ®map_sdw_mbq, ctx,
|
||||
config, lock_key, lock_name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
|
||||
|
|
|
|||
|
|
@ -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,33 @@ 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 __free(kfree) = NULL;
|
||||
|
||||
scoped_guard(mutex, &dsp->pwr_lock) {
|
||||
if (!*pstr)
|
||||
return 0;
|
||||
|
||||
str = kasprintf(GFP_KERNEL, "%s\n", *pstr);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, str, strlen(str));
|
||||
}
|
||||
}
|
||||
|
||||
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 +404,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 +438,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, ®, 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 +989,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 +1039,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 +1057,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 +1446,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 __free(kfree) = NULL;
|
||||
size_t buf_len = 0;
|
||||
size_t region_len;
|
||||
unsigned int reg;
|
||||
int regions = 0;
|
||||
int ret, offset, type;
|
||||
|
|
@ -1605,23 +1568,23 @@ 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);
|
||||
region_len = le32_to_cpu(region->len);
|
||||
if (region_len > buf_len) {
|
||||
buf_len = round_up(region_len, PAGE_SIZE);
|
||||
kfree(buf);
|
||||
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
|
||||
if (!buf) {
|
||||
cs_dsp_err(dsp, "Out of memory\n");
|
||||
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,8 +1601,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
|
|||
|
||||
ret = 0;
|
||||
out_fw:
|
||||
cs_dsp_buf_free(&buf_list);
|
||||
|
||||
if (ret == -EOVERFLOW)
|
||||
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
|
||||
|
||||
|
|
@ -2171,7 +2132,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 __free(kfree) = NULL;
|
||||
size_t buf_len = 0;
|
||||
size_t region_len;
|
||||
|
||||
if (!firmware)
|
||||
return 0;
|
||||
|
|
@ -2313,20 +2276,22 @@ 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);
|
||||
region_len = le32_to_cpu(blk->len);
|
||||
if (region_len > buf_len) {
|
||||
buf_len = round_up(region_len, PAGE_SIZE);
|
||||
kfree(buf);
|
||||
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
|
||||
if (!buf) {
|
||||
cs_dsp_err(dsp, "Out of memory\n");
|
||||
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,8 +2311,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
|
|||
|
||||
ret = 0;
|
||||
out_fw:
|
||||
cs_dsp_buf_free(&buf_list);
|
||||
|
||||
if (ret == -EOVERFLOW)
|
||||
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
|
||||
|
||||
|
|
@ -2366,6 +2329,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 +2345,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);
|
||||
|
|
|
|||
|
|
@ -600,6 +600,7 @@ KUNIT_ARRAY_PARAM(cs_dsp_callbacks_ops,
|
|||
|
||||
static const struct cs_dsp_callbacks_test_param cs_dsp_no_callbacks_cases[] = {
|
||||
{ .ops = &cs_dsp_callback_test_empty_client_ops, .case_name = "empty ops" },
|
||||
{ .ops = NULL, .case_name = "NULL ops" },
|
||||
};
|
||||
|
||||
KUNIT_ARRAY_PARAM(cs_dsp_no_callbacks,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
config GPIOLIB_LEGACY
|
||||
def_bool y
|
||||
|
||||
config HAVE_SHARED_GPIOS
|
||||
bool
|
||||
|
||||
menuconfig GPIOLIB
|
||||
bool "GPIO Support"
|
||||
help
|
||||
|
|
@ -50,6 +53,11 @@ config OF_GPIO_MM_GPIOCHIP
|
|||
this symbol, but new drivers should use the generic gpio-regmap
|
||||
infrastructure instead.
|
||||
|
||||
config GPIO_SHARED
|
||||
def_bool y
|
||||
depends on HAVE_SHARED_GPIOS || COMPILE_TEST
|
||||
select AUXILIARY_BUS
|
||||
|
||||
config DEBUG_GPIO
|
||||
bool "Debug GPIO calls"
|
||||
depends on DEBUG_KERNEL
|
||||
|
|
@ -2017,6 +2025,15 @@ config GPIO_SIM
|
|||
This enables the GPIO simulator - a configfs-based GPIO testing
|
||||
driver.
|
||||
|
||||
config GPIO_SHARED_PROXY
|
||||
tristate "Proxy driver for non-exclusive GPIOs"
|
||||
default m
|
||||
depends on GPIO_SHARED || COMPILE_TEST
|
||||
select AUXILIARY_BUS
|
||||
help
|
||||
This enables the GPIO shared proxy driver - an abstraction layer
|
||||
for GPIO pins that are shared by multiple devices.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "GPIO Debugging utilities"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
|
|||
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
||||
gpiolib-acpi-y := gpiolib-acpi-core.o gpiolib-acpi-quirks.o
|
||||
obj-$(CONFIG_GPIOLIB) += gpiolib-swnode.o
|
||||
obj-$(CONFIG_GPIO_SHARED) += gpiolib-shared.o
|
||||
|
||||
# Device drivers. Generally keep list sorted alphabetically
|
||||
obj-$(CONFIG_GPIO_REGMAP) += gpio-regmap.o
|
||||
|
|
@ -159,6 +160,7 @@ obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
|
|||
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o
|
||||
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
|
||||
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
|
||||
obj-$(CONFIG_GPIO_SHARED_PROXY) += gpio-shared-proxy.o
|
||||
obj-$(CONFIG_GPIO_SIFIVE) += gpio-sifive.o
|
||||
obj-$(CONFIG_GPIO_SIM) += gpio-sim.o
|
||||
obj-$(CONFIG_GPIO_SIOX) += gpio-siox.o
|
||||
|
|
|
|||
|
|
@ -0,0 +1,333 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2025 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "gpiolib-shared.h"
|
||||
|
||||
struct gpio_shared_proxy_data {
|
||||
struct gpio_chip gc;
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
struct device *dev;
|
||||
bool voted_high;
|
||||
};
|
||||
|
||||
static int
|
||||
gpio_shared_proxy_set_unlocked(struct gpio_shared_proxy_data *proxy,
|
||||
int (*set_func)(struct gpio_desc *desc, int value),
|
||||
int value)
|
||||
{
|
||||
struct gpio_shared_desc *shared_desc = proxy->shared_desc;
|
||||
struct gpio_desc *desc = shared_desc->desc;
|
||||
int ret = 0;
|
||||
|
||||
gpio_shared_lockdep_assert(shared_desc);
|
||||
|
||||
if (value) {
|
||||
/* User wants to set value to high. */
|
||||
if (proxy->voted_high)
|
||||
/* Already voted for high, nothing to do. */
|
||||
goto out;
|
||||
|
||||
/* Haven't voted for high yet. */
|
||||
if (!shared_desc->highcnt) {
|
||||
/*
|
||||
* Current value is low, need to actually set value
|
||||
* to high.
|
||||
*/
|
||||
ret = set_func(desc, 1);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
shared_desc->highcnt++;
|
||||
proxy->voted_high = true;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Desired value is low. */
|
||||
if (!proxy->voted_high)
|
||||
/* We didn't vote for high, nothing to do. */
|
||||
goto out;
|
||||
|
||||
/* We previously voted for high. */
|
||||
if (shared_desc->highcnt == 1) {
|
||||
/* This is the last remaining vote for high, set value to low. */
|
||||
ret = set_func(desc, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
shared_desc->highcnt--;
|
||||
proxy->voted_high = false;
|
||||
|
||||
out:
|
||||
if (shared_desc->highcnt)
|
||||
dev_dbg(proxy->dev,
|
||||
"Voted for value '%s', effective value is 'high', number of votes for 'high': %u\n",
|
||||
str_high_low(value), shared_desc->highcnt);
|
||||
else
|
||||
dev_dbg(proxy->dev, "Voted for value 'low', effective value is 'low'\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_request(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
struct gpio_shared_desc *shared_desc = proxy->shared_desc;
|
||||
|
||||
guard(gpio_shared_desc_lock)(shared_desc);
|
||||
|
||||
proxy->shared_desc->usecnt++;
|
||||
|
||||
dev_dbg(proxy->dev, "Shared GPIO requested, number of users: %u\n",
|
||||
proxy->shared_desc->usecnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpio_shared_proxy_free(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
struct gpio_shared_desc *shared_desc = proxy->shared_desc;
|
||||
|
||||
guard(gpio_shared_desc_lock)(shared_desc);
|
||||
|
||||
proxy->shared_desc->usecnt--;
|
||||
|
||||
dev_dbg(proxy->dev, "Shared GPIO freed, number of users: %u\n",
|
||||
proxy->shared_desc->usecnt);
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_set_config(struct gpio_chip *gc,
|
||||
unsigned int offset, unsigned long cfg)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
struct gpio_shared_desc *shared_desc = proxy->shared_desc;
|
||||
struct gpio_desc *desc = shared_desc->desc;
|
||||
int ret;
|
||||
|
||||
guard(gpio_shared_desc_lock)(shared_desc);
|
||||
|
||||
if (shared_desc->usecnt > 1) {
|
||||
if (shared_desc->cfg != cfg) {
|
||||
dev_dbg(proxy->dev,
|
||||
"Shared GPIO's configuration already set, accepting changes but users may conflict!!\n");
|
||||
} else {
|
||||
dev_dbg(proxy->dev, "Equal config requested, nothing to do\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpiod_set_config(desc, cfg);
|
||||
if (ret && ret != -ENOTSUPP)
|
||||
return ret;
|
||||
|
||||
shared_desc->cfg = cfg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_direction_input(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
struct gpio_shared_desc *shared_desc = proxy->shared_desc;
|
||||
struct gpio_desc *desc = shared_desc->desc;
|
||||
int dir;
|
||||
|
||||
guard(gpio_shared_desc_lock)(shared_desc);
|
||||
|
||||
if (shared_desc->usecnt == 1) {
|
||||
dev_dbg(proxy->dev,
|
||||
"Only one user of this shared GPIO, allowing to set direction to input\n");
|
||||
|
||||
return gpiod_direction_input(desc);
|
||||
}
|
||||
|
||||
dir = gpiod_get_direction(desc);
|
||||
if (dir < 0)
|
||||
return dir;
|
||||
|
||||
if (dir == GPIO_LINE_DIRECTION_OUT) {
|
||||
dev_dbg(proxy->dev,
|
||||
"Shared GPIO's direction already set to output, refusing to change\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_direction_output(struct gpio_chip *gc,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
struct gpio_shared_desc *shared_desc = proxy->shared_desc;
|
||||
struct gpio_desc *desc = shared_desc->desc;
|
||||
int ret, dir;
|
||||
|
||||
guard(gpio_shared_desc_lock)(shared_desc);
|
||||
|
||||
if (shared_desc->usecnt == 1) {
|
||||
dev_dbg(proxy->dev,
|
||||
"Only one user of this shared GPIO, allowing to set direction to output with value '%s'\n",
|
||||
str_high_low(value));
|
||||
|
||||
ret = gpiod_direction_output(desc, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (value) {
|
||||
proxy->voted_high = true;
|
||||
shared_desc->highcnt = 1;
|
||||
} else {
|
||||
proxy->voted_high = false;
|
||||
shared_desc->highcnt = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dir = gpiod_get_direction(desc);
|
||||
if (dir < 0)
|
||||
return dir;
|
||||
|
||||
if (dir == GPIO_LINE_DIRECTION_IN) {
|
||||
dev_dbg(proxy->dev,
|
||||
"Shared GPIO's direction already set to input, refusing to change\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return gpio_shared_proxy_set_unlocked(proxy, gpiod_direction_output, value);
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_get(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
|
||||
return gpiod_get_value(proxy->shared_desc->desc);
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_get_cansleep(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
|
||||
return gpiod_get_value_cansleep(proxy->shared_desc->desc);
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_do_set(struct gpio_shared_proxy_data *proxy,
|
||||
int (*set_func)(struct gpio_desc *desc, int value),
|
||||
int value)
|
||||
{
|
||||
guard(gpio_shared_desc_lock)(proxy->shared_desc);
|
||||
|
||||
return gpio_shared_proxy_set_unlocked(proxy, set_func, value);
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_set(struct gpio_chip *gc, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
|
||||
return gpio_shared_proxy_do_set(proxy, gpiod_set_value, value);
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_set_cansleep(struct gpio_chip *gc,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
|
||||
return gpio_shared_proxy_do_set(proxy, gpiod_set_value_cansleep, value);
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_get_direction(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
|
||||
return gpiod_get_direction(proxy->shared_desc->desc);
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
|
||||
|
||||
return gpiod_to_irq(proxy->shared_desc->desc);
|
||||
}
|
||||
|
||||
static int gpio_shared_proxy_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct gpio_shared_proxy_data *proxy;
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
struct device *dev = &adev->dev;
|
||||
struct gpio_chip *gc;
|
||||
|
||||
shared_desc = devm_gpiod_shared_get(dev);
|
||||
if (IS_ERR(shared_desc))
|
||||
return PTR_ERR(shared_desc);
|
||||
|
||||
proxy = devm_kzalloc(dev, sizeof(*proxy), GFP_KERNEL);
|
||||
if (!proxy)
|
||||
return -ENOMEM;
|
||||
|
||||
proxy->shared_desc = shared_desc;
|
||||
proxy->dev = dev;
|
||||
|
||||
gc = &proxy->gc;
|
||||
gc->base = -1;
|
||||
gc->ngpio = 1;
|
||||
gc->label = dev_name(dev);
|
||||
gc->parent = dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->can_sleep = shared_desc->can_sleep;
|
||||
|
||||
gc->request = gpio_shared_proxy_request;
|
||||
gc->free = gpio_shared_proxy_free;
|
||||
gc->set_config = gpio_shared_proxy_set_config;
|
||||
gc->direction_input = gpio_shared_proxy_direction_input;
|
||||
gc->direction_output = gpio_shared_proxy_direction_output;
|
||||
if (gc->can_sleep) {
|
||||
gc->set = gpio_shared_proxy_set_cansleep;
|
||||
gc->get = gpio_shared_proxy_get_cansleep;
|
||||
} else {
|
||||
gc->set = gpio_shared_proxy_set;
|
||||
gc->get = gpio_shared_proxy_get;
|
||||
}
|
||||
gc->get_direction = gpio_shared_proxy_get_direction;
|
||||
gc->to_irq = gpio_shared_proxy_to_irq;
|
||||
|
||||
return devm_gpiochip_add_data(dev, &proxy->gc, proxy);
|
||||
}
|
||||
|
||||
static const struct auxiliary_device_id gpio_shared_proxy_id_table[] = {
|
||||
{ .name = "gpiolib_shared.proxy" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(auxiliary, gpio_shared_proxy_id_table);
|
||||
|
||||
static struct auxiliary_driver gpio_shared_proxy_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-shared-proxy",
|
||||
},
|
||||
.probe = gpio_shared_proxy_probe,
|
||||
.id_table = gpio_shared_proxy_id_table,
|
||||
};
|
||||
module_auxiliary_driver(gpio_shared_proxy_driver);
|
||||
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>");
|
||||
MODULE_DESCRIPTION("Shared GPIO mux driver.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -0,0 +1,558 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2025 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fwnode.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-shared.h"
|
||||
|
||||
/* Represents a single reference to a GPIO pin. */
|
||||
struct gpio_shared_ref {
|
||||
struct list_head list;
|
||||
/* Firmware node associated with this GPIO's consumer. */
|
||||
struct fwnode_handle *fwnode;
|
||||
/* GPIO flags this consumer uses for the request. */
|
||||
enum gpiod_flags flags;
|
||||
char *con_id;
|
||||
int dev_id;
|
||||
struct auxiliary_device adev;
|
||||
struct gpiod_lookup_table *lookup;
|
||||
};
|
||||
|
||||
/* Represents a single GPIO pin. */
|
||||
struct gpio_shared_entry {
|
||||
struct list_head list;
|
||||
/* Firmware node associated with the GPIO controller. */
|
||||
struct fwnode_handle *fwnode;
|
||||
/* Hardware offset of the GPIO within its chip. */
|
||||
unsigned int offset;
|
||||
/* Index in the property value array. */
|
||||
size_t index;
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
struct kref ref;
|
||||
struct list_head refs;
|
||||
};
|
||||
|
||||
static LIST_HEAD(gpio_shared_list);
|
||||
static DEFINE_MUTEX(gpio_shared_lock);
|
||||
static DEFINE_IDA(gpio_shared_ida);
|
||||
|
||||
static struct gpio_shared_entry *
|
||||
gpio_shared_find_entry(struct fwnode_handle *controller_node,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct gpio_shared_entry *entry;
|
||||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
if (entry->fwnode == controller_node && entry->offset == offset)
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static int gpio_shared_of_traverse(struct device_node *curr)
|
||||
{
|
||||
struct gpio_shared_entry *entry;
|
||||
size_t con_id_len, suffix_len;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct of_phandle_args args;
|
||||
struct property *prop;
|
||||
unsigned int offset;
|
||||
const char *suffix;
|
||||
int ret, count, i;
|
||||
|
||||
for_each_property_of_node(curr, prop) {
|
||||
/*
|
||||
* The standard name for a GPIO property is "foo-gpios"
|
||||
* or "foo-gpio". Some bindings also use "gpios" or "gpio".
|
||||
* There are some legacy device-trees which have a different
|
||||
* naming convention and for which we have rename quirks in
|
||||
* place in gpiolib-of.c. I don't think any of them require
|
||||
* support for shared GPIOs so for now let's just ignore
|
||||
* them. We can always just export the quirk list and
|
||||
* iterate over it here.
|
||||
*/
|
||||
if (!strends(prop->name, "-gpios") &&
|
||||
!strends(prop->name, "-gpio") &&
|
||||
strcmp(prop->name, "gpios") != 0 &&
|
||||
strcmp(prop->name, "gpio") != 0)
|
||||
continue;
|
||||
|
||||
count = of_count_phandle_with_args(curr, prop->name,
|
||||
"#gpio-cells");
|
||||
if (count <= 0)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
struct device_node *np __free(device_node) = NULL;
|
||||
|
||||
ret = of_parse_phandle_with_args(curr, prop->name,
|
||||
"#gpio-cells", i,
|
||||
&args);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
np = args.np;
|
||||
|
||||
if (!of_property_present(np, "gpio-controller"))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We support 1, 2 and 3 cell GPIO bindings in the
|
||||
* kernel currently. There's only one old MIPS dts that
|
||||
* has a one-cell binding but there's no associated
|
||||
* consumer so it may as well be an error. There don't
|
||||
* seem to be any 3-cell users of non-exclusive GPIOs,
|
||||
* so we can skip this as well. Let's occupy ourselves
|
||||
* with the predominant 2-cell binding with the first
|
||||
* cell indicating the hardware offset of the GPIO and
|
||||
* the second defining the GPIO flags of the request.
|
||||
*/
|
||||
if (args.args_count != 2)
|
||||
continue;
|
||||
|
||||
fwnode = of_fwnode_handle(args.np);
|
||||
offset = args.args[0];
|
||||
|
||||
entry = gpio_shared_find_entry(fwnode, offset);
|
||||
if (!entry) {
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
entry->fwnode = fwnode_handle_get(fwnode);
|
||||
entry->offset = offset;
|
||||
entry->index = count;
|
||||
INIT_LIST_HEAD(&entry->refs);
|
||||
|
||||
list_add_tail(&entry->list, &gpio_shared_list);
|
||||
}
|
||||
|
||||
struct gpio_shared_ref *ref __free(kfree) =
|
||||
kzalloc(sizeof(*ref), GFP_KERNEL);
|
||||
if (!ref)
|
||||
return -ENOMEM;
|
||||
|
||||
ref->fwnode = fwnode_handle_get(of_fwnode_handle(curr));
|
||||
ref->flags = args.args[1];
|
||||
|
||||
if (strends(prop->name, "gpios"))
|
||||
suffix = "-gpios";
|
||||
else if (strends(prop->name, "gpio"))
|
||||
suffix = "-gpio";
|
||||
else
|
||||
suffix = NULL;
|
||||
if (!suffix)
|
||||
continue;
|
||||
|
||||
/* We only set con_id if there's actually one. */
|
||||
if (strcmp(prop->name, "gpios") && strcmp(prop->name, "gpio")) {
|
||||
ref->con_id = kstrdup(prop->name, GFP_KERNEL);
|
||||
if (!ref->con_id)
|
||||
return -ENOMEM;
|
||||
|
||||
con_id_len = strlen(ref->con_id);
|
||||
suffix_len = strlen(suffix);
|
||||
|
||||
ref->con_id[con_id_len - suffix_len] = '\0';
|
||||
}
|
||||
|
||||
ref->dev_id = ida_alloc(&gpio_shared_ida, GFP_KERNEL);
|
||||
if (ref->dev_id < 0) {
|
||||
kfree(ref->con_id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!list_empty(&entry->refs))
|
||||
pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n",
|
||||
entry->offset, fwnode_get_name(entry->fwnode));
|
||||
|
||||
list_add_tail(&no_free_ptr(ref)->list, &entry->refs);
|
||||
}
|
||||
}
|
||||
|
||||
for_each_child_of_node_scoped(curr, child) {
|
||||
ret = gpio_shared_of_traverse(child);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_shared_of_scan(void)
|
||||
{
|
||||
return gpio_shared_of_traverse(of_root);
|
||||
}
|
||||
#else
|
||||
static int gpio_shared_of_scan(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static void gpio_shared_adev_release(struct device *dev)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int gpio_shared_make_adev(struct gpio_device *gdev,
|
||||
struct gpio_shared_ref *ref)
|
||||
{
|
||||
struct auxiliary_device *adev = &ref->adev;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&gpio_shared_lock);
|
||||
|
||||
memset(adev, 0, sizeof(*adev));
|
||||
|
||||
adev->id = ref->dev_id;
|
||||
adev->name = "proxy";
|
||||
adev->dev.parent = gdev->dev.parent;
|
||||
adev->dev.release = gpio_shared_adev_release;
|
||||
|
||||
ret = auxiliary_device_init(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = auxiliary_device_add(adev);
|
||||
if (ret) {
|
||||
auxiliary_device_uninit(adev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_debug("Created an auxiliary GPIO proxy %s for GPIO device %s\n",
|
||||
dev_name(&adev->dev), gpio_device_get_label(gdev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags)
|
||||
{
|
||||
const char *dev_id = dev_name(consumer);
|
||||
struct gpio_shared_entry *entry;
|
||||
struct gpio_shared_ref *ref;
|
||||
|
||||
struct gpiod_lookup_table *lookup __free(kfree) =
|
||||
kzalloc(struct_size(lookup, table, 2), GFP_KERNEL);
|
||||
if (!lookup)
|
||||
return -ENOMEM;
|
||||
|
||||
guard(mutex)(&gpio_shared_lock);
|
||||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
if (!device_match_fwnode(consumer, ref->fwnode))
|
||||
continue;
|
||||
|
||||
/* We've already done that on a previous request. */
|
||||
if (ref->lookup)
|
||||
return 0;
|
||||
|
||||
char *key __free(kfree) =
|
||||
kasprintf(GFP_KERNEL,
|
||||
KBUILD_MODNAME ".proxy.%u",
|
||||
ref->adev.id);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
pr_debug("Adding machine lookup entry for a shared GPIO for consumer %s, with key '%s' and con_id '%s'\n",
|
||||
dev_id, key, ref->con_id ?: "none");
|
||||
|
||||
lookup->dev_id = dev_id;
|
||||
lookup->table[0] = GPIO_LOOKUP(no_free_ptr(key), 0,
|
||||
ref->con_id, lflags);
|
||||
|
||||
gpiod_add_lookup_table(no_free_ptr(lookup));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* We warn here because this can only happen if the programmer borked. */
|
||||
WARN_ON(1);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void gpio_shared_remove_adev(struct auxiliary_device *adev)
|
||||
{
|
||||
lockdep_assert_held(&gpio_shared_lock);
|
||||
|
||||
auxiliary_device_uninit(adev);
|
||||
auxiliary_device_delete(adev);
|
||||
}
|
||||
|
||||
int gpio_device_setup_shared(struct gpio_device *gdev)
|
||||
{
|
||||
struct gpio_shared_entry *entry;
|
||||
struct gpio_shared_ref *ref;
|
||||
unsigned long *flags;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&gpio_shared_lock);
|
||||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
if (gdev->dev.parent == &ref->adev.dev) {
|
||||
/*
|
||||
* This is a shared GPIO proxy. Mark its
|
||||
* descriptor as such and return here.
|
||||
*/
|
||||
__set_bit(GPIOD_FLAG_SHARED_PROXY,
|
||||
&gdev->descs[0].flags);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is not a shared GPIO proxy but it still may be the device
|
||||
* exposing shared pins. Find them and create the proxy devices.
|
||||
*/
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
||||
continue;
|
||||
|
||||
if (list_count_nodes(&entry->refs) <= 1)
|
||||
continue;
|
||||
|
||||
flags = &gdev->descs[entry->offset].flags;
|
||||
|
||||
__set_bit(GPIOD_FLAG_SHARED, flags);
|
||||
/*
|
||||
* Shared GPIOs are not requested via the normal path. Make
|
||||
* them inaccessible to anyone even before we register the
|
||||
* chip.
|
||||
*/
|
||||
__set_bit(GPIOD_FLAG_REQUESTED, flags);
|
||||
|
||||
pr_debug("GPIO %u owned by %s is shared by multiple consumers\n",
|
||||
entry->offset, gpio_device_get_label(gdev));
|
||||
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
pr_debug("Setting up a shared GPIO entry for %s\n",
|
||||
fwnode_get_name(ref->fwnode));
|
||||
|
||||
ret = gpio_shared_make_adev(gdev, ref);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_device_teardown_shared(struct gpio_device *gdev)
|
||||
{
|
||||
struct gpio_shared_entry *entry;
|
||||
struct gpio_shared_ref *ref;
|
||||
|
||||
guard(mutex)(&gpio_shared_lock);
|
||||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
if (!device_match_fwnode(&gdev->dev, entry->fwnode))
|
||||
continue;
|
||||
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
gpiod_remove_lookup_table(ref->lookup);
|
||||
kfree(ref->lookup->table[0].key);
|
||||
kfree(ref->lookup);
|
||||
ref->lookup = NULL;
|
||||
gpio_shared_remove_adev(&ref->adev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_shared_release(struct kref *kref)
|
||||
{
|
||||
struct gpio_shared_entry *entry =
|
||||
container_of(kref, struct gpio_shared_entry, ref);
|
||||
struct gpio_shared_desc *shared_desc = entry->shared_desc;
|
||||
|
||||
guard(mutex)(&gpio_shared_lock);
|
||||
|
||||
gpio_device_put(shared_desc->desc->gdev);
|
||||
if (shared_desc->can_sleep)
|
||||
mutex_destroy(&shared_desc->mutex);
|
||||
kfree(shared_desc);
|
||||
entry->shared_desc = NULL;
|
||||
}
|
||||
|
||||
static void gpiod_shared_put(void *data)
|
||||
{
|
||||
struct gpio_shared_entry *entry = data;
|
||||
|
||||
lockdep_assert_not_held(&gpio_shared_lock);
|
||||
|
||||
kref_put(&entry->ref, gpio_shared_release);
|
||||
}
|
||||
|
||||
static struct gpio_shared_desc *
|
||||
gpiod_shared_desc_create(struct gpio_shared_entry *entry)
|
||||
{
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
struct gpio_device *gdev;
|
||||
|
||||
shared_desc = kzalloc(sizeof(*shared_desc), GFP_KERNEL);
|
||||
if (!shared_desc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gdev = gpio_device_find_by_fwnode(entry->fwnode);
|
||||
if (!gdev) {
|
||||
kfree(shared_desc);
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
shared_desc->desc = &gdev->descs[entry->offset];
|
||||
shared_desc->can_sleep = gpiod_cansleep(shared_desc->desc);
|
||||
if (shared_desc->can_sleep)
|
||||
mutex_init(&shared_desc->mutex);
|
||||
else
|
||||
spin_lock_init(&shared_desc->spinlock);
|
||||
|
||||
return shared_desc;
|
||||
}
|
||||
|
||||
static struct gpio_shared_entry *gpiod_shared_find(struct auxiliary_device *adev)
|
||||
{
|
||||
struct gpio_shared_desc *shared_desc;
|
||||
struct gpio_shared_entry *entry;
|
||||
struct gpio_shared_ref *ref;
|
||||
|
||||
guard(mutex)(&gpio_shared_lock);
|
||||
|
||||
list_for_each_entry(entry, &gpio_shared_list, list) {
|
||||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
if (adev != &ref->adev)
|
||||
continue;
|
||||
|
||||
if (entry->shared_desc) {
|
||||
kref_get(&entry->ref);
|
||||
return entry;
|
||||
}
|
||||
|
||||
shared_desc = gpiod_shared_desc_create(entry);
|
||||
if (IS_ERR(shared_desc))
|
||||
return ERR_CAST(shared_desc);
|
||||
|
||||
kref_init(&entry->ref);
|
||||
entry->shared_desc = shared_desc;
|
||||
|
||||
pr_debug("Device %s acquired a reference to the shared GPIO %u owned by %s\n",
|
||||
dev_name(&adev->dev), gpio_chip_hwgpio(shared_desc->desc),
|
||||
gpio_device_get_label(shared_desc->desc->gdev));
|
||||
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev)
|
||||
{
|
||||
struct gpio_shared_entry *entry;
|
||||
int ret;
|
||||
|
||||
entry = gpiod_shared_find(to_auxiliary_dev(dev));
|
||||
if (IS_ERR(entry))
|
||||
return ERR_CAST(entry);
|
||||
|
||||
ret = devm_add_action_or_reset(dev, gpiod_shared_put, entry);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return entry->shared_desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_gpiod_shared_get);
|
||||
|
||||
static void gpio_shared_drop_ref(struct gpio_shared_ref *ref)
|
||||
{
|
||||
list_del(&ref->list);
|
||||
kfree(ref->con_id);
|
||||
ida_free(&gpio_shared_ida, ref->dev_id);
|
||||
fwnode_handle_put(ref->fwnode);
|
||||
kfree(ref);
|
||||
}
|
||||
|
||||
static void gpio_shared_drop_entry(struct gpio_shared_entry *entry)
|
||||
{
|
||||
list_del(&entry->list);
|
||||
fwnode_handle_put(entry->fwnode);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is only called if gpio_shared_init() fails so it's in fact __init and
|
||||
* not __exit.
|
||||
*/
|
||||
static void __init gpio_shared_teardown(void)
|
||||
{
|
||||
struct gpio_shared_entry *entry, *epos;
|
||||
struct gpio_shared_ref *ref, *rpos;
|
||||
|
||||
list_for_each_entry_safe(entry, epos, &gpio_shared_list, list) {
|
||||
list_for_each_entry_safe(ref, rpos, &entry->refs, list)
|
||||
gpio_shared_drop_ref(ref);
|
||||
|
||||
gpio_shared_drop_entry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_shared_free_exclusive(void)
|
||||
{
|
||||
struct gpio_shared_entry *entry, *epos;
|
||||
|
||||
list_for_each_entry_safe(entry, epos, &gpio_shared_list, list) {
|
||||
if (list_count_nodes(&entry->refs) > 1)
|
||||
continue;
|
||||
|
||||
gpio_shared_drop_ref(list_first_entry(&entry->refs,
|
||||
struct gpio_shared_ref,
|
||||
list));
|
||||
gpio_shared_drop_entry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init gpio_shared_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Right now, we only support OF-based systems. */
|
||||
ret = gpio_shared_of_scan();
|
||||
if (ret) {
|
||||
gpio_shared_teardown();
|
||||
pr_err("Failed to scan OF nodes for shared GPIOs: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_shared_free_exclusive();
|
||||
|
||||
pr_debug("Finished scanning firmware nodes for shared GPIOs\n");
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(gpio_shared_init);
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef __LINUX_GPIO_SHARED_H
|
||||
#define __LINUX_GPIO_SHARED_H
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
struct gpio_device;
|
||||
struct gpio_desc;
|
||||
struct device;
|
||||
|
||||
#if IS_ENABLED(CONFIG_GPIO_SHARED)
|
||||
|
||||
int gpio_device_setup_shared(struct gpio_device *gdev);
|
||||
void gpio_device_teardown_shared(struct gpio_device *gdev);
|
||||
int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags);
|
||||
|
||||
#else
|
||||
|
||||
static inline int gpio_device_setup_shared(struct gpio_device *gdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void gpio_device_teardown_shared(struct gpio_device *gdev) { }
|
||||
|
||||
static inline int gpio_shared_add_proxy_lookup(struct device *consumer,
|
||||
unsigned long lflags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIO_SHARED */
|
||||
|
||||
struct gpio_shared_desc {
|
||||
struct gpio_desc *desc;
|
||||
bool can_sleep;
|
||||
unsigned long cfg;
|
||||
unsigned int usecnt;
|
||||
unsigned int highcnt;
|
||||
union {
|
||||
struct mutex mutex;
|
||||
spinlock_t spinlock;
|
||||
};
|
||||
};
|
||||
|
||||
struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev);
|
||||
|
||||
DEFINE_LOCK_GUARD_1(gpio_shared_desc_lock, struct gpio_shared_desc,
|
||||
if (_T->lock->can_sleep)
|
||||
mutex_lock(&_T->lock->mutex);
|
||||
else
|
||||
spin_lock_irqsave(&_T->lock->spinlock, _T->flags),
|
||||
if (_T->lock->can_sleep)
|
||||
mutex_unlock(&_T->lock->mutex);
|
||||
else
|
||||
spin_unlock_irqrestore(&_T->lock->spinlock, _T->flags),
|
||||
unsigned long flags)
|
||||
|
||||
static inline void gpio_shared_lockdep_assert(struct gpio_shared_desc *shared_desc)
|
||||
{
|
||||
if (shared_desc->can_sleep)
|
||||
lockdep_assert_held(&shared_desc->mutex);
|
||||
else
|
||||
lockdep_assert_held(&shared_desc->spinlock);
|
||||
}
|
||||
|
||||
#endif /* __LINUX_GPIO_SHARED_H */
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
#include "gpiolib-acpi.h"
|
||||
#include "gpiolib-cdev.h"
|
||||
#include "gpiolib-of.h"
|
||||
#include "gpiolib-shared.h"
|
||||
#include "gpiolib-swnode.h"
|
||||
#include "gpiolib-sysfs.h"
|
||||
#include "gpiolib.h"
|
||||
|
|
@ -1200,6 +1201,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
if (ret)
|
||||
goto err_remove_irqchip_mask;
|
||||
|
||||
ret = gpio_device_setup_shared(gdev);
|
||||
if (ret)
|
||||
goto err_remove_irqchip;
|
||||
|
||||
/*
|
||||
* By first adding the chardev, and then adding the device,
|
||||
* we get a device node entry in sysfs under
|
||||
|
|
@ -1211,10 +1216,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
if (gpiolib_initialized) {
|
||||
ret = gpiochip_setup_dev(gdev);
|
||||
if (ret)
|
||||
goto err_remove_irqchip;
|
||||
goto err_teardown_shared;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_teardown_shared:
|
||||
gpio_device_teardown_shared(gdev);
|
||||
err_remove_irqchip:
|
||||
gpiochip_irqchip_remove(gc);
|
||||
err_remove_irqchip_mask:
|
||||
|
|
@ -1283,6 +1291,7 @@ void gpiochip_remove(struct gpio_chip *gc)
|
|||
/* Numb the device, cancelling all outstanding operations */
|
||||
rcu_assign_pointer(gdev->chip, NULL);
|
||||
synchronize_srcu(&gdev->srcu);
|
||||
gpio_device_teardown_shared(gdev);
|
||||
gpiochip_irqchip_remove(gc);
|
||||
acpi_gpiochip_remove(gc);
|
||||
of_gpiochip_remove(gc);
|
||||
|
|
@ -3981,6 +3990,26 @@ int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_consumer_name);
|
||||
|
||||
/**
|
||||
* gpiod_is_shared() - check if this GPIO can be shared by multiple consumers
|
||||
* @desc: GPIO to inspect
|
||||
*
|
||||
* Returns:
|
||||
* True if this GPIO can be shared by multiple consumers at once. False if it's
|
||||
* a regular, exclusive GPIO.
|
||||
*
|
||||
* Note:
|
||||
* This function returning true does not mean that this GPIO is currently being
|
||||
* shared. It means the GPIO core has registered the fact that the firmware
|
||||
* configuration indicates that it can be shared by multiple consumers and is
|
||||
* in charge of arbitrating the access.
|
||||
*/
|
||||
bool gpiod_is_shared(const struct gpio_desc *desc)
|
||||
{
|
||||
return test_bit(GPIOD_FLAG_SHARED_PROXY, &desc->flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_is_shared);
|
||||
|
||||
/**
|
||||
* gpiod_to_irq() - return the IRQ corresponding to a GPIO
|
||||
* @desc: gpio whose IRQ will be returned (already requested)
|
||||
|
|
@ -4652,11 +4681,29 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer,
|
|||
scoped_guard(srcu, &gpio_devices_srcu) {
|
||||
desc = gpiod_fwnode_lookup(fwnode, consumer, con_id, idx,
|
||||
&flags, &lookupflags);
|
||||
if (!IS_ERR_OR_NULL(desc) &&
|
||||
test_bit(GPIOD_FLAG_SHARED, &desc->flags)) {
|
||||
/*
|
||||
* We're dealing with a GPIO shared by multiple
|
||||
* consumers. This is the moment to add the machine
|
||||
* lookup table for the proxy device as previously
|
||||
* we only knew the consumer's fwnode.
|
||||
*/
|
||||
ret = gpio_shared_add_proxy_lookup(consumer, lookupflags);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Trigger platform lookup for shared GPIO proxy. */
|
||||
desc = ERR_PTR(-ENOENT);
|
||||
/* Trigger it even for fwnode-only gpiod_get(). */
|
||||
platform_lookup_allowed = true;
|
||||
}
|
||||
|
||||
if (gpiod_not_found(desc) && platform_lookup_allowed) {
|
||||
/*
|
||||
* Either we are not using DT or ACPI, or their lookup
|
||||
* did not return a result. In that case, use platform
|
||||
* lookup as a fallback.
|
||||
* did not return a result or this is a shared GPIO. In
|
||||
* that case, use platform lookup as a fallback.
|
||||
*/
|
||||
dev_dbg(consumer,
|
||||
"using lookup tables for GPIO lookup\n");
|
||||
|
|
@ -4679,14 +4726,19 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer,
|
|||
return ERR_PTR(ret);
|
||||
|
||||
/*
|
||||
* This happens when there are several consumers for
|
||||
* the same GPIO line: we just return here without
|
||||
* further initialization. It is a bit of a hack.
|
||||
* This is necessary to support fixed regulators.
|
||||
* This happens when there are several consumers for the same
|
||||
* GPIO line: we just return here without further
|
||||
* initialization. It's a hack introduced long ago to support
|
||||
* fixed regulators. We now have a better solution with
|
||||
* automated scanning where affected platforms just need to
|
||||
* select the provided Kconfig option.
|
||||
*
|
||||
* FIXME: Make this more sane and safe.
|
||||
* FIXME: Remove the GPIOD_FLAGS_BIT_NONEXCLUSIVE flag after
|
||||
* making sure all platforms use the new mechanism.
|
||||
*/
|
||||
dev_info(consumer, "nonexclusive access to GPIO for %s\n", name);
|
||||
dev_info(consumer,
|
||||
"nonexclusive access to GPIO for %s, consider updating your code to using gpio-shared-proxy\n",
|
||||
name);
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -204,6 +204,8 @@ struct gpio_desc {
|
|||
#define GPIOD_FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */
|
||||
#define GPIOD_FLAG_EVENT_CLOCK_REALTIME 18 /* GPIO CDEV reports REALTIME timestamps in events */
|
||||
#define GPIOD_FLAG_EVENT_CLOCK_HTE 19 /* GPIO CDEV reports hardware timestamps in events */
|
||||
#define GPIOD_FLAG_SHARED 20 /* GPIO is shared by multiple consumers */
|
||||
#define GPIOD_FLAG_SHARED_PROXY 21 /* GPIO is a virtual proxy to a physically shared pin. */
|
||||
|
||||
/* Connection label */
|
||||
struct gpio_desc_label __rcu *label;
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@ static void arizona_haptics_work(struct work_struct *work)
|
|||
struct arizona_haptics,
|
||||
work);
|
||||
struct arizona *arizona = haptics->arizona;
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_dapm_to_component(arizona->dapm);
|
||||
int ret;
|
||||
|
||||
if (!haptics->arizona->dapm) {
|
||||
|
|
@ -65,7 +63,7 @@ static void arizona_haptics_work(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
ret = snd_soc_component_enable_pin(component, "HAPTICS");
|
||||
ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
|
||||
ret);
|
||||
|
|
@ -80,7 +78,7 @@ static void arizona_haptics_work(struct work_struct *work)
|
|||
}
|
||||
} else {
|
||||
/* This disable sequence will be a noop if already enabled */
|
||||
ret = snd_soc_component_disable_pin(component, "HAPTICS");
|
||||
ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
|
||||
ret);
|
||||
|
|
@ -139,14 +137,12 @@ static int arizona_haptics_play(struct input_dev *input, void *data,
|
|||
static void arizona_haptics_close(struct input_dev *input)
|
||||
{
|
||||
struct arizona_haptics *haptics = input_get_drvdata(input);
|
||||
struct snd_soc_component *component;
|
||||
struct snd_soc_dapm_context *dapm = haptics->arizona->dapm;
|
||||
|
||||
cancel_work_sync(&haptics->work);
|
||||
|
||||
if (haptics->arizona->dapm) {
|
||||
component = snd_soc_dapm_to_component(haptics->arizona->dapm);
|
||||
snd_soc_component_disable_pin(component, "HAPTICS");
|
||||
}
|
||||
if (dapm)
|
||||
snd_soc_dapm_disable_pin(dapm, "HAPTICS");
|
||||
}
|
||||
|
||||
static int arizona_haptics_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ static void arizona_micsupp_check_cp(struct work_struct *work)
|
|||
struct arizona_micsupp *micsupp =
|
||||
container_of(work, struct arizona_micsupp, check_cp_work);
|
||||
struct snd_soc_dapm_context *dapm = *micsupp->dapm;
|
||||
struct snd_soc_component *component;
|
||||
const struct regulator_desc *desc = micsupp->desc;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
|
@ -61,14 +60,11 @@ static void arizona_micsupp_check_cp(struct work_struct *work)
|
|||
}
|
||||
|
||||
if (dapm) {
|
||||
component = snd_soc_dapm_to_component(dapm);
|
||||
|
||||
if ((val & (desc->enable_mask | desc->bypass_mask)) ==
|
||||
desc->enable_mask)
|
||||
snd_soc_component_force_enable_pin(component,
|
||||
"MICSUPP");
|
||||
snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
|
||||
else
|
||||
snd_soc_component_disable_pin(component, "MICSUPP");
|
||||
snd_soc_dapm_disable_pin(dapm, "MICSUPP");
|
||||
|
||||
snd_soc_dapm_sync(dapm);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -807,6 +807,7 @@ int gbaudio_register_module(struct gbaudio_module_info *module)
|
|||
{
|
||||
int ret;
|
||||
struct snd_soc_component *comp;
|
||||
struct snd_soc_dapm_context *dapm;
|
||||
struct gbaudio_jack *jack = NULL;
|
||||
|
||||
if (!gbcodec) {
|
||||
|
|
@ -815,6 +816,7 @@ int gbaudio_register_module(struct gbaudio_module_info *module)
|
|||
}
|
||||
|
||||
comp = gbcodec->component;
|
||||
dapm = snd_soc_component_to_dapm(comp);
|
||||
|
||||
mutex_lock(&gbcodec->register_mutex);
|
||||
|
||||
|
|
@ -833,18 +835,18 @@ int gbaudio_register_module(struct gbaudio_module_info *module)
|
|||
}
|
||||
|
||||
if (module->dapm_widgets)
|
||||
snd_soc_dapm_new_controls(&comp->dapm, module->dapm_widgets,
|
||||
snd_soc_dapm_new_controls(dapm, module->dapm_widgets,
|
||||
module->num_dapm_widgets);
|
||||
if (module->controls)
|
||||
snd_soc_add_component_controls(comp, module->controls,
|
||||
module->num_controls);
|
||||
if (module->dapm_routes)
|
||||
snd_soc_dapm_add_routes(&comp->dapm, module->dapm_routes,
|
||||
snd_soc_dapm_add_routes(dapm, module->dapm_routes,
|
||||
module->num_dapm_routes);
|
||||
|
||||
/* card already instantiated, create widgets here only */
|
||||
if (comp->card->instantiated) {
|
||||
gbaudio_dapm_link_component_dai_widgets(comp->card, &comp->dapm);
|
||||
gbaudio_dapm_link_component_dai_widgets(comp->card, dapm);
|
||||
#ifdef CONFIG_SND_JACK
|
||||
/*
|
||||
* register jack devices for this module
|
||||
|
|
@ -966,9 +968,11 @@ void gbaudio_unregister_module(struct gbaudio_module_info *module)
|
|||
#endif
|
||||
|
||||
if (module->dapm_routes) {
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(comp);
|
||||
|
||||
dev_dbg(comp->dev, "Removing %d routes\n",
|
||||
module->num_dapm_routes);
|
||||
snd_soc_dapm_del_routes(&comp->dapm, module->dapm_routes,
|
||||
snd_soc_dapm_del_routes(dapm, module->dapm_routes,
|
||||
module->num_dapm_routes);
|
||||
}
|
||||
if (module->controls) {
|
||||
|
|
@ -979,9 +983,11 @@ void gbaudio_unregister_module(struct gbaudio_module_info *module)
|
|||
module->num_controls);
|
||||
}
|
||||
if (module->dapm_widgets) {
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(comp);
|
||||
|
||||
dev_dbg(comp->dev, "Removing %d widgets\n",
|
||||
module->num_dapm_widgets);
|
||||
gbaudio_dapm_free_controls(&comp->dapm, module->dapm_widgets,
|
||||
gbaudio_dapm_free_controls(dapm, module->dapm_widgets,
|
||||
module->num_dapm_widgets);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,12 +115,13 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm,
|
|||
{
|
||||
int i;
|
||||
struct snd_soc_dapm_widget *w, *tmp_w;
|
||||
struct snd_soc_card *card = snd_soc_dapm_to_card(dapm);
|
||||
|
||||
mutex_lock(&dapm->card->dapm_mutex);
|
||||
mutex_lock(&card->dapm_mutex);
|
||||
for (i = 0; i < num; i++) {
|
||||
/* below logic can be optimized to identify widget pointer */
|
||||
w = NULL;
|
||||
list_for_each_entry(tmp_w, &dapm->card->widgets, list) {
|
||||
list_for_each_entry(tmp_w, &card->widgets, list) {
|
||||
if (tmp_w->dapm == dapm &&
|
||||
!strcmp(tmp_w->name, widget->name)) {
|
||||
w = tmp_w;
|
||||
|
|
@ -128,7 +129,7 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm,
|
|||
}
|
||||
}
|
||||
if (!w) {
|
||||
dev_err(dapm->dev, "%s: widget not found\n",
|
||||
dev_err(card->dev, "%s: widget not found\n",
|
||||
widget->name);
|
||||
widget++;
|
||||
continue;
|
||||
|
|
@ -136,7 +137,7 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm,
|
|||
widget++;
|
||||
gbaudio_dapm_free_widget(w);
|
||||
}
|
||||
mutex_unlock(&dapm->card->dapm_mutex);
|
||||
mutex_unlock(&card->dapm_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ static int gbcodec_mixer_ctl_info(struct snd_kcontrol *kcontrol,
|
|||
struct gbaudio_ctl_pvt *data;
|
||||
struct gb_audio_ctl_elem_info *info;
|
||||
struct gbaudio_module_info *module;
|
||||
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
|
||||
struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
|
||||
struct gbaudio_codec_info *gbcodec = snd_soc_component_get_drvdata(comp);
|
||||
|
||||
dev_dbg(comp->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
|
||||
|
|
@ -214,7 +214,7 @@ static int gbcodec_mixer_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
struct gbaudio_ctl_pvt *data;
|
||||
struct gb_audio_ctl_elem_value gbvalue;
|
||||
struct gbaudio_module_info *module;
|
||||
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
|
||||
struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
|
||||
struct gbaudio_codec_info *gb = snd_soc_component_get_drvdata(comp);
|
||||
struct gb_bundle *bundle;
|
||||
|
||||
|
|
@ -276,7 +276,7 @@ static int gbcodec_mixer_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
struct gbaudio_ctl_pvt *data;
|
||||
struct gb_audio_ctl_elem_value gbvalue;
|
||||
struct gbaudio_module_info *module;
|
||||
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
|
||||
struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
|
||||
struct gbaudio_codec_info *gb = snd_soc_component_get_drvdata(comp);
|
||||
struct gb_bundle *bundle;
|
||||
|
||||
|
|
@ -380,7 +380,7 @@ static int gbcodec_mixer_dapm_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
struct gbaudio_module_info *module;
|
||||
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
||||
struct device *codec_dev = widget->dapm->dev;
|
||||
struct device *codec_dev = snd_soc_dapm_to_dev(widget->dapm);
|
||||
struct gbaudio_codec_info *gb = dev_get_drvdata(codec_dev);
|
||||
struct gb_bundle *bundle;
|
||||
|
||||
|
|
@ -393,7 +393,7 @@ static int gbcodec_mixer_dapm_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
bundle = to_gb_bundle(module->dev);
|
||||
|
||||
if (data->vcount == 2)
|
||||
dev_warn(widget->dapm->dev,
|
||||
dev_warn(codec_dev,
|
||||
"GB: Control '%s' is stereo, which is not supported\n",
|
||||
kcontrol->id.name);
|
||||
|
||||
|
|
@ -429,7 +429,7 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
struct gbaudio_module_info *module;
|
||||
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
||||
struct device *codec_dev = widget->dapm->dev;
|
||||
struct device *codec_dev = snd_soc_dapm_to_dev(widget->dapm);
|
||||
struct gbaudio_codec_info *gb = dev_get_drvdata(codec_dev);
|
||||
struct gb_bundle *bundle;
|
||||
|
||||
|
|
@ -443,7 +443,7 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
bundle = to_gb_bundle(module->dev);
|
||||
|
||||
if (data->vcount == 2)
|
||||
dev_warn(widget->dapm->dev,
|
||||
dev_warn(codec_dev,
|
||||
"GB: Control '%s' is stereo, which is not supported\n",
|
||||
kcontrol->id.name);
|
||||
|
||||
|
|
@ -543,7 +543,7 @@ static int gbcodec_enum_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int ret, ctl_id;
|
||||
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
|
||||
struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
|
||||
struct gbaudio_codec_info *gb = snd_soc_component_get_drvdata(comp);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
struct gb_audio_ctl_elem_value gbvalue;
|
||||
|
|
@ -588,7 +588,7 @@ static int gbcodec_enum_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int ret, ctl_id;
|
||||
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
|
||||
struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
|
||||
struct gbaudio_codec_info *gb = snd_soc_component_get_drvdata(comp);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
struct gb_audio_ctl_elem_value gbvalue;
|
||||
|
|
@ -712,7 +712,7 @@ static int gbcodec_enum_dapm_ctl_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
||||
struct gbaudio_module_info *module;
|
||||
struct gb_audio_ctl_elem_value gbvalue;
|
||||
struct device *codec_dev = widget->dapm->dev;
|
||||
struct device *codec_dev = snd_soc_dapm_to_dev(widget->dapm);
|
||||
struct gbaudio_codec_info *gb = dev_get_drvdata(codec_dev);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
struct gb_bundle *bundle;
|
||||
|
|
@ -759,7 +759,7 @@ static int gbcodec_enum_dapm_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
||||
struct gb_audio_ctl_elem_value gbvalue;
|
||||
struct gbaudio_module_info *module;
|
||||
struct device *codec_dev = widget->dapm->dev;
|
||||
struct device *codec_dev = snd_soc_dapm_to_dev(widget->dapm);
|
||||
struct gbaudio_codec_info *gb = dev_get_drvdata(codec_dev);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
struct gb_bundle *bundle;
|
||||
|
|
@ -924,7 +924,7 @@ static int gbaudio_widget_event(struct snd_soc_dapm_widget *w,
|
|||
{
|
||||
int wid;
|
||||
int ret;
|
||||
struct device *codec_dev = w->dapm->dev;
|
||||
struct device *codec_dev = snd_soc_dapm_to_dev(w->dapm);
|
||||
struct gbaudio_codec_info *gbcodec = dev_get_drvdata(codec_dev);
|
||||
struct gbaudio_module_info *module;
|
||||
struct gb_bundle *bundle;
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ struct cs_dsp_coeff_ctl {
|
|||
const char *subname;
|
||||
unsigned int subname_len;
|
||||
unsigned int offset;
|
||||
size_t len;
|
||||
unsigned int len;
|
||||
unsigned int type;
|
||||
unsigned int flags;
|
||||
unsigned int set:1;
|
||||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -26,21 +26,21 @@ struct cs_dsp_test {
|
|||
|
||||
struct cs_dsp_test_local *local;
|
||||
|
||||
/* Following members are private */
|
||||
/* private: Following members are private */
|
||||
bool saw_bus_write;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cs_dsp_mock_alg_def - Info for creating a mock algorithm entry.
|
||||
*
|
||||
* @id Algorithm ID.
|
||||
* @ver; Algorithm version.
|
||||
* @xm_base_words XM base address in DSP words.
|
||||
* @xm_size_words XM size in DSP words.
|
||||
* @ym_base_words YM base address in DSP words.
|
||||
* @ym_size_words YM size in DSP words.
|
||||
* @zm_base_words ZM base address in DSP words.
|
||||
* @zm_size_words ZM size in DSP words.
|
||||
* @id: Algorithm ID.
|
||||
* @ver: Algorithm version.
|
||||
* @xm_base_words: XM base address in DSP words.
|
||||
* @xm_size_words: XM size in DSP words.
|
||||
* @ym_base_words: YM base address in DSP words.
|
||||
* @ym_size_words: YM size in DSP words.
|
||||
* @zm_base_words: ZM base address in DSP words.
|
||||
* @zm_size_words: ZM size in DSP words.
|
||||
*/
|
||||
struct cs_dsp_mock_alg_def {
|
||||
unsigned int id;
|
||||
|
|
|
|||
|
|
@ -167,6 +167,8 @@ int gpiod_cansleep(const struct gpio_desc *desc);
|
|||
int gpiod_to_irq(const struct gpio_desc *desc);
|
||||
int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name);
|
||||
|
||||
bool gpiod_is_shared(const struct gpio_desc *desc);
|
||||
|
||||
/* Convert between the old gpio_ and new gpiod_ interfaces */
|
||||
struct gpio_desc *gpio_to_desc(unsigned gpio);
|
||||
int desc_to_gpio(const struct gpio_desc *desc);
|
||||
|
|
@ -520,6 +522,13 @@ static inline int gpiod_set_consumer_name(struct gpio_desc *desc,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline bool gpiod_is_shared(const struct gpio_desc *desc)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(desc);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct gpio_desc *gpio_to_desc(unsigned gpio)
|
||||
{
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -3075,6 +3075,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
|
||||
|
|
|
|||
|
|
@ -676,7 +676,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,
|
||||
|
|
@ -738,7 +738,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,
|
||||
|
|
@ -970,7 +970,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
|
||||
|
|
@ -983,9 +983,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
|
||||
|
|
@ -1198,12 +1198,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
|
||||
*
|
||||
|
|
@ -1211,9 +1212,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) \
|
||||
#define devm_regmap_init_sdw_mbq_cfg(dev, sdw, config, mbq_config) \
|
||||
__regmap_lockdep_wrapper(__devm_regmap_init_sdw_mbq, \
|
||||
#config, sdw, config, mbq_config)
|
||||
#config, dev, sdw, config, mbq_config)
|
||||
|
||||
/**
|
||||
* devm_regmap_init_slimbus() - Initialise managed register map
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -562,4 +562,22 @@ static inline bool strstarts(const char *str, const char *prefix)
|
|||
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* strends - Check if a string ends with another string.
|
||||
* @str - NULL-terminated string to check against @suffix
|
||||
* @suffix - NULL-terminated string defining the suffix to look for in @str
|
||||
*
|
||||
* Returns:
|
||||
* True if @str ends with @suffix. False in all other cases.
|
||||
*/
|
||||
static inline bool strends(const char *str, const char *suffix)
|
||||
{
|
||||
unsigned int str_len = strlen(str), suffix_len = strlen(suffix);
|
||||
|
||||
if (str_len < suffix_len)
|
||||
return false;
|
||||
|
||||
return !(strcmp(str + str_len - suffix_len, suffix));
|
||||
}
|
||||
|
||||
#endif /* _LINUX_STRING_H_ */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -177,6 +182,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
|
||||
|
|
@ -243,6 +251,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
|
||||
|
|
@ -258,12 +267,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
|
||||
|
||||
|
|
@ -291,9 +310,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;
|
||||
|
|
@ -304,11 +330,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)
|
||||
|
|
@ -340,6 +369,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];
|
||||
|
|
@ -358,8 +388,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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -114,8 +114,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;
|
||||
};
|
||||
|
|
@ -131,8 +131,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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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, \
|
||||
|
|
@ -1225,6 +1239,7 @@ struct soc_mixer_control {
|
|||
unsigned int sign_bit;
|
||||
unsigned int invert:1;
|
||||
unsigned int autodisable:1;
|
||||
unsigned int sdca_q78:1;
|
||||
#ifdef CONFIG_SND_SOC_TOPOLOGY
|
||||
struct snd_soc_dobj dobj;
|
||||
#endif
|
||||
|
|
@ -1305,22 +1320,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);
|
||||
|
||||
|
|
@ -1482,22 +1481,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), \
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
@ -197,7 +203,6 @@ struct tasdevice_priv {
|
|||
struct acoustic_data acou_data;
|
||||
#endif
|
||||
struct tasdevice_fw *fmw;
|
||||
struct gpio_desc *speaker_id;
|
||||
struct gpio_desc *reset;
|
||||
struct mutex codec_lock;
|
||||
struct regmap *regmap;
|
||||
|
|
@ -215,6 +220,7 @@ struct tasdevice_priv {
|
|||
unsigned int magic_num;
|
||||
unsigned int chip_id;
|
||||
unsigned int sysclk;
|
||||
int speaker_id;
|
||||
|
||||
int irq;
|
||||
int cur_prog;
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ DECLARE_EVENT_CLASS(snd_soc_dapm,
|
|||
TP_ARGS(dapm, val),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( card_name, dapm->card->name)
|
||||
__string( comp_name, dapm->component ? dapm->component->name : "(none)")
|
||||
__string( card_name, snd_soc_dapm_to_card(dapm)->name)
|
||||
__string( comp_name, snd_soc_dapm_to_component(dapm) ? snd_soc_dapm_to_component(dapm)->name : "(none)")
|
||||
__field( int, val)
|
||||
),
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -602,6 +602,18 @@ static void string_test_memtostr(struct kunit *test)
|
|||
KUNIT_EXPECT_EQ(test, dest[7], '\0');
|
||||
}
|
||||
|
||||
static void string_test_strends(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_TRUE(test, strends("foo-bar", "bar"));
|
||||
KUNIT_EXPECT_TRUE(test, strends("foo-bar", "-bar"));
|
||||
KUNIT_EXPECT_TRUE(test, strends("foobar", "foobar"));
|
||||
KUNIT_EXPECT_TRUE(test, strends("foobar", ""));
|
||||
KUNIT_EXPECT_FALSE(test, strends("bar", "foobar"));
|
||||
KUNIT_EXPECT_FALSE(test, strends("", "foo"));
|
||||
KUNIT_EXPECT_FALSE(test, strends("foobar", "ba"));
|
||||
KUNIT_EXPECT_TRUE(test, strends("", ""));
|
||||
}
|
||||
|
||||
static struct kunit_case string_test_cases[] = {
|
||||
KUNIT_CASE(string_test_memset16),
|
||||
KUNIT_CASE(string_test_memset32),
|
||||
|
|
@ -623,6 +635,7 @@ static struct kunit_case string_test_cases[] = {
|
|||
KUNIT_CASE(string_test_strlcat),
|
||||
KUNIT_CASE(string_test_strtomem),
|
||||
KUNIT_CASE(string_test_memtostr),
|
||||
KUNIT_CASE(string_test_strends),
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -2106,13 +2106,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]);
|
||||
|
|
@ -2124,7 +2122,6 @@ static int __init alsa_rawmidi_init(void)
|
|||
amidi_map[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SND_OSSEMUL */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@
|
|||
snd-dice-y := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
|
||||
dice-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \
|
||||
dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.o \
|
||||
dice-harman.o dice-focusrite.o dice-weiss.o
|
||||
dice-harman.o dice-focusrite.o dice-weiss.o dice-teac.o
|
||||
obj-$(CONFIG_SND_DICE) += snd-dice.o
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
|
|||
break;
|
||||
|
||||
base_offset += EXT_APP_STREAM_ENTRIES;
|
||||
stream_count = be32_to_cpu(reg[0]);
|
||||
stream_count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
|
||||
err = read_stream_entries(dice, section_addr, base_offset,
|
||||
stream_count, mode,
|
||||
dice->tx_pcm_chs,
|
||||
|
|
@ -125,7 +125,7 @@ static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
|
|||
break;
|
||||
|
||||
base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE;
|
||||
stream_count = be32_to_cpu(reg[1]);
|
||||
stream_count = min_t(unsigned int, be32_to_cpu(reg[1]), MAX_STREAMS);
|
||||
err = read_stream_entries(dice, section_addr, base_offset,
|
||||
stream_count,
|
||||
mode, dice->rx_pcm_chs,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// dice-teac.c - a part of driver for DICE based devices
|
||||
//
|
||||
// Copyright (c) 2025 Takashi Sakamoto
|
||||
|
||||
#include "dice.h"
|
||||
|
||||
int snd_dice_detect_teac_formats(struct snd_dice *dice)
|
||||
{
|
||||
__be32 reg;
|
||||
u32 data;
|
||||
int err;
|
||||
|
||||
err = snd_dice_transaction_read_tx(dice, TX_NUMBER, ®, sizeof(reg));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
dice->tx_pcm_chs[0][SND_DICE_RATE_MODE_LOW] = 16;
|
||||
dice->tx_pcm_chs[0][SND_DICE_RATE_MODE_MIDDLE] = 16;
|
||||
dice->tx_midi_ports[0] = 1;
|
||||
|
||||
data = be32_to_cpu(reg);
|
||||
if (data > 1) {
|
||||
dice->tx_pcm_chs[1][SND_DICE_RATE_MODE_LOW] = 16;
|
||||
dice->tx_pcm_chs[1][SND_DICE_RATE_MODE_MIDDLE] = 16;
|
||||
}
|
||||
|
||||
err = snd_dice_transaction_read_rx(dice, RX_NUMBER, ®, sizeof(reg));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
dice->rx_pcm_chs[0][SND_DICE_RATE_MODE_LOW] = 16;
|
||||
dice->rx_pcm_chs[0][SND_DICE_RATE_MODE_MIDDLE] = 16;
|
||||
dice->rx_midi_ports[0] = 1;
|
||||
|
||||
data = be32_to_cpu(reg);
|
||||
if (data > 1) {
|
||||
dice->rx_pcm_chs[1][SND_DICE_RATE_MODE_LOW] = 16;
|
||||
dice->rx_pcm_chs[1][SND_DICE_RATE_MODE_MIDDLE] = 16;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ MODULE_LICENSE("GPL");
|
|||
#define OUI_PRESONUS 0x000a92
|
||||
#define OUI_HARMAN 0x000fd7
|
||||
#define OUI_AVID 0x00a07e
|
||||
#define OUI_TEAC 0x00022e
|
||||
|
||||
#define DICE_CATEGORY_ID 0x04
|
||||
#define WEISS_CATEGORY_ID 0x00
|
||||
|
|
@ -458,6 +459,18 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
.match_flags = IEEE1394_MATCH_VERSION,
|
||||
.version = DICE_INTERFACE,
|
||||
},
|
||||
// Tascam IF-FW/DM MkII for DM-3200 and DM-4800.
|
||||
{
|
||||
.match_flags = IEEE1394_MATCH_VENDOR_ID |
|
||||
IEEE1394_MATCH_MODEL_ID |
|
||||
IEEE1394_MATCH_SPECIFIER_ID |
|
||||
IEEE1394_MATCH_VERSION,
|
||||
.vendor_id = OUI_TEAC,
|
||||
.model_id = OUI_TEAC,
|
||||
.specifier_id = OUI_TEAC,
|
||||
.version = 0x800006,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_teac_formats,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
|
||||
|
|
|
|||
|
|
@ -233,5 +233,6 @@ int snd_dice_detect_presonus_formats(struct snd_dice *dice);
|
|||
int snd_dice_detect_harman_formats(struct snd_dice *dice);
|
||||
int snd_dice_detect_focusrite_pro40_tcd3070_formats(struct snd_dice *dice);
|
||||
int snd_dice_detect_weiss_formats(struct snd_dice *dice);
|
||||
int snd_dice_detect_teac_formats(struct snd_dice *dice);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -3406,7 +3406,42 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
|
|||
spec->power_hook = alc287_s4_power_gpio3_default;
|
||||
spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
|
||||
}
|
||||
/* GPIO2: mute led GPIO3: micmute led */
|
||||
static void alc245_tas2781_spi_hp_fixup_muteled(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
static const hda_nid_t conn[] = { 0x02 };
|
||||
|
||||
switch (action) {
|
||||
case HDA_FIXUP_ACT_PRE_PROBE:
|
||||
spec->gen.auto_mute_via_amp = 1;
|
||||
snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
|
||||
break;
|
||||
}
|
||||
|
||||
tas2781_fixup_spi(codec, fix, action);
|
||||
alc_fixup_hp_gpio_led(codec, action, 0x04, 0x0);
|
||||
alc285_fixup_hp_coef_micmute_led(codec, fix, action);
|
||||
}
|
||||
/* JD2: mute led GPIO3: micmute led */
|
||||
static void alc245_tas2781_i2c_hp_fixup_muteled(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
static const hda_nid_t conn[] = { 0x02 };
|
||||
|
||||
switch (action) {
|
||||
case HDA_FIXUP_ACT_PRE_PROBE:
|
||||
spec->gen.auto_mute_via_amp = 1;
|
||||
snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
|
||||
break;
|
||||
}
|
||||
|
||||
tas2781_fixup_txnw_i2c(codec, fix, action);
|
||||
alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
|
||||
alc285_fixup_hp_coef_micmute_led(codec, fix, action);
|
||||
}
|
||||
/*
|
||||
* Clear COEF 0x0d (PCBEEP passthrough) bit 0x40 where BIOS sets it wrongly
|
||||
* at PM resume
|
||||
|
|
@ -3418,6 +3453,21 @@ static void alc283_fixup_dell_hp_resume(struct hda_codec *codec,
|
|||
alc_write_coef_idx(codec, 0xd, 0x2800);
|
||||
}
|
||||
|
||||
/* Swap DAC assignments for HP and speaker */
|
||||
static void alc288_fixup_surface_swap_dacs(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
static hda_nid_t preferred_pairs[] = {
|
||||
0x21, 0x03, 0x14, 0x02, 0
|
||||
};
|
||||
|
||||
if (action != HDA_FIXUP_ACT_PRE_PROBE)
|
||||
return;
|
||||
|
||||
spec->gen.preferred_dacs = preferred_pairs;
|
||||
}
|
||||
|
||||
enum {
|
||||
ALC269_FIXUP_GPIO2,
|
||||
ALC269_FIXUP_SONY_VAIO,
|
||||
|
|
@ -3737,6 +3787,10 @@ enum {
|
|||
ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
|
||||
ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK,
|
||||
ALC256_FIXUP_VAIO_RPL_MIC_NO_PRESENCE,
|
||||
ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED,
|
||||
ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED,
|
||||
ALC288_FIXUP_SURFACE_SWAP_DACS,
|
||||
ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO,
|
||||
};
|
||||
|
||||
/* A special fixup for Lenovo C940 and Yoga Duet 7;
|
||||
|
|
@ -5270,6 +5324,12 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc236_fixup_hp_mute_led_micmute_vref,
|
||||
},
|
||||
[ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc236_fixup_hp_mute_led_coefbit2,
|
||||
.chained = true,
|
||||
.chain_id = ALC236_FIXUP_HP_GPIO_LED,
|
||||
},
|
||||
[ALC236_FIXUP_LENOVO_INV_DMIC] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_inv_dmic,
|
||||
|
|
@ -6183,7 +6243,19 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
},
|
||||
.chained = true,
|
||||
.chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
|
||||
}
|
||||
},
|
||||
[ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc245_tas2781_spi_hp_fixup_muteled,
|
||||
},
|
||||
[ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc245_tas2781_i2c_hp_fixup_muteled,
|
||||
},
|
||||
[ALC288_FIXUP_SURFACE_SWAP_DACS] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc288_fixup_surface_swap_dacs,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
|
|
@ -6526,6 +6598,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
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),
|
||||
|
|
@ -6696,15 +6770,29 @@ 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, 0x8ed5, "HP Merino13X", ALC245_FIXUP_TAS2781_SPI_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8ed6, "HP Merino13", ALC245_FIXUP_TAS2781_SPI_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8ed7, "HP Merino14", ALC245_FIXUP_TAS2781_SPI_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8ed8, "HP Merino16", ALC245_FIXUP_TAS2781_SPI_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8ed9, "HP Merino14W", ALC245_FIXUP_TAS2781_SPI_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8eda, "HP Merino16W", ALC245_FIXUP_TAS2781_SPI_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f40, "HP Lampas14", ALC287_FIXUP_TXNW2781_I2C),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f41, "HP Lampas16", ALC287_FIXUP_TXNW2781_I2C),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f42, "HP LampasW14", ALC287_FIXUP_TXNW2781_I2C),
|
||||
SND_PCI_QUIRK(0x103c, 0x8eb6, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||
SND_PCI_QUIRK(0x103c, 0x8eb7, "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, 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, 0x8f62, "HP ZBook 8 G2a 16W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
|
||||
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),
|
||||
|
|
@ -6736,6 +6824,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1043, 0x1314, "ASUS GA605K", ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1384, "ASUS RC73XA", ALC287_FIXUP_TXNW2781_I2C),
|
||||
SND_PCI_QUIRK(0x1043, 0x1394, "ASUS RC73YA", ALC287_FIXUP_TXNW2781_I2C),
|
||||
SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
|
||||
SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
|
||||
|
|
@ -6883,6 +6973,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
|
||||
SND_PCI_QUIRK(0x10ec, 0x12f6, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
|
||||
SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1414, 0x9c20, "Microsoft Surface Pro 2/3", ALC288_FIXUP_SURFACE_SWAP_DACS),
|
||||
SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
|
||||
SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
|
||||
SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -548,20 +548,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
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(cs35l56->base.dev, "Calibration applied\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
|
||||
|
|
@ -669,7 +673,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 +701,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 +822,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 +838,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,7 +1154,7 @@ 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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {
|
|||
|
||||
static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
|
||||
{
|
||||
struct gpio_desc *speaker_id;
|
||||
struct acpi_device *adev;
|
||||
struct device *physdev;
|
||||
LIST_HEAD(resources);
|
||||
|
|
@ -119,19 +120,31 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
|
|||
/* Speaker id was needed for ASUS projects. */
|
||||
ret = kstrtou32(sub, 16, &subid);
|
||||
if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
|
||||
ret = devm_acpi_dev_add_driver_gpios(p->dev,
|
||||
tas2781_speaker_id_gpios);
|
||||
if (ret < 0)
|
||||
ret = acpi_dev_add_driver_gpios(adev, tas2781_speaker_id_gpios);
|
||||
if (ret < 0) {
|
||||
dev_err(p->dev, "Failed to add driver gpio %d.\n",
|
||||
ret);
|
||||
p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN);
|
||||
if (IS_ERR(p->speaker_id)) {
|
||||
dev_err(p->dev, "Failed to get Speaker id.\n");
|
||||
ret = PTR_ERR(p->speaker_id);
|
||||
goto err;
|
||||
p->speaker_id = -1;
|
||||
goto end_2563;
|
||||
}
|
||||
|
||||
speaker_id = fwnode_gpiod_get_index(acpi_fwnode_handle(adev),
|
||||
"speakerid", 0, GPIOD_IN, NULL);
|
||||
if (!IS_ERR(speaker_id)) {
|
||||
p->speaker_id = gpiod_get_value_cansleep(speaker_id);
|
||||
dev_dbg(p->dev, "Got speaker id gpio from ACPI: %d.\n",
|
||||
p->speaker_id);
|
||||
gpiod_put(speaker_id);
|
||||
} else {
|
||||
p->speaker_id = NULL;
|
||||
p->speaker_id = -1;
|
||||
ret = PTR_ERR(speaker_id);
|
||||
dev_err(p->dev, "Get speaker id gpio failed %d.\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
acpi_dev_remove_driver_gpios(adev);
|
||||
} else {
|
||||
p->speaker_id = -1;
|
||||
}
|
||||
|
||||
end_2563:
|
||||
|
|
@ -432,23 +445,16 @@ static void tasdevice_dspfw_init(void *context)
|
|||
struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
|
||||
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
|
||||
struct hda_codec *codec = tas_priv->codec;
|
||||
int ret, spk_id;
|
||||
int ret;
|
||||
|
||||
tasdevice_dsp_remove(tas_priv);
|
||||
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
|
||||
if (tas_priv->speaker_id != NULL) {
|
||||
// Speaker id need to be checked for ASUS only.
|
||||
spk_id = gpiod_get_value(tas_priv->speaker_id);
|
||||
if (spk_id < 0) {
|
||||
// Speaker id is not valid, use default.
|
||||
dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id);
|
||||
spk_id = 0;
|
||||
}
|
||||
if (tas_priv->speaker_id >= 0) {
|
||||
snprintf(tas_priv->coef_binaryname,
|
||||
sizeof(tas_priv->coef_binaryname),
|
||||
"TAS2XXX%04X%d.bin",
|
||||
lower_16_bits(codec->core.subsystem_id),
|
||||
spk_id);
|
||||
tas_priv->speaker_id);
|
||||
} else {
|
||||
snprintf(tas_priv->coef_binaryname,
|
||||
sizeof(tas_priv->coef_binaryname),
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue