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-h6-i2s
|
||||||
- const: allwinner,sun50i-r329-i2s
|
- const: allwinner,sun50i-r329-i2s
|
||||||
- items:
|
- items:
|
||||||
- const: allwinner,sun20i-d1-i2s
|
- enum:
|
||||||
|
- allwinner,sun20i-d1-i2s
|
||||||
|
- allwinner,sun55i-a523-i2s
|
||||||
- const: allwinner,sun50i-r329-i2s
|
- const: allwinner,sun50i-r329-i2s
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ properties:
|
||||||
- const: allwinner,sun8i-h3-spdif
|
- const: allwinner,sun8i-h3-spdif
|
||||||
- const: allwinner,sun50i-h6-spdif
|
- const: allwinner,sun50i-h6-spdif
|
||||||
- const: allwinner,sun50i-h616-spdif
|
- const: allwinner,sun50i-h616-spdif
|
||||||
|
- const: allwinner,sun55i-a523-spdif
|
||||||
- items:
|
- items:
|
||||||
- const: allwinner,sun8i-a83t-spdif
|
- const: allwinner,sun8i-a83t-spdif
|
||||||
- const: allwinner,sun8i-h3-spdif
|
- const: allwinner,sun8i-h3-spdif
|
||||||
|
|
@ -37,14 +38,12 @@ properties:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
clocks:
|
clocks:
|
||||||
items:
|
minItems: 2
|
||||||
- description: Bus Clock
|
maxItems: 3
|
||||||
- description: Module Clock
|
|
||||||
|
|
||||||
clock-names:
|
clock-names:
|
||||||
items:
|
minItems: 2
|
||||||
- const: apb
|
maxItems: 3
|
||||||
- const: spdif
|
|
||||||
|
|
||||||
# Even though it only applies to subschemas under the conditionals,
|
# Even though it only applies to subschemas under the conditionals,
|
||||||
# not listing them here will trigger a warning because of the
|
# not listing them here will trigger a warning because of the
|
||||||
|
|
@ -65,6 +64,7 @@ allOf:
|
||||||
- allwinner,sun8i-h3-spdif
|
- allwinner,sun8i-h3-spdif
|
||||||
- allwinner,sun50i-h6-spdif
|
- allwinner,sun50i-h6-spdif
|
||||||
- allwinner,sun50i-h616-spdif
|
- allwinner,sun50i-h616-spdif
|
||||||
|
- allwinner,sun55i-a523-spdif
|
||||||
|
|
||||||
then:
|
then:
|
||||||
required:
|
required:
|
||||||
|
|
@ -98,6 +98,38 @@ allOf:
|
||||||
- const: rx
|
- const: rx
|
||||||
- const: tx
|
- 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:
|
required:
|
||||||
- "#sound-dai-cells"
|
- "#sound-dai-cells"
|
||||||
- compatible
|
- compatible
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,16 @@ properties:
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
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-cpha: true
|
||||||
|
|
||||||
spi-cpol: true
|
spi-cpol: true
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,15 @@ description:
|
||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: dai-common.yaml#
|
- $ref: dai-common.yaml#
|
||||||
|
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
enum:
|
enum:
|
||||||
|
- cirrus,cs4282
|
||||||
|
- cirrus,cs4302
|
||||||
|
- cirrus,cs4304
|
||||||
|
- cirrus,cs4308
|
||||||
- cirrus,cs5302
|
- cirrus,cs5302
|
||||||
- cirrus,cs5304
|
- cirrus,cs5304
|
||||||
- cirrus,cs5308
|
- cirrus,cs5308
|
||||||
|
|
@ -26,6 +31,9 @@ properties:
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
spi-max-frequency:
|
||||||
|
maximum: 24000000
|
||||||
|
|
||||||
'#sound-dai-cells':
|
'#sound-dai-cells':
|
||||||
const: 1
|
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,46 +67,72 @@ properties:
|
||||||
$ref: audio-graph-port.yaml#
|
$ref: audio-graph-port.yaml#
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
if:
|
allOf:
|
||||||
properties:
|
- if:
|
||||||
compatible:
|
properties:
|
||||||
contains:
|
compatible:
|
||||||
const: nvidia,tegra210-admaif
|
contains:
|
||||||
|
const: nvidia,tegra210-admaif
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
dmas:
|
||||||
|
description:
|
||||||
|
DMA channel specifiers, equally divided for Tx and Rx.
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 20
|
||||||
|
dma-names:
|
||||||
|
items:
|
||||||
|
pattern: "^[rt]x(10|[1-9])$"
|
||||||
|
description:
|
||||||
|
Should be "rx1", "rx2" ... "rx10" for DMA Rx channel
|
||||||
|
Should be "tx1", "tx2" ... "tx10" for DMA Tx channel
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 20
|
||||||
|
interconnects: false
|
||||||
|
interconnect-names: false
|
||||||
|
iommus: false
|
||||||
|
|
||||||
then:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
dmas:
|
compatible:
|
||||||
description:
|
contains:
|
||||||
DMA channel specifiers, equally divided for Tx and Rx.
|
const: nvidia,tegra186-admaif
|
||||||
minItems: 1
|
then:
|
||||||
maxItems: 20
|
properties:
|
||||||
dma-names:
|
dmas:
|
||||||
items:
|
description:
|
||||||
pattern: "^[rt]x(10|[1-9])$"
|
DMA channel specifiers, equally divided for Tx and Rx.
|
||||||
description:
|
minItems: 1
|
||||||
Should be "rx1", "rx2" ... "rx10" for DMA Rx channel
|
maxItems: 40
|
||||||
Should be "tx1", "tx2" ... "tx10" for DMA Tx channel
|
dma-names:
|
||||||
minItems: 1
|
items:
|
||||||
maxItems: 20
|
pattern: "^[rt]x(1[0-9]|[1-9]|20)$"
|
||||||
interconnects: false
|
description:
|
||||||
interconnect-names: false
|
Should be "rx1", "rx2" ... "rx20" for DMA Rx channel
|
||||||
iommus: false
|
Should be "tx1", "tx2" ... "tx20" for DMA Tx channel
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 40
|
||||||
|
|
||||||
else:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
dmas:
|
compatible:
|
||||||
description:
|
contains:
|
||||||
DMA channel specifiers, equally divided for Tx and Rx.
|
const: nvidia,tegra264-admaif
|
||||||
minItems: 1
|
then:
|
||||||
maxItems: 40
|
properties:
|
||||||
dma-names:
|
dmas:
|
||||||
items:
|
description:
|
||||||
pattern: "^[rt]x(1[0-9]|[1-9]|20)$"
|
DMA channel specifiers, equally divided for Tx and Rx.
|
||||||
description:
|
minItems: 1
|
||||||
Should be "rx1", "rx2" ... "rx20" for DMA Rx channel
|
maxItems: 64
|
||||||
Should be "tx1", "tx2" ... "tx20" for DMA Tx channel
|
dma-names:
|
||||||
minItems: 1
|
items:
|
||||||
maxItems: 40
|
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:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
|
|
|
||||||
|
|
@ -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:
|
oneOf:
|
||||||
- enum:
|
- enum:
|
||||||
- qcom,sc7280-lpass-rx-macro
|
- qcom,sc7280-lpass-rx-macro
|
||||||
|
- qcom,sm6115-lpass-rx-macro
|
||||||
- qcom,sm8250-lpass-rx-macro
|
- qcom,sm8250-lpass-rx-macro
|
||||||
- qcom,sm8450-lpass-rx-macro
|
- qcom,sm8450-lpass-rx-macro
|
||||||
- qcom,sm8550-lpass-rx-macro
|
- qcom,sm8550-lpass-rx-macro
|
||||||
- qcom,sc8280xp-lpass-rx-macro
|
- qcom,sc8280xp-lpass-rx-macro
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
|
- qcom,kaanapali-lpass-rx-macro
|
||||||
- qcom,sm8650-lpass-rx-macro
|
- qcom,sm8650-lpass-rx-macro
|
||||||
- qcom,sm8750-lpass-rx-macro
|
- qcom,sm8750-lpass-rx-macro
|
||||||
- qcom,x1e80100-lpass-rx-macro
|
- qcom,x1e80100-lpass-rx-macro
|
||||||
|
|
@ -80,6 +82,23 @@ allOf:
|
||||||
- const: npl
|
- const: npl
|
||||||
- const: fsgen
|
- 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:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ properties:
|
||||||
- qcom,sc8280xp-lpass-tx-macro
|
- qcom,sc8280xp-lpass-tx-macro
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
|
- qcom,kaanapali-lpass-tx-macro
|
||||||
- qcom,sm8650-lpass-tx-macro
|
- qcom,sm8650-lpass-tx-macro
|
||||||
- qcom,sm8750-lpass-tx-macro
|
- qcom,sm8750-lpass-tx-macro
|
||||||
- qcom,x1e80100-lpass-tx-macro
|
- qcom,x1e80100-lpass-tx-macro
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ properties:
|
||||||
oneOf:
|
oneOf:
|
||||||
- enum:
|
- enum:
|
||||||
- qcom,sc7280-lpass-va-macro
|
- qcom,sc7280-lpass-va-macro
|
||||||
|
- qcom,sm6115-lpass-va-macro
|
||||||
- qcom,sm8250-lpass-va-macro
|
- qcom,sm8250-lpass-va-macro
|
||||||
- qcom,sm8450-lpass-va-macro
|
- qcom,sm8450-lpass-va-macro
|
||||||
- qcom,sm8550-lpass-va-macro
|
- qcom,sm8550-lpass-va-macro
|
||||||
|
|
@ -21,6 +22,7 @@ properties:
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
- qcom,glymur-lpass-va-macro
|
- qcom,glymur-lpass-va-macro
|
||||||
|
- qcom,kaanapali-lpass-va-macro
|
||||||
- qcom,sm8650-lpass-va-macro
|
- qcom,sm8650-lpass-va-macro
|
||||||
- qcom,sm8750-lpass-va-macro
|
- qcom,sm8750-lpass-va-macro
|
||||||
- qcom,x1e80100-lpass-va-macro
|
- qcom,x1e80100-lpass-va-macro
|
||||||
|
|
@ -41,11 +43,7 @@ properties:
|
||||||
|
|
||||||
clock-names:
|
clock-names:
|
||||||
minItems: 1
|
minItems: 1
|
||||||
items:
|
maxItems: 4
|
||||||
- const: mclk
|
|
||||||
- const: macro
|
|
||||||
- const: dcodec
|
|
||||||
- const: npl
|
|
||||||
|
|
||||||
clock-output-names:
|
clock-output-names:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
@ -90,16 +88,33 @@ allOf:
|
||||||
clocks:
|
clocks:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
clock-names:
|
clock-names:
|
||||||
maxItems: 1
|
items:
|
||||||
|
- const: mclk
|
||||||
else:
|
else:
|
||||||
properties:
|
properties:
|
||||||
clocks:
|
clocks:
|
||||||
minItems: 3
|
minItems: 3
|
||||||
maxItems: 3
|
maxItems: 3
|
||||||
clock-names:
|
clock-names:
|
||||||
minItems: 3
|
items:
|
||||||
maxItems: 3
|
- 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:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
|
|
@ -111,8 +126,10 @@ allOf:
|
||||||
minItems: 3
|
minItems: 3
|
||||||
maxItems: 3
|
maxItems: 3
|
||||||
clock-names:
|
clock-names:
|
||||||
minItems: 3
|
items:
|
||||||
maxItems: 3
|
- const: mclk
|
||||||
|
- const: macro
|
||||||
|
- const: dcodec
|
||||||
|
|
||||||
- if:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -127,8 +144,11 @@ allOf:
|
||||||
minItems: 4
|
minItems: 4
|
||||||
maxItems: 4
|
maxItems: 4
|
||||||
clock-names:
|
clock-names:
|
||||||
minItems: 4
|
items:
|
||||||
maxItems: 4
|
- const: mclk
|
||||||
|
- const: macro
|
||||||
|
- const: dcodec
|
||||||
|
- const: npl
|
||||||
|
|
||||||
- if:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -142,8 +162,10 @@ allOf:
|
||||||
minItems: 3
|
minItems: 3
|
||||||
maxItems: 3
|
maxItems: 3
|
||||||
clock-names:
|
clock-names:
|
||||||
minItems: 3
|
items:
|
||||||
maxItems: 3
|
- const: mclk
|
||||||
|
- const: macro
|
||||||
|
- const: dcodec
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ properties:
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
- qcom,glymur-lpass-wsa-macro
|
- qcom,glymur-lpass-wsa-macro
|
||||||
|
- qcom,kaanapali-lpass-wsa-macro
|
||||||
- qcom,sm8650-lpass-wsa-macro
|
- qcom,sm8650-lpass-wsa-macro
|
||||||
- qcom,sm8750-lpass-wsa-macro
|
- qcom,sm8750-lpass-wsa-macro
|
||||||
- qcom,x1e80100-lpass-wsa-macro
|
- qcom,x1e80100-lpass-wsa-macro
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ properties:
|
||||||
- const: qcom,sdm845-sndcard
|
- const: qcom,sdm845-sndcard
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
|
- qcom,kaanapali-sndcard
|
||||||
- qcom,sm8550-sndcard
|
- qcom,sm8550-sndcard
|
||||||
- qcom,sm8650-sndcard
|
- qcom,sm8650-sndcard
|
||||||
- qcom,sm8750-sndcard
|
- qcom,sm8750-sndcard
|
||||||
|
|
@ -38,6 +39,7 @@ properties:
|
||||||
- qcom,qcs8275-sndcard
|
- qcom,qcs8275-sndcard
|
||||||
- qcom,qcs9075-sndcard
|
- qcom,qcs9075-sndcard
|
||||||
- qcom,qcs9100-sndcard
|
- qcom,qcs9100-sndcard
|
||||||
|
- qcom,qrb2210-sndcard
|
||||||
- qcom,qrb4210-rb2-sndcard
|
- qcom,qrb4210-rb2-sndcard
|
||||||
- qcom,qrb5165-rb5-sndcard
|
- qcom,qrb5165-rb5-sndcard
|
||||||
- qcom,sc7180-qdsp6-sndcard
|
- qcom,sc7180-qdsp6-sndcard
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ properties:
|
||||||
$ref: /schemas/gpio/qcom,wcd934x-gpio.yaml#
|
$ref: /schemas/gpio/qcom,wcd934x-gpio.yaml#
|
||||||
|
|
||||||
patternProperties:
|
patternProperties:
|
||||||
"^.*@[0-9a-f]+$":
|
"@[0-9a-f]+$":
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
description: |
|
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
|
Instruments Smart Amp speaker protection algorithm. The
|
||||||
integrated speaker voltage and current sense provides for real time
|
integrated speaker voltage and current sense provides for real time
|
||||||
monitoring of loudspeaker behavior.
|
monitoring of loudspeaker behavior.
|
||||||
The TAS5802/TAS5815/TAS5825/TAS5827/TAS5828 is a stereo, digital input
|
The TAS5802/TAS5815/TAS5822/TAS5825/TAS5827/TAS5828 is a stereo,
|
||||||
Class-D audio amplifier optimized for efficiently driving high peak
|
digital input Class-D audio amplifier optimized for efficiently driving
|
||||||
power into small loudspeakers. An integrated on-chip DSP supports
|
high peak power into small loudspeakers. An integrated on-chip DSP
|
||||||
Texas Instruments Smart Amp speaker protection algorithm.
|
supports Texas Instruments Smart Amp speaker protection algorithm.
|
||||||
|
|
||||||
Specifications about the audio amplifier can be found at:
|
Specifications about the audio amplifier can be found at:
|
||||||
https://www.ti.com/lit/gpn/tas2120
|
https://www.ti.com/lit/gpn/tas2120
|
||||||
https://www.ti.com/lit/gpn/tas2320
|
https://www.ti.com/lit/gpn/tas2320
|
||||||
https://www.ti.com/lit/gpn/tas2563
|
https://www.ti.com/lit/gpn/tas2563
|
||||||
https://www.ti.com/lit/gpn/tas2572
|
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/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/tas5815
|
||||||
|
https://www.ti.com/lit/gpn/tas5822m
|
||||||
https://www.ti.com/lit/gpn/tas5825m
|
https://www.ti.com/lit/gpn/tas5825m
|
||||||
https://www.ti.com/lit/gpn/tas5827
|
https://www.ti.com/lit/gpn/tas5827
|
||||||
https://www.ti.com/lit/gpn/tas5828m
|
https://www.ti.com/lit/gpn/tas5828m
|
||||||
|
https://www.ti.com/lit/gpn/tas5830
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
|
|
@ -57,12 +62,18 @@ properties:
|
||||||
ti,tas2563: 6.1-W Boosted Class-D Audio Amplifier With Integrated
|
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.
|
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
|
ti,tas2570: 5.8-W Digital Input smart amp with I/V sense and integrated
|
||||||
11-V Class-H Boost
|
11-V Class-H Boost
|
||||||
|
|
||||||
ti,tas2572: 6.6-W Digital Input smart amp with I/V sense and integrated
|
ti,tas2572: 6.6-W Digital Input smart amp with I/V sense and integrated
|
||||||
13-V Class-H Boost
|
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
|
ti,tas2781: 24-V Class-D Amplifier with Real Time Integrated Speaker
|
||||||
Protection and Audio Processing, 16/20/24/32bit stereo I2S or
|
Protection and Audio Processing, 16/20/24/32bit stereo I2S or
|
||||||
multichannel TDM.
|
multichannel TDM.
|
||||||
|
|
@ -71,9 +82,20 @@ properties:
|
||||||
Audio Amplifier with 96-Khz Extended Processing and Low Idle Power
|
Audio Amplifier with 96-Khz Extended Processing and Low Idle Power
|
||||||
Dissipation.
|
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
|
ti,tas5815: 30-W, Digital Input, Stereo, Closed-loop Class-D Audio
|
||||||
Amplifier with 96 kHz Enhanced Processing
|
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
|
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.
|
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
|
ti,tas5828: 50-W Stereo, Digital Input, High Efficiency Closed-Loop
|
||||||
Class-D Amplifier with Hybrid-Pro Algorithm
|
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:
|
oneOf:
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
|
|
@ -90,13 +115,19 @@ properties:
|
||||||
- ti,tas2120
|
- ti,tas2120
|
||||||
- ti,tas2320
|
- ti,tas2320
|
||||||
- ti,tas2563
|
- ti,tas2563
|
||||||
|
- ti,tas2568
|
||||||
- ti,tas2570
|
- ti,tas2570
|
||||||
- ti,tas2572
|
- ti,tas2572
|
||||||
|
- ti,tas2574
|
||||||
- ti,tas5802
|
- ti,tas5802
|
||||||
|
- ti,tas5806m
|
||||||
|
- ti,tas5806md
|
||||||
- ti,tas5815
|
- ti,tas5815
|
||||||
|
- ti,tas5822
|
||||||
- ti,tas5825
|
- ti,tas5825
|
||||||
- ti,tas5827
|
- ti,tas5827
|
||||||
- ti,tas5828
|
- ti,tas5828
|
||||||
|
- ti,tas5830
|
||||||
- const: ti,tas2781
|
- const: ti,tas2781
|
||||||
- enum:
|
- enum:
|
||||||
- ti,tas2781
|
- ti,tas2781
|
||||||
|
|
@ -132,6 +163,8 @@ allOf:
|
||||||
- ti,tas2118
|
- ti,tas2118
|
||||||
- ti,tas2120
|
- ti,tas2120
|
||||||
- ti,tas2320
|
- ti,tas2320
|
||||||
|
- ti,tas2568
|
||||||
|
- ti,tas2574
|
||||||
then:
|
then:
|
||||||
properties:
|
properties:
|
||||||
reg:
|
reg:
|
||||||
|
|
@ -207,6 +240,22 @@ allOf:
|
||||||
minimum: 0x54
|
minimum: 0x54
|
||||||
maximum: 0x57
|
maximum: 0x57
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- ti,tas5806m
|
||||||
|
- ti,tas5806md
|
||||||
|
- ti,tas5822
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
maxItems: 4
|
||||||
|
items:
|
||||||
|
minimum: 0x2c
|
||||||
|
maximum: 0x2f
|
||||||
|
|
||||||
- if:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
|
|
@ -214,6 +263,7 @@ allOf:
|
||||||
enum:
|
enum:
|
||||||
- ti,tas5827
|
- ti,tas5827
|
||||||
- ti,tas5828
|
- ti,tas5828
|
||||||
|
- ti,tas5830
|
||||||
then:
|
then:
|
||||||
properties:
|
properties:
|
||||||
reg:
|
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: http://wiki.analog.com/
|
||||||
W: https://ez.analog.com/linux-software-drivers
|
W: https://ez.analog.com/linux-software-drivers
|
||||||
F: Documentation/devicetree/bindings/sound/adi,*
|
F: Documentation/devicetree/bindings/sound/adi,*
|
||||||
|
F: Documentation/devicetree/bindings/sound/trivial-codec.yaml
|
||||||
F: sound/soc/codecs/ad1*
|
F: sound/soc/codecs/ad1*
|
||||||
F: sound/soc/codecs/ad7*
|
F: sound/soc/codecs/ad7*
|
||||||
F: sound/soc/codecs/adau*
|
F: sound/soc/codecs/adau*
|
||||||
|
|
@ -2421,9 +2422,9 @@ M: Martin Povišer <povik+lin@cutebit.org>
|
||||||
L: asahi@lists.linux.dev
|
L: asahi@lists.linux.dev
|
||||||
L: linux-sound@vger.kernel.org
|
L: linux-sound@vger.kernel.org
|
||||||
S: Maintained
|
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/apple,*
|
||||||
|
F: Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml
|
||||||
|
F: Documentation/devicetree/bindings/sound/trivial-codec.yaml
|
||||||
F: sound/soc/apple/*
|
F: sound/soc/apple/*
|
||||||
F: sound/soc/codecs/cs42l83-i2c.c
|
F: sound/soc/codecs/cs42l83-i2c.c
|
||||||
F: sound/soc/codecs/cs42l84.*
|
F: sound/soc/codecs/cs42l84.*
|
||||||
|
|
@ -18749,7 +18750,7 @@ NXP TFA9879 DRIVER
|
||||||
M: Peter Rosin <peda@axentia.se>
|
M: Peter Rosin <peda@axentia.se>
|
||||||
L: linux-sound@vger.kernel.org
|
L: linux-sound@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/devicetree/bindings/sound/nxp,tfa9879.yaml
|
F: Documentation/devicetree/bindings/sound/trivial-codec.yaml
|
||||||
F: sound/soc/codecs/tfa9879*
|
F: sound/soc/codecs/tfa9879*
|
||||||
|
|
||||||
NXP-NCI NFC DRIVER
|
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/wlf,arizona.yaml
|
||||||
F: Documentation/devicetree/bindings/mfd/wm831x.txt
|
F: Documentation/devicetree/bindings/mfd/wm831x.txt
|
||||||
F: Documentation/devicetree/bindings/regulator/wlf,arizona.yaml
|
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/wlf,*.yaml
|
||||||
F: Documentation/devicetree/bindings/sound/wm*
|
F: Documentation/devicetree/bindings/sound/wm*
|
||||||
F: Documentation/hwmon/wm83??.rst
|
F: Documentation/hwmon/wm83??.rst
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
struct regmap_mbq_context {
|
struct regmap_mbq_context {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
struct sdw_slave *sdw;
|
||||||
|
|
||||||
struct regmap_sdw_mbq_cfg cfg;
|
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,
|
static int regmap_sdw_mbq_poll_busy(struct sdw_slave *slave, unsigned int reg,
|
||||||
struct regmap_mbq_context *ctx)
|
struct regmap_mbq_context *ctx)
|
||||||
{
|
{
|
||||||
struct device *dev = &slave->dev;
|
struct device *dev = ctx->dev;
|
||||||
int val, ret = 0;
|
int val, ret = 0;
|
||||||
|
|
||||||
dev_dbg(dev, "Deferring transaction for 0x%x\n", reg);
|
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)
|
static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
|
||||||
{
|
{
|
||||||
struct regmap_mbq_context *ctx = context;
|
struct regmap_mbq_context *ctx = context;
|
||||||
struct device *dev = ctx->dev;
|
struct sdw_slave *slave = ctx->sdw;
|
||||||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
|
||||||
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
|
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
|
||||||
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
|
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
|
||||||
int ret;
|
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)
|
static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val)
|
||||||
{
|
{
|
||||||
struct regmap_mbq_context *ctx = context;
|
struct regmap_mbq_context *ctx = context;
|
||||||
struct device *dev = ctx->dev;
|
struct sdw_slave *slave = ctx->sdw;
|
||||||
struct sdw_slave *slave = dev_to_sdw_dev(dev);
|
|
||||||
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
|
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
|
||||||
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
|
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -208,6 +207,7 @@ static int regmap_sdw_mbq_config_check(const struct regmap_config *config)
|
||||||
|
|
||||||
static struct regmap_mbq_context *
|
static struct regmap_mbq_context *
|
||||||
regmap_sdw_mbq_gen_context(struct device *dev,
|
regmap_sdw_mbq_gen_context(struct device *dev,
|
||||||
|
struct sdw_slave *sdw,
|
||||||
const struct regmap_config *config,
|
const struct regmap_config *config,
|
||||||
const struct regmap_sdw_mbq_cfg *mbq_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);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
ctx->dev = dev;
|
ctx->dev = dev;
|
||||||
|
ctx->sdw = sdw;
|
||||||
|
|
||||||
if (mbq_config)
|
if (mbq_config)
|
||||||
ctx->cfg = *mbq_config;
|
ctx->cfg = *mbq_config;
|
||||||
|
|
@ -228,7 +229,7 @@ regmap_sdw_mbq_gen_context(struct device *dev,
|
||||||
return ctx;
|
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_config *config,
|
||||||
const struct regmap_sdw_mbq_cfg *mbq_config,
|
const struct regmap_sdw_mbq_cfg *mbq_config,
|
||||||
struct lock_class_key *lock_key,
|
struct lock_class_key *lock_key,
|
||||||
|
|
@ -241,16 +242,16 @@ struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ERR_PTR(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))
|
if (IS_ERR(ctx))
|
||||||
return ERR_CAST(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);
|
config, lock_key, lock_name);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__regmap_init_sdw_mbq);
|
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_config *config,
|
||||||
const struct regmap_sdw_mbq_cfg *mbq_config,
|
const struct regmap_sdw_mbq_cfg *mbq_config,
|
||||||
struct lock_class_key *lock_key,
|
struct lock_class_key *lock_key,
|
||||||
|
|
@ -263,11 +264,11 @@ struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ERR_PTR(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))
|
if (IS_ERR(ctx))
|
||||||
return ERR_CAST(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);
|
config, lock_key, lock_name);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
|
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,11 @@
|
||||||
* Cirrus Logic International Semiconductor Ltd.
|
* Cirrus Logic International Semiconductor Ltd.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/cleanup.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/math.h>
|
||||||
#include <linux/minmax.h>
|
#include <linux/minmax.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.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_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
|
* cs_dsp_mem_region_name() - Return a name string for a memory type
|
||||||
* @type: the memory type to match
|
* @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
|
#ifdef CONFIG_DEBUG_FS
|
||||||
static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s)
|
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);
|
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)
|
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);
|
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)
|
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;
|
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,
|
static ssize_t cs_dsp_debugfs_wmfw_read(struct file *file,
|
||||||
char __user *user_buf,
|
char __user *user_buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct cs_dsp *dsp = file->private_data;
|
struct cs_dsp *dsp = file->private_data;
|
||||||
ssize_t ret;
|
|
||||||
|
|
||||||
mutex_lock(&dsp->pwr_lock);
|
return cs_dsp_debugfs_string_read(dsp, user_buf, count, ppos,
|
||||||
|
&dsp->wmfw_file_name);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t cs_dsp_debugfs_bin_read(struct file *file,
|
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)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct cs_dsp *dsp = file->private_data;
|
struct cs_dsp *dsp = file->private_data;
|
||||||
ssize_t ret;
|
|
||||||
|
|
||||||
mutex_lock(&dsp->pwr_lock);
|
return cs_dsp_debugfs_string_read(dsp, user_buf, count, ppos,
|
||||||
|
&dsp->bin_file_name);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
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;
|
struct cs_dsp_coeff_ctl *ctl;
|
||||||
unsigned int reg;
|
unsigned int reg;
|
||||||
|
|
||||||
|
guard(mutex)(&dsp->pwr_lock);
|
||||||
|
|
||||||
list_for_each_entry(ctl, &dsp->ctl_list, list) {
|
list_for_each_entry(ctl, &dsp->ctl_list, list) {
|
||||||
cs_dsp_coeff_base_reg(ctl, ®, 0);
|
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,
|
ctl->subname_len, ctl->subname, ctl->len,
|
||||||
cs_dsp_mem_region_name(ctl->alg_region.type),
|
cs_dsp_mem_region_name(ctl->alg_region.type),
|
||||||
ctl->offset, reg, ctl->fw_name, ctl->alg_region.alg, ctl->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)
|
static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl)
|
||||||
{
|
{
|
||||||
kfree(ctl->cache);
|
kvfree(ctl->cache);
|
||||||
kfree(ctl->subname);
|
kfree(ctl->subname);
|
||||||
kfree(ctl);
|
kfree(ctl);
|
||||||
}
|
}
|
||||||
|
|
@ -1078,7 +1039,7 @@ static int cs_dsp_create_control(struct cs_dsp *dsp,
|
||||||
ctl->type = type;
|
ctl->type = type;
|
||||||
ctl->offset = offset;
|
ctl->offset = offset;
|
||||||
ctl->len = len;
|
ctl->len = len;
|
||||||
ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
|
ctl->cache = kvzalloc(ctl->len, GFP_KERNEL);
|
||||||
if (!ctl->cache) {
|
if (!ctl->cache) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_ctl_subname;
|
goto err_ctl_subname;
|
||||||
|
|
@ -1096,7 +1057,7 @@ static int cs_dsp_create_control(struct cs_dsp *dsp,
|
||||||
|
|
||||||
err_list_del:
|
err_list_del:
|
||||||
list_del(&ctl->list);
|
list_del(&ctl->list);
|
||||||
kfree(ctl->cache);
|
kvfree(ctl->cache);
|
||||||
err_ctl_subname:
|
err_ctl_subname:
|
||||||
kfree(ctl->subname);
|
kfree(ctl->subname);
|
||||||
err_ctl:
|
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 wmfw_region *region;
|
||||||
const struct cs_dsp_region *mem;
|
const struct cs_dsp_region *mem;
|
||||||
const char *region_name;
|
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;
|
unsigned int reg;
|
||||||
int regions = 0;
|
int regions = 0;
|
||||||
int ret, offset, type;
|
int ret, offset, type;
|
||||||
|
|
@ -1605,23 +1568,23 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
|
||||||
region_name);
|
region_name);
|
||||||
|
|
||||||
if (reg) {
|
if (reg) {
|
||||||
buf = cs_dsp_buf_alloc(region->data,
|
region_len = le32_to_cpu(region->len);
|
||||||
le32_to_cpu(region->len),
|
if (region_len > buf_len) {
|
||||||
&buf_list);
|
buf_len = round_up(region_len, PAGE_SIZE);
|
||||||
if (!buf) {
|
kfree(buf);
|
||||||
cs_dsp_err(dsp, "Out of memory\n");
|
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
|
||||||
ret = -ENOMEM;
|
if (!buf) {
|
||||||
goto out_fw;
|
ret = -ENOMEM;
|
||||||
|
goto out_fw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = regmap_raw_write(regmap, reg, buf->buf,
|
memcpy(buf, region->data, region_len);
|
||||||
le32_to_cpu(region->len));
|
ret = regmap_raw_write(regmap, reg, buf, region_len);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
cs_dsp_err(dsp,
|
cs_dsp_err(dsp,
|
||||||
"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
|
"%s.%d: Failed to write %zu bytes at %d in %s: %d\n",
|
||||||
file, regions,
|
file, regions, region_len, offset, region_name, ret);
|
||||||
le32_to_cpu(region->len), offset,
|
|
||||||
region_name, ret);
|
|
||||||
goto out_fw;
|
goto out_fw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1638,8 +1601,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out_fw:
|
out_fw:
|
||||||
cs_dsp_buf_free(&buf_list);
|
|
||||||
|
|
||||||
if (ret == -EOVERFLOW)
|
if (ret == -EOVERFLOW)
|
||||||
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
|
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;
|
struct cs_dsp_alg_region *alg_region;
|
||||||
const char *region_name;
|
const char *region_name;
|
||||||
int ret, pos, blocks, type, offset, reg, version;
|
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)
|
if (!firmware)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -2313,20 +2276,22 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg) {
|
if (reg) {
|
||||||
buf = cs_dsp_buf_alloc(blk->data,
|
region_len = le32_to_cpu(blk->len);
|
||||||
le32_to_cpu(blk->len),
|
if (region_len > buf_len) {
|
||||||
&buf_list);
|
buf_len = round_up(region_len, PAGE_SIZE);
|
||||||
if (!buf) {
|
kfree(buf);
|
||||||
cs_dsp_err(dsp, "Out of memory\n");
|
buf = kmalloc(buf_len, GFP_KERNEL | GFP_DMA);
|
||||||
ret = -ENOMEM;
|
if (!buf) {
|
||||||
goto out_fw;
|
ret = -ENOMEM;
|
||||||
|
goto out_fw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cs_dsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
|
memcpy(buf, blk->data, region_len);
|
||||||
file, blocks, le32_to_cpu(blk->len),
|
|
||||||
reg);
|
cs_dsp_dbg(dsp, "%s.%d: Writing %zu bytes at %x\n",
|
||||||
ret = regmap_raw_write(regmap, reg, buf->buf,
|
file, blocks, region_len, reg);
|
||||||
le32_to_cpu(blk->len));
|
ret = regmap_raw_write(regmap, reg, buf, region_len);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
cs_dsp_err(dsp,
|
cs_dsp_err(dsp,
|
||||||
"%s.%d: Failed to write to %x in %s: %d\n",
|
"%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;
|
ret = 0;
|
||||||
out_fw:
|
out_fw:
|
||||||
cs_dsp_buf_free(&buf_list);
|
|
||||||
|
|
||||||
if (ret == -EOVERFLOW)
|
if (ret == -EOVERFLOW)
|
||||||
cs_dsp_err(dsp, "%s: file content overflows file data\n", file);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct cs_dsp_client_ops cs_dsp_default_client_ops = {
|
||||||
|
};
|
||||||
|
|
||||||
static int cs_dsp_common_init(struct cs_dsp *dsp)
|
static int cs_dsp_common_init(struct cs_dsp *dsp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -2379,6 +2345,9 @@ static int cs_dsp_common_init(struct cs_dsp *dsp)
|
||||||
|
|
||||||
mutex_init(&dsp->pwr_lock);
|
mutex_init(&dsp->pwr_lock);
|
||||||
|
|
||||||
|
if (!dsp->client_ops)
|
||||||
|
dsp->client_ops = &cs_dsp_default_client_ops;
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
/* Ensure this is invalid if client never provides a debugfs root */
|
/* Ensure this is invalid if client never provides a debugfs root */
|
||||||
dsp->debugfs_root = ERR_PTR(-ENODEV);
|
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[] = {
|
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 = &cs_dsp_callback_test_empty_client_ops, .case_name = "empty ops" },
|
||||||
|
{ .ops = NULL, .case_name = "NULL ops" },
|
||||||
};
|
};
|
||||||
|
|
||||||
KUNIT_ARRAY_PARAM(cs_dsp_no_callbacks,
|
KUNIT_ARRAY_PARAM(cs_dsp_no_callbacks,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@
|
||||||
config GPIOLIB_LEGACY
|
config GPIOLIB_LEGACY
|
||||||
def_bool y
|
def_bool y
|
||||||
|
|
||||||
|
config HAVE_SHARED_GPIOS
|
||||||
|
bool
|
||||||
|
|
||||||
menuconfig GPIOLIB
|
menuconfig GPIOLIB
|
||||||
bool "GPIO Support"
|
bool "GPIO Support"
|
||||||
help
|
help
|
||||||
|
|
@ -50,6 +53,11 @@ config OF_GPIO_MM_GPIOCHIP
|
||||||
this symbol, but new drivers should use the generic gpio-regmap
|
this symbol, but new drivers should use the generic gpio-regmap
|
||||||
infrastructure instead.
|
infrastructure instead.
|
||||||
|
|
||||||
|
config GPIO_SHARED
|
||||||
|
def_bool y
|
||||||
|
depends on HAVE_SHARED_GPIOS || COMPILE_TEST
|
||||||
|
select AUXILIARY_BUS
|
||||||
|
|
||||||
config DEBUG_GPIO
|
config DEBUG_GPIO
|
||||||
bool "Debug GPIO calls"
|
bool "Debug GPIO calls"
|
||||||
depends on DEBUG_KERNEL
|
depends on DEBUG_KERNEL
|
||||||
|
|
@ -2017,6 +2025,15 @@ config GPIO_SIM
|
||||||
This enables the GPIO simulator - a configfs-based GPIO testing
|
This enables the GPIO simulator - a configfs-based GPIO testing
|
||||||
driver.
|
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
|
endmenu
|
||||||
|
|
||||||
menu "GPIO Debugging utilities"
|
menu "GPIO Debugging utilities"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
|
||||||
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
||||||
gpiolib-acpi-y := gpiolib-acpi-core.o gpiolib-acpi-quirks.o
|
gpiolib-acpi-y := gpiolib-acpi-core.o gpiolib-acpi-quirks.o
|
||||||
obj-$(CONFIG_GPIOLIB) += gpiolib-swnode.o
|
obj-$(CONFIG_GPIOLIB) += gpiolib-swnode.o
|
||||||
|
obj-$(CONFIG_GPIO_SHARED) += gpiolib-shared.o
|
||||||
|
|
||||||
# Device drivers. Generally keep list sorted alphabetically
|
# Device drivers. Generally keep list sorted alphabetically
|
||||||
obj-$(CONFIG_GPIO_REGMAP) += gpio-regmap.o
|
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_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o
|
||||||
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
|
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
|
||||||
obj-$(CONFIG_GPIO_SCH) += gpio-sch.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_SIFIVE) += gpio-sifive.o
|
||||||
obj-$(CONFIG_GPIO_SIM) += gpio-sim.o
|
obj-$(CONFIG_GPIO_SIM) += gpio-sim.o
|
||||||
obj-$(CONFIG_GPIO_SIOX) += gpio-siox.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-acpi.h"
|
||||||
#include "gpiolib-cdev.h"
|
#include "gpiolib-cdev.h"
|
||||||
#include "gpiolib-of.h"
|
#include "gpiolib-of.h"
|
||||||
|
#include "gpiolib-shared.h"
|
||||||
#include "gpiolib-swnode.h"
|
#include "gpiolib-swnode.h"
|
||||||
#include "gpiolib-sysfs.h"
|
#include "gpiolib-sysfs.h"
|
||||||
#include "gpiolib.h"
|
#include "gpiolib.h"
|
||||||
|
|
@ -1200,6 +1201,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_remove_irqchip_mask;
|
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,
|
* By first adding the chardev, and then adding the device,
|
||||||
* we get a device node entry in sysfs under
|
* 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) {
|
if (gpiolib_initialized) {
|
||||||
ret = gpiochip_setup_dev(gdev);
|
ret = gpiochip_setup_dev(gdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_remove_irqchip;
|
goto err_teardown_shared;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_teardown_shared:
|
||||||
|
gpio_device_teardown_shared(gdev);
|
||||||
err_remove_irqchip:
|
err_remove_irqchip:
|
||||||
gpiochip_irqchip_remove(gc);
|
gpiochip_irqchip_remove(gc);
|
||||||
err_remove_irqchip_mask:
|
err_remove_irqchip_mask:
|
||||||
|
|
@ -1283,6 +1291,7 @@ void gpiochip_remove(struct gpio_chip *gc)
|
||||||
/* Numb the device, cancelling all outstanding operations */
|
/* Numb the device, cancelling all outstanding operations */
|
||||||
rcu_assign_pointer(gdev->chip, NULL);
|
rcu_assign_pointer(gdev->chip, NULL);
|
||||||
synchronize_srcu(&gdev->srcu);
|
synchronize_srcu(&gdev->srcu);
|
||||||
|
gpio_device_teardown_shared(gdev);
|
||||||
gpiochip_irqchip_remove(gc);
|
gpiochip_irqchip_remove(gc);
|
||||||
acpi_gpiochip_remove(gc);
|
acpi_gpiochip_remove(gc);
|
||||||
of_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);
|
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
|
* gpiod_to_irq() - return the IRQ corresponding to a GPIO
|
||||||
* @desc: gpio whose IRQ will be returned (already requested)
|
* @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) {
|
scoped_guard(srcu, &gpio_devices_srcu) {
|
||||||
desc = gpiod_fwnode_lookup(fwnode, consumer, con_id, idx,
|
desc = gpiod_fwnode_lookup(fwnode, consumer, con_id, idx,
|
||||||
&flags, &lookupflags);
|
&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) {
|
if (gpiod_not_found(desc) && platform_lookup_allowed) {
|
||||||
/*
|
/*
|
||||||
* Either we are not using DT or ACPI, or their lookup
|
* Either we are not using DT or ACPI, or their lookup
|
||||||
* did not return a result. In that case, use platform
|
* did not return a result or this is a shared GPIO. In
|
||||||
* lookup as a fallback.
|
* that case, use platform lookup as a fallback.
|
||||||
*/
|
*/
|
||||||
dev_dbg(consumer,
|
dev_dbg(consumer,
|
||||||
"using lookup tables for GPIO lookup\n");
|
"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);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This happens when there are several consumers for
|
* This happens when there are several consumers for the same
|
||||||
* the same GPIO line: we just return here without
|
* GPIO line: we just return here without further
|
||||||
* further initialization. It is a bit of a hack.
|
* initialization. It's a hack introduced long ago to support
|
||||||
* This is necessary to support fixed regulators.
|
* 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;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,8 @@ struct gpio_desc {
|
||||||
#define GPIOD_FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */
|
#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_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_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 */
|
/* Connection label */
|
||||||
struct gpio_desc_label __rcu *label;
|
struct gpio_desc_label __rcu *label;
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,6 @@ static void arizona_haptics_work(struct work_struct *work)
|
||||||
struct arizona_haptics,
|
struct arizona_haptics,
|
||||||
work);
|
work);
|
||||||
struct arizona *arizona = haptics->arizona;
|
struct arizona *arizona = haptics->arizona;
|
||||||
struct snd_soc_component *component =
|
|
||||||
snd_soc_dapm_to_component(arizona->dapm);
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!haptics->arizona->dapm) {
|
if (!haptics->arizona->dapm) {
|
||||||
|
|
@ -65,7 +63,7 @@ static void arizona_haptics_work(struct work_struct *work)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = snd_soc_component_enable_pin(component, "HAPTICS");
|
ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
|
dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
|
||||||
ret);
|
ret);
|
||||||
|
|
@ -80,7 +78,7 @@ static void arizona_haptics_work(struct work_struct *work)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* This disable sequence will be a noop if already enabled */
|
/* 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) {
|
if (ret != 0) {
|
||||||
dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
|
dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
|
||||||
ret);
|
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)
|
static void arizona_haptics_close(struct input_dev *input)
|
||||||
{
|
{
|
||||||
struct arizona_haptics *haptics = input_get_drvdata(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);
|
cancel_work_sync(&haptics->work);
|
||||||
|
|
||||||
if (haptics->arizona->dapm) {
|
if (dapm)
|
||||||
component = snd_soc_dapm_to_component(haptics->arizona->dapm);
|
snd_soc_dapm_disable_pin(dapm, "HAPTICS");
|
||||||
snd_soc_component_disable_pin(component, "HAPTICS");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arizona_haptics_probe(struct platform_device *pdev)
|
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 =
|
struct arizona_micsupp *micsupp =
|
||||||
container_of(work, struct arizona_micsupp, check_cp_work);
|
container_of(work, struct arizona_micsupp, check_cp_work);
|
||||||
struct snd_soc_dapm_context *dapm = *micsupp->dapm;
|
struct snd_soc_dapm_context *dapm = *micsupp->dapm;
|
||||||
struct snd_soc_component *component;
|
|
||||||
const struct regulator_desc *desc = micsupp->desc;
|
const struct regulator_desc *desc = micsupp->desc;
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -61,14 +60,11 @@ static void arizona_micsupp_check_cp(struct work_struct *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dapm) {
|
if (dapm) {
|
||||||
component = snd_soc_dapm_to_component(dapm);
|
|
||||||
|
|
||||||
if ((val & (desc->enable_mask | desc->bypass_mask)) ==
|
if ((val & (desc->enable_mask | desc->bypass_mask)) ==
|
||||||
desc->enable_mask)
|
desc->enable_mask)
|
||||||
snd_soc_component_force_enable_pin(component,
|
snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
|
||||||
"MICSUPP");
|
|
||||||
else
|
else
|
||||||
snd_soc_component_disable_pin(component, "MICSUPP");
|
snd_soc_dapm_disable_pin(dapm, "MICSUPP");
|
||||||
|
|
||||||
snd_soc_dapm_sync(dapm);
|
snd_soc_dapm_sync(dapm);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -807,6 +807,7 @@ int gbaudio_register_module(struct gbaudio_module_info *module)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct snd_soc_component *comp;
|
struct snd_soc_component *comp;
|
||||||
|
struct snd_soc_dapm_context *dapm;
|
||||||
struct gbaudio_jack *jack = NULL;
|
struct gbaudio_jack *jack = NULL;
|
||||||
|
|
||||||
if (!gbcodec) {
|
if (!gbcodec) {
|
||||||
|
|
@ -815,6 +816,7 @@ int gbaudio_register_module(struct gbaudio_module_info *module)
|
||||||
}
|
}
|
||||||
|
|
||||||
comp = gbcodec->component;
|
comp = gbcodec->component;
|
||||||
|
dapm = snd_soc_component_to_dapm(comp);
|
||||||
|
|
||||||
mutex_lock(&gbcodec->register_mutex);
|
mutex_lock(&gbcodec->register_mutex);
|
||||||
|
|
||||||
|
|
@ -833,18 +835,18 @@ int gbaudio_register_module(struct gbaudio_module_info *module)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module->dapm_widgets)
|
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);
|
module->num_dapm_widgets);
|
||||||
if (module->controls)
|
if (module->controls)
|
||||||
snd_soc_add_component_controls(comp, module->controls,
|
snd_soc_add_component_controls(comp, module->controls,
|
||||||
module->num_controls);
|
module->num_controls);
|
||||||
if (module->dapm_routes)
|
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);
|
module->num_dapm_routes);
|
||||||
|
|
||||||
/* card already instantiated, create widgets here only */
|
/* card already instantiated, create widgets here only */
|
||||||
if (comp->card->instantiated) {
|
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
|
#ifdef CONFIG_SND_JACK
|
||||||
/*
|
/*
|
||||||
* register jack devices for this module
|
* register jack devices for this module
|
||||||
|
|
@ -966,9 +968,11 @@ void gbaudio_unregister_module(struct gbaudio_module_info *module)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (module->dapm_routes) {
|
if (module->dapm_routes) {
|
||||||
|
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(comp);
|
||||||
|
|
||||||
dev_dbg(comp->dev, "Removing %d routes\n",
|
dev_dbg(comp->dev, "Removing %d routes\n",
|
||||||
module->num_dapm_routes);
|
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);
|
module->num_dapm_routes);
|
||||||
}
|
}
|
||||||
if (module->controls) {
|
if (module->controls) {
|
||||||
|
|
@ -979,9 +983,11 @@ void gbaudio_unregister_module(struct gbaudio_module_info *module)
|
||||||
module->num_controls);
|
module->num_controls);
|
||||||
}
|
}
|
||||||
if (module->dapm_widgets) {
|
if (module->dapm_widgets) {
|
||||||
|
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(comp);
|
||||||
|
|
||||||
dev_dbg(comp->dev, "Removing %d widgets\n",
|
dev_dbg(comp->dev, "Removing %d widgets\n",
|
||||||
module->num_dapm_widgets);
|
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);
|
module->num_dapm_widgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,12 +115,13 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm,
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct snd_soc_dapm_widget *w, *tmp_w;
|
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++) {
|
for (i = 0; i < num; i++) {
|
||||||
/* below logic can be optimized to identify widget pointer */
|
/* below logic can be optimized to identify widget pointer */
|
||||||
w = NULL;
|
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 &&
|
if (tmp_w->dapm == dapm &&
|
||||||
!strcmp(tmp_w->name, widget->name)) {
|
!strcmp(tmp_w->name, widget->name)) {
|
||||||
w = tmp_w;
|
w = tmp_w;
|
||||||
|
|
@ -128,7 +129,7 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!w) {
|
if (!w) {
|
||||||
dev_err(dapm->dev, "%s: widget not found\n",
|
dev_err(card->dev, "%s: widget not found\n",
|
||||||
widget->name);
|
widget->name);
|
||||||
widget++;
|
widget++;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -136,7 +137,7 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm,
|
||||||
widget++;
|
widget++;
|
||||||
gbaudio_dapm_free_widget(w);
|
gbaudio_dapm_free_widget(w);
|
||||||
}
|
}
|
||||||
mutex_unlock(&dapm->card->dapm_mutex);
|
mutex_unlock(&card->dapm_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ static int gbcodec_mixer_ctl_info(struct snd_kcontrol *kcontrol,
|
||||||
struct gbaudio_ctl_pvt *data;
|
struct gbaudio_ctl_pvt *data;
|
||||||
struct gb_audio_ctl_elem_info *info;
|
struct gb_audio_ctl_elem_info *info;
|
||||||
struct gbaudio_module_info *module;
|
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);
|
struct gbaudio_codec_info *gbcodec = snd_soc_component_get_drvdata(comp);
|
||||||
|
|
||||||
dev_dbg(comp->dev, "Entered %s:%s\n", __func__, kcontrol->id.name);
|
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 gbaudio_ctl_pvt *data;
|
||||||
struct gb_audio_ctl_elem_value gbvalue;
|
struct gb_audio_ctl_elem_value gbvalue;
|
||||||
struct gbaudio_module_info *module;
|
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 gbaudio_codec_info *gb = snd_soc_component_get_drvdata(comp);
|
||||||
struct gb_bundle *bundle;
|
struct gb_bundle *bundle;
|
||||||
|
|
||||||
|
|
@ -276,7 +276,7 @@ static int gbcodec_mixer_ctl_put(struct snd_kcontrol *kcontrol,
|
||||||
struct gbaudio_ctl_pvt *data;
|
struct gbaudio_ctl_pvt *data;
|
||||||
struct gb_audio_ctl_elem_value gbvalue;
|
struct gb_audio_ctl_elem_value gbvalue;
|
||||||
struct gbaudio_module_info *module;
|
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 gbaudio_codec_info *gb = snd_soc_component_get_drvdata(comp);
|
||||||
struct gb_bundle *bundle;
|
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 gbaudio_module_info *module;
|
||||||
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
||||||
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
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 gbaudio_codec_info *gb = dev_get_drvdata(codec_dev);
|
||||||
struct gb_bundle *bundle;
|
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);
|
bundle = to_gb_bundle(module->dev);
|
||||||
|
|
||||||
if (data->vcount == 2)
|
if (data->vcount == 2)
|
||||||
dev_warn(widget->dapm->dev,
|
dev_warn(codec_dev,
|
||||||
"GB: Control '%s' is stereo, which is not supported\n",
|
"GB: Control '%s' is stereo, which is not supported\n",
|
||||||
kcontrol->id.name);
|
kcontrol->id.name);
|
||||||
|
|
||||||
|
|
@ -429,7 +429,7 @@ static int gbcodec_mixer_dapm_ctl_put(struct snd_kcontrol *kcontrol,
|
||||||
struct gbaudio_module_info *module;
|
struct gbaudio_module_info *module;
|
||||||
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
||||||
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
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 gbaudio_codec_info *gb = dev_get_drvdata(codec_dev);
|
||||||
struct gb_bundle *bundle;
|
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);
|
bundle = to_gb_bundle(module->dev);
|
||||||
|
|
||||||
if (data->vcount == 2)
|
if (data->vcount == 2)
|
||||||
dev_warn(widget->dapm->dev,
|
dev_warn(codec_dev,
|
||||||
"GB: Control '%s' is stereo, which is not supported\n",
|
"GB: Control '%s' is stereo, which is not supported\n",
|
||||||
kcontrol->id.name);
|
kcontrol->id.name);
|
||||||
|
|
||||||
|
|
@ -543,7 +543,7 @@ static int gbcodec_enum_ctl_get(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
int ret, ctl_id;
|
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 gbaudio_codec_info *gb = snd_soc_component_get_drvdata(comp);
|
||||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
struct gb_audio_ctl_elem_value gbvalue;
|
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)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
int ret, ctl_id;
|
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 gbaudio_codec_info *gb = snd_soc_component_get_drvdata(comp);
|
||||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
struct gb_audio_ctl_elem_value gbvalue;
|
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 snd_soc_dapm_widget *widget = wlist->widgets[0];
|
||||||
struct gbaudio_module_info *module;
|
struct gbaudio_module_info *module;
|
||||||
struct gb_audio_ctl_elem_value gbvalue;
|
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 gbaudio_codec_info *gb = dev_get_drvdata(codec_dev);
|
||||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
struct gb_bundle *bundle;
|
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 snd_soc_dapm_widget *widget = wlist->widgets[0];
|
||||||
struct gb_audio_ctl_elem_value gbvalue;
|
struct gb_audio_ctl_elem_value gbvalue;
|
||||||
struct gbaudio_module_info *module;
|
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 gbaudio_codec_info *gb = dev_get_drvdata(codec_dev);
|
||||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||||
struct gb_bundle *bundle;
|
struct gb_bundle *bundle;
|
||||||
|
|
@ -924,7 +924,7 @@ static int gbaudio_widget_event(struct snd_soc_dapm_widget *w,
|
||||||
{
|
{
|
||||||
int wid;
|
int wid;
|
||||||
int ret;
|
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_codec_info *gbcodec = dev_get_drvdata(codec_dev);
|
||||||
struct gbaudio_module_info *module;
|
struct gbaudio_module_info *module;
|
||||||
struct gb_bundle *bundle;
|
struct gb_bundle *bundle;
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ struct cs_dsp_coeff_ctl {
|
||||||
const char *subname;
|
const char *subname;
|
||||||
unsigned int subname_len;
|
unsigned int subname_len;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
size_t len;
|
unsigned int len;
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unsigned int set:1;
|
unsigned int set:1;
|
||||||
|
|
@ -188,8 +188,8 @@ struct cs_dsp {
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
struct dentry *debugfs_root;
|
struct dentry *debugfs_root;
|
||||||
char *wmfw_file_name;
|
const char *wmfw_file_name;
|
||||||
char *bin_file_name;
|
const char *bin_file_name;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,21 +26,21 @@ struct cs_dsp_test {
|
||||||
|
|
||||||
struct cs_dsp_test_local *local;
|
struct cs_dsp_test_local *local;
|
||||||
|
|
||||||
/* Following members are private */
|
/* private: Following members are private */
|
||||||
bool saw_bus_write;
|
bool saw_bus_write;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct cs_dsp_mock_alg_def - Info for creating a mock algorithm entry.
|
* struct cs_dsp_mock_alg_def - Info for creating a mock algorithm entry.
|
||||||
*
|
*
|
||||||
* @id Algorithm ID.
|
* @id: Algorithm ID.
|
||||||
* @ver; Algorithm version.
|
* @ver: Algorithm version.
|
||||||
* @xm_base_words XM base address in DSP words.
|
* @xm_base_words: XM base address in DSP words.
|
||||||
* @xm_size_words XM size in DSP words.
|
* @xm_size_words: XM size in DSP words.
|
||||||
* @ym_base_words YM base address in DSP words.
|
* @ym_base_words: YM base address in DSP words.
|
||||||
* @ym_size_words YM size in DSP words.
|
* @ym_size_words: YM size in DSP words.
|
||||||
* @zm_base_words ZM base address in DSP words.
|
* @zm_base_words: ZM base address in DSP words.
|
||||||
* @zm_size_words ZM size in DSP words.
|
* @zm_size_words: ZM size in DSP words.
|
||||||
*/
|
*/
|
||||||
struct cs_dsp_mock_alg_def {
|
struct cs_dsp_mock_alg_def {
|
||||||
unsigned int id;
|
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_to_irq(const struct gpio_desc *desc);
|
||||||
int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name);
|
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 */
|
/* Convert between the old gpio_ and new gpiod_ interfaces */
|
||||||
struct gpio_desc *gpio_to_desc(unsigned gpio);
|
struct gpio_desc *gpio_to_desc(unsigned gpio);
|
||||||
int desc_to_gpio(const struct gpio_desc *desc);
|
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;
|
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)
|
static inline struct gpio_desc *gpio_to_desc(unsigned gpio)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
|
|
@ -3075,6 +3075,7 @@
|
||||||
#define PCI_DEVICE_ID_INTEL_5100_22 0x65f6
|
#define PCI_DEVICE_ID_INTEL_5100_22 0x65f6
|
||||||
#define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff
|
#define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff
|
||||||
#define PCI_DEVICE_ID_INTEL_HDA_FCL 0x67a8
|
#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_0 0x7000
|
||||||
#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
|
#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
|
||||||
#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
|
#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,
|
const struct regmap_config *config,
|
||||||
struct lock_class_key *lock_key,
|
struct lock_class_key *lock_key,
|
||||||
const char *lock_name);
|
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_config *config,
|
||||||
const struct regmap_sdw_mbq_cfg *mbq_config,
|
const struct regmap_sdw_mbq_cfg *mbq_config,
|
||||||
struct lock_class_key *lock_key,
|
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,
|
const struct regmap_config *config,
|
||||||
struct lock_class_key *lock_key,
|
struct lock_class_key *lock_key,
|
||||||
const char *lock_name);
|
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_config *config,
|
||||||
const struct regmap_sdw_mbq_cfg *mbq_config,
|
const struct regmap_sdw_mbq_cfg *mbq_config,
|
||||||
struct lock_class_key *lock_key,
|
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) \
|
#define regmap_init_sdw_mbq(sdw, config) \
|
||||||
__regmap_lockdep_wrapper(__regmap_init_sdw_mbq, #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
|
* 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
|
* to a struct regmap. The regmap will be automatically freed by the
|
||||||
* device management code.
|
* 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, \
|
__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
|
* 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) \
|
#define devm_regmap_init_sdw_mbq(sdw, config) \
|
||||||
__regmap_lockdep_wrapper(__devm_regmap_init_sdw_mbq, #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
|
* 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
|
* @config: Configuration for register map
|
||||||
* @mbq_config: Properties for the MBQ registers
|
* @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
|
* to a struct regmap. The regmap will be automatically freed by the
|
||||||
* device management code.
|
* 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, \
|
__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
|
* devm_regmap_init_slimbus() - Initialise managed register map
|
||||||
|
|
|
||||||
|
|
@ -355,4 +355,6 @@
|
||||||
/* Check the reserved and fixed bits in address */
|
/* 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_VALID_CTL(reg) (((reg) & (GENMASK(31, 25) | BIT(18) | BIT(13))) == BIT(30))
|
||||||
|
|
||||||
|
#define SDW_SDCA_MAX_REGISTER 0x47FFFFFF
|
||||||
|
|
||||||
#endif /* __SDW_REGISTERS_H */
|
#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;
|
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_ */
|
#endif /* _LINUX_STRING_H_ */
|
||||||
|
|
|
||||||
|
|
@ -47,21 +47,44 @@ struct cirrus_amp_cal_controls {
|
||||||
int cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
|
int cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
|
||||||
const struct cirrus_amp_cal_controls *controls,
|
const struct cirrus_amp_cal_controls *controls,
|
||||||
const struct cirrus_amp_cal_data *data);
|
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,
|
int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index,
|
||||||
struct cirrus_amp_cal_data *out_data);
|
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);
|
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 {
|
struct cs_amp_test_hooks {
|
||||||
efi_status_t (*get_efi_variable)(efi_char16_t *name,
|
efi_status_t (*get_efi_variable)(efi_char16_t *name,
|
||||||
efi_guid_t *guid,
|
efi_guid_t *guid,
|
||||||
|
u32 *returned_attr,
|
||||||
unsigned long *size,
|
unsigned long *size,
|
||||||
void *buf);
|
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,
|
int (*write_cal_coeff)(struct cs_dsp *dsp,
|
||||||
const struct cirrus_amp_cal_controls *controls,
|
const struct cirrus_amp_cal_controls *controls,
|
||||||
const char *ctl_name, u32 val);
|
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;
|
extern const struct cs_amp_test_hooks * const cs_amp_test_hooks;
|
||||||
|
|
||||||
#endif /* CS_AMP_LIB_H */
|
#endif /* CS_AMP_LIB_H */
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,15 @@
|
||||||
#ifndef __CS35L56_H
|
#ifndef __CS35L56_H
|
||||||
#define __CS35L56_H
|
#define __CS35L56_H
|
||||||
|
|
||||||
|
#include <linux/debugfs.h>
|
||||||
#include <linux/firmware/cirrus/cs_dsp.h>
|
#include <linux/firmware/cirrus/cs_dsp.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <sound/cs-amp-lib.h>
|
#include <sound/cs-amp-lib.h>
|
||||||
|
|
||||||
|
struct snd_ctl_elem_value;
|
||||||
|
|
||||||
#define CS35L56_DEVID 0x0000000
|
#define CS35L56_DEVID 0x0000000
|
||||||
#define CS35L56_REVID 0x0000004
|
#define CS35L56_REVID 0x0000004
|
||||||
#define CS35L56_RELID 0x000000C
|
#define CS35L56_RELID 0x000000C
|
||||||
|
|
@ -62,6 +65,8 @@
|
||||||
#define CS35L56_IRQ1_MASK_8 0x000E0AC
|
#define CS35L56_IRQ1_MASK_8 0x000E0AC
|
||||||
#define CS35L56_IRQ1_MASK_18 0x000E0D4
|
#define CS35L56_IRQ1_MASK_18 0x000E0D4
|
||||||
#define CS35L56_IRQ1_MASK_20 0x000E0DC
|
#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_MBOX_1_RAW 0x0011000
|
||||||
#define CS35L56_DSP_VIRTUAL1_MBOX_1 0x0011020
|
#define CS35L56_DSP_VIRTUAL1_MBOX_1 0x0011020
|
||||||
#define CS35L56_DSP_VIRTUAL1_MBOX_2 0x0011024
|
#define CS35L56_DSP_VIRTUAL1_MBOX_2 0x0011024
|
||||||
|
|
@ -177,6 +182,9 @@
|
||||||
/* IRQ1_EINT_8 */
|
/* IRQ1_EINT_8 */
|
||||||
#define CS35L56_TEMP_ERR_EINT1_MASK 0x80000000
|
#define CS35L56_TEMP_ERR_EINT1_MASK 0x80000000
|
||||||
|
|
||||||
|
/* MIXER_NGATE_CHn_CFG */
|
||||||
|
#define CS35L56_AUX_NGATE_CHn_EN 0x00000001
|
||||||
|
|
||||||
/* Mixer input sources */
|
/* Mixer input sources */
|
||||||
#define CS35L56_INPUT_SRC_NONE 0x00
|
#define CS35L56_INPUT_SRC_NONE 0x00
|
||||||
#define CS35L56_INPUT_SRC_ASP1RX1 0x08
|
#define CS35L56_INPUT_SRC_ASP1RX1 0x08
|
||||||
|
|
@ -243,6 +251,7 @@
|
||||||
#define CS35L56_MBOX_CMD_AUDIO_PLAY 0x0B000001
|
#define CS35L56_MBOX_CMD_AUDIO_PLAY 0x0B000001
|
||||||
#define CS35L56_MBOX_CMD_AUDIO_PAUSE 0x0B000002
|
#define CS35L56_MBOX_CMD_AUDIO_PAUSE 0x0B000002
|
||||||
#define CS35L56_MBOX_CMD_AUDIO_REINIT 0x0B000003
|
#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_HIBERNATE_NOW 0x02000001
|
||||||
#define CS35L56_MBOX_CMD_WAKEUP 0x02000002
|
#define CS35L56_MBOX_CMD_WAKEUP 0x02000002
|
||||||
#define CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE 0x02000003
|
#define CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE 0x02000003
|
||||||
|
|
@ -258,12 +267,22 @@
|
||||||
#define CS35L56_PS3_POLL_US 500
|
#define CS35L56_PS3_POLL_US 500
|
||||||
#define CS35L56_PS3_TIMEOUT_US 300000
|
#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_CONTROL_PORT_READY_US 2200
|
||||||
#define CS35L56_HALO_STATE_POLL_US 1000
|
#define CS35L56_HALO_STATE_POLL_US 1000
|
||||||
#define CS35L56_HALO_STATE_TIMEOUT_US 250000
|
#define CS35L56_HALO_STATE_TIMEOUT_US 250000
|
||||||
#define CS35L56_RESET_PULSE_MIN_US 1100
|
#define CS35L56_RESET_PULSE_MIN_US 1100
|
||||||
#define CS35L56_WAKE_HOLD_TIME_US 1000
|
#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_PLAYBACK_PORT 1
|
||||||
#define CS35L56_SDW1_CAPTURE_PORT 3
|
#define CS35L56_SDW1_CAPTURE_PORT 3
|
||||||
|
|
||||||
|
|
@ -291,9 +310,16 @@ struct cs35l56_fw_reg {
|
||||||
unsigned int posture_number;
|
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 cs35l56_base {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
|
struct cs_dsp *dsp;
|
||||||
int irq;
|
int irq;
|
||||||
struct mutex irq_lock;
|
struct mutex irq_lock;
|
||||||
u8 type;
|
u8 type;
|
||||||
|
|
@ -304,11 +330,14 @@ struct cs35l56_base {
|
||||||
bool can_hibernate;
|
bool can_hibernate;
|
||||||
bool cal_data_valid;
|
bool cal_data_valid;
|
||||||
s8 cal_index;
|
s8 cal_index;
|
||||||
|
u8 num_amps;
|
||||||
struct cirrus_amp_cal_data cal_data;
|
struct cirrus_amp_cal_data cal_data;
|
||||||
struct gpio_desc *reset_gpio;
|
struct gpio_desc *reset_gpio;
|
||||||
struct cs35l56_spi_payload *spi_payload_buf;
|
struct cs35l56_spi_payload *spi_payload_buf;
|
||||||
const struct cs35l56_fw_reg *fw_reg;
|
const struct cs35l56_fw_reg *fw_reg;
|
||||||
const struct cirrus_amp_cal_controls *calibration_controls;
|
const struct cirrus_amp_cal_controls *calibration_controls;
|
||||||
|
struct dentry *debugfs;
|
||||||
|
u64 silicon_uid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool cs35l56_is_otp_register(unsigned int reg)
|
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 regmap_config cs35l63_regmap_sdw;
|
||||||
|
|
||||||
extern const struct cirrus_amp_cal_controls cs35l56_calibration_controls;
|
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 char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
|
||||||
extern const unsigned int cs35l56_tx_input_values[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);
|
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);
|
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_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,
|
int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
|
||||||
bool *fw_missing, unsigned int *fw_version);
|
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);
|
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_hw_init(struct cs35l56_base *cs35l56_base);
|
||||||
int cs35l56_get_speaker_id(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/types.h>
|
||||||
#include <linux/kconfig.h>
|
#include <linux/kconfig.h>
|
||||||
|
|
||||||
|
struct acpi_table_swft;
|
||||||
|
struct fwnode_handle;
|
||||||
struct sdw_slave;
|
struct sdw_slave;
|
||||||
|
struct sdca_dev;
|
||||||
|
|
||||||
#define SDCA_MAX_FUNCTION_COUNT 8
|
#define SDCA_MAX_FUNCTION_COUNT 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct sdca_function_desc - short descriptor for an SDCA Function
|
* struct sdca_function_desc - short descriptor for an SDCA Function
|
||||||
* @node: firmware node for the Function.
|
* @node: firmware node for the Function.
|
||||||
|
* @func_dev: pointer to SDCA function device.
|
||||||
* @name: Human-readable string.
|
* @name: Human-readable string.
|
||||||
* @type: Function topology type.
|
* @type: Function topology type.
|
||||||
* @adr: ACPI address (used for SDCA register access).
|
* @adr: ACPI address (used for SDCA register access).
|
||||||
*/
|
*/
|
||||||
struct sdca_function_desc {
|
struct sdca_function_desc {
|
||||||
struct fwnode_handle *node;
|
struct fwnode_handle *node;
|
||||||
|
struct sdca_dev *func_dev;
|
||||||
const char *name;
|
const char *name;
|
||||||
u32 type;
|
u32 type;
|
||||||
u8 adr;
|
u8 adr;
|
||||||
|
|
@ -37,11 +42,13 @@ struct sdca_function_desc {
|
||||||
* @num_functions: Total number of supported SDCA functions. Invalid/unsupported
|
* @num_functions: Total number of supported SDCA functions. Invalid/unsupported
|
||||||
* functions will be skipped.
|
* functions will be skipped.
|
||||||
* @function: Array of function descriptors.
|
* @function: Array of function descriptors.
|
||||||
|
* @swft: Pointer to the SWFT table, if available.
|
||||||
*/
|
*/
|
||||||
struct sdca_device_data {
|
struct sdca_device_data {
|
||||||
u32 interface_revision;
|
u32 interface_revision;
|
||||||
int num_functions;
|
int num_functions;
|
||||||
struct sdca_function_desc function[SDCA_MAX_FUNCTION_COUNT];
|
struct sdca_function_desc function[SDCA_MAX_FUNCTION_COUNT];
|
||||||
|
struct acpi_table_swft *swft;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sdca_quirk {
|
enum sdca_quirk {
|
||||||
|
|
@ -52,17 +59,29 @@ enum sdca_quirk {
|
||||||
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA)
|
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SDCA)
|
||||||
|
|
||||||
void sdca_lookup_functions(struct sdw_slave *slave);
|
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);
|
void sdca_lookup_interface_revision(struct sdw_slave *slave);
|
||||||
bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk);
|
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
|
#else
|
||||||
|
|
||||||
static inline void sdca_lookup_functions(struct sdw_slave *slave) {}
|
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 void sdca_lookup_interface_revision(struct sdw_slave *slave) {}
|
||||||
static inline bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
|
static inline bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
|
||||||
{
|
{
|
||||||
return false;
|
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
|
||||||
|
|
||||||
#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/types.h>
|
||||||
#include <linux/hid.h>
|
#include <linux/hid.h>
|
||||||
|
|
||||||
|
struct acpi_table_swft;
|
||||||
struct device;
|
struct device;
|
||||||
struct sdca_entity;
|
struct sdca_entity;
|
||||||
struct sdca_function_desc;
|
struct sdca_function_desc;
|
||||||
|
|
@ -63,6 +64,7 @@ struct sdca_function_desc;
|
||||||
* @SDCA_FUNCTION_TYPE_RJ: Retaskable jack.
|
* @SDCA_FUNCTION_TYPE_RJ: Retaskable jack.
|
||||||
* @SDCA_FUNCTION_TYPE_SIMPLE_JACK: Subset of UAJ.
|
* @SDCA_FUNCTION_TYPE_SIMPLE_JACK: Subset of UAJ.
|
||||||
* @SDCA_FUNCTION_TYPE_HID: Human Interface Device, for e.g. buttons.
|
* @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_TYPE_IMP_DEF: Implementation-defined function.
|
||||||
*
|
*
|
||||||
* SDCA Function Types from SDCA specification v1.0a Section 5.1.2
|
* 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_RJ = 0x07,
|
||||||
SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08,
|
SDCA_FUNCTION_TYPE_SIMPLE_JACK = 0x08,
|
||||||
SDCA_FUNCTION_TYPE_HID = 0x0A,
|
SDCA_FUNCTION_TYPE_HID = 0x0A,
|
||||||
|
SDCA_FUNCTION_TYPE_COMPANION_AMP = 0x0B,
|
||||||
SDCA_FUNCTION_TYPE_IMP_DEF = 0x1F,
|
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_RJ_NAME "RJ"
|
||||||
#define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack"
|
#define SDCA_FUNCTION_TYPE_SIMPLE_NAME "SimpleJack"
|
||||||
#define SDCA_FUNCTION_TYPE_HID_NAME "HID"
|
#define SDCA_FUNCTION_TYPE_HID_NAME "HID"
|
||||||
|
#define SDCA_FUNCTION_TYPE_COMPANION_AMP_NAME "CompanionAmp"
|
||||||
#define SDCA_FUNCTION_TYPE_IMP_DEF_NAME "ImplementationDefined"
|
#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, \
|
#define SDCA_CTL_TYPE_S(ent, sel) SDCA_CTL_TYPE(SDCA_ENTITY_TYPE_##ent, \
|
||||||
SDCA_CTL_##ent##_##sel)
|
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
|
* 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_STATUS = 0x14,
|
||||||
SDCA_CTL_XU_FDL_SET_INDEX = 0x15,
|
SDCA_CTL_XU_FDL_SET_INDEX = 0x15,
|
||||||
SDCA_CTL_XU_FDL_HOST_REQUEST = 0x16,
|
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_NEEDS_INITIALIZATION = BIT(5),
|
||||||
SDCA_CTL_ENTITY_0_FUNCTION_HAS_BEEN_RESET = BIT(6),
|
SDCA_CTL_ENTITY_0_FUNCTION_HAS_BEEN_RESET = BIT(6),
|
||||||
SDCA_CTL_ENTITY_0_FUNCTION_BUSY = BIT(7),
|
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"
|
#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_NDAI_PACKETTYPE_NAME "NDAI Packet Type"
|
||||||
#define SDCA_CTL_MIXER_NAME "Mixer"
|
#define SDCA_CTL_MIXER_NAME "Mixer"
|
||||||
#define SDCA_CTL_SELECTOR_NAME "Selector"
|
#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_CHANNEL_VOLUME_NAME "Channel Volume"
|
||||||
#define SDCA_CTL_AGC_NAME "AGC"
|
#define SDCA_CTL_AGC_NAME "AGC"
|
||||||
#define SDCA_CTL_BASS_BOOST_NAME "Bass Boost"
|
#define SDCA_CTL_BASS_BOOST_NAME "Bass Boost"
|
||||||
|
|
@ -771,6 +825,7 @@ struct sdca_control {
|
||||||
u8 layers;
|
u8 layers;
|
||||||
|
|
||||||
bool deferrable;
|
bool deferrable;
|
||||||
|
bool is_volatile;
|
||||||
bool has_default;
|
bool has_default;
|
||||||
bool has_fixed;
|
bool has_fixed;
|
||||||
};
|
};
|
||||||
|
|
@ -1089,6 +1144,27 @@ struct sdca_entity_hide {
|
||||||
struct hid_descriptor hid_desc;
|
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
|
* struct sdca_entity - information for one SDCA Entity
|
||||||
* @label: String such as "OT 12".
|
* @label: String such as "OT 12".
|
||||||
|
|
@ -1105,6 +1181,7 @@ struct sdca_entity_hide {
|
||||||
* @pde: Power Domain Entity specific Entity properties.
|
* @pde: Power Domain Entity specific Entity properties.
|
||||||
* @ge: Group Entity specific Entity properties.
|
* @ge: Group Entity specific Entity properties.
|
||||||
* @hide: HIDE Entity specific Entity properties.
|
* @hide: HIDE Entity specific Entity properties.
|
||||||
|
* @xu: XU Entity specific Entity properties.
|
||||||
*/
|
*/
|
||||||
struct sdca_entity {
|
struct sdca_entity {
|
||||||
const char *label;
|
const char *label;
|
||||||
|
|
@ -1122,6 +1199,7 @@ struct sdca_entity {
|
||||||
struct sdca_entity_pde pde;
|
struct sdca_entity_pde pde;
|
||||||
struct sdca_entity_ge ge;
|
struct sdca_entity_ge ge;
|
||||||
struct sdca_entity_hide hide;
|
struct sdca_entity_hide hide;
|
||||||
|
struct sdca_entity_xu xu;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1288,6 +1366,42 @@ enum sdca_cluster_range {
|
||||||
SDCA_CLUSTER_NCOLS = 2,
|
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
|
* struct sdca_function_data - top-level information for one SDCA function
|
||||||
* @desc: Pointer to short descriptor from initial parsing.
|
* @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.
|
* @num_clusters: Number of Channel Clusters reported in this Function.
|
||||||
* @busy_max_delay: Maximum Function busy delay in microseconds, before an
|
* @busy_max_delay: Maximum Function busy delay in microseconds, before an
|
||||||
* error should be reported.
|
* 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_data {
|
||||||
struct sdca_function_desc *desc;
|
struct sdca_function_desc *desc;
|
||||||
|
|
@ -1311,6 +1428,9 @@ struct sdca_function_data {
|
||||||
int num_clusters;
|
int num_clusters;
|
||||||
|
|
||||||
unsigned int busy_max_delay;
|
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,
|
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;
|
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_desc *desc,
|
||||||
struct sdca_function_data *function);
|
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_control *sdca_selector_find_control(struct device *dev,
|
||||||
struct sdca_entity *entity,
|
struct sdca_entity *entity,
|
||||||
const int sel);
|
const int sel);
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,27 @@
|
||||||
#ifndef __SDCA_HID_H__
|
#ifndef __SDCA_HID_H__
|
||||||
#define __SDCA_HID_H__
|
#define __SDCA_HID_H__
|
||||||
|
|
||||||
#include <linux/types.h>
|
struct device;
|
||||||
#include <linux/hid.h>
|
struct sdw_slave;
|
||||||
|
|
||||||
|
struct sdca_entity;
|
||||||
|
struct sdca_interrupt;
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_SND_SOC_SDCA_HID)
|
#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
|
#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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,18 +23,23 @@ struct sdca_function_data;
|
||||||
/**
|
/**
|
||||||
* struct sdca_interrupt - contains information about a single SDCA interrupt
|
* struct sdca_interrupt - contains information about a single SDCA interrupt
|
||||||
* @name: The name of the 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.
|
* @component: Pointer to the ASoC component owns the interrupt.
|
||||||
* @function: Pointer to the Function that the interrupt is associated with.
|
* @function: Pointer to the Function that the interrupt is associated with.
|
||||||
* @entity: Pointer to the Entity 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.
|
* @control: Pointer to the Control that the interrupt is associated with.
|
||||||
* @priv: Pointer to private data for use by the handler.
|
* @priv: Pointer to private data for use by the handler.
|
||||||
* @externally_requested: Internal flag used to check if a client driver has
|
* @irq: IRQ number allocated to this interrupt, also used internally to track
|
||||||
* already requested the interrupt, for custom handling, allowing the core to
|
* the IRQ being assigned.
|
||||||
* skip handling this interrupt.
|
|
||||||
*/
|
*/
|
||||||
struct sdca_interrupt {
|
struct sdca_interrupt {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
struct device *dev;
|
||||||
|
struct regmap *device_regmap;
|
||||||
|
struct regmap *function_regmap;
|
||||||
struct snd_soc_component *component;
|
struct snd_soc_component *component;
|
||||||
struct sdca_function_data *function;
|
struct sdca_function_data *function;
|
||||||
struct sdca_entity *entity;
|
struct sdca_entity *entity;
|
||||||
|
|
@ -42,7 +47,7 @@ struct sdca_interrupt {
|
||||||
|
|
||||||
void *priv;
|
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_request(struct device *dev, struct sdca_interrupt_info *interrupt_info,
|
||||||
int sdca_irq, const char *name, irq_handler_t handler,
|
int sdca_irq, const char *name, irq_handler_t handler,
|
||||||
void *data);
|
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_function_data *function,
|
||||||
struct sdca_entity *entity,
|
struct sdca_entity *entity,
|
||||||
struct sdca_control *control,
|
struct sdca_control *control,
|
||||||
struct sdca_interrupt *interrupt);
|
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,
|
int sdca_irq_populate(struct sdca_function_data *function,
|
||||||
struct snd_soc_component *component,
|
struct snd_soc_component *component,
|
||||||
struct sdca_interrupt_info *info);
|
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,
|
int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
|
||||||
struct sdca_function_data *function);
|
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__
|
#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_lnl_machines[];
|
||||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_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_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_cnl_sdw_machines[];
|
||||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_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_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_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_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
|
* 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
|
* @name_prefix: string used for codec controls
|
||||||
*/
|
*/
|
||||||
struct snd_soc_acpi_adr_device {
|
struct snd_soc_acpi_adr_device {
|
||||||
const u64 adr;
|
u64 adr;
|
||||||
const u8 num_endpoints;
|
u8 num_endpoints;
|
||||||
const struct snd_soc_acpi_endpoint *endpoints;
|
const struct snd_soc_acpi_endpoint *endpoints;
|
||||||
const char *name_prefix;
|
const char *name_prefix;
|
||||||
};
|
};
|
||||||
|
|
@ -131,8 +131,8 @@ struct snd_soc_acpi_adr_device {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct snd_soc_acpi_link_adr {
|
struct snd_soc_acpi_link_adr {
|
||||||
const u32 mask;
|
u32 mask;
|
||||||
const u32 num_adr;
|
u32 num_adr;
|
||||||
const struct snd_soc_acpi_adr_device *adr_d;
|
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) \
|
#define SOC_VALUE_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
|
||||||
SOC_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) \
|
#define SND_SOC_BYTES(xname, xbase, xregs) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||||
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
|
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
|
||||||
|
|
@ -331,6 +338,13 @@ struct platform_device;
|
||||||
.put = xhandler_put, .private_value = \
|
.put = xhandler_put, .private_value = \
|
||||||
((unsigned long)&(struct soc_bytes) \
|
((unsigned long)&(struct soc_bytes) \
|
||||||
{.base = xbase, .num_regs = xregs }) }
|
{.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) \
|
#define SND_SOC_BYTES_MASK(xname, xbase, xregs, xmask) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||||
|
|
@ -1225,6 +1239,7 @@ struct soc_mixer_control {
|
||||||
unsigned int sign_bit;
|
unsigned int sign_bit;
|
||||||
unsigned int invert:1;
|
unsigned int invert:1;
|
||||||
unsigned int autodisable:1;
|
unsigned int autodisable:1;
|
||||||
|
unsigned int sdca_q78:1;
|
||||||
#ifdef CONFIG_SND_SOC_TOPOLOGY
|
#ifdef CONFIG_SND_SOC_TOPOLOGY
|
||||||
struct snd_soc_dobj dobj;
|
struct snd_soc_dobj dobj;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1305,22 +1320,6 @@ static inline unsigned int snd_soc_enum_item_to_val(const struct soc_enum *e,
|
||||||
return e->values[item];
|
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);
|
int snd_soc_util_init(void);
|
||||||
void snd_soc_util_exit(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)
|
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)
|
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)
|
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)
|
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), \
|
#define snd_soc_dapm_mutex_lock_root(x) _Generic((x), \
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include <sound/soc-acpi.h>
|
#include <sound/soc-acpi.h>
|
||||||
|
|
||||||
#define SOC_SDW_MAX_DAI_NUM 8
|
#define SOC_SDW_MAX_DAI_NUM 8
|
||||||
|
#define SOC_SDW_MAX_AUX_NUM 2
|
||||||
#define SOC_SDW_MAX_NO_PROPS 2
|
#define SOC_SDW_MAX_NO_PROPS 2
|
||||||
#define SOC_SDW_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0))
|
#define SOC_SDW_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0))
|
||||||
|
|
||||||
|
|
@ -45,6 +46,7 @@ struct asoc_sdw_codec_info;
|
||||||
|
|
||||||
struct asoc_sdw_dai_info {
|
struct asoc_sdw_dai_info {
|
||||||
const bool direction[2]; /* playback & capture support */
|
const bool direction[2]; /* playback & capture support */
|
||||||
|
const char *codec_name;
|
||||||
const char *dai_name;
|
const char *dai_name;
|
||||||
const char *component_name;
|
const char *component_name;
|
||||||
const int dai_type;
|
const int dai_type;
|
||||||
|
|
@ -64,16 +66,22 @@ struct asoc_sdw_dai_info {
|
||||||
bool quirk_exclude;
|
bool quirk_exclude;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct asoc_sdw_aux_info {
|
||||||
|
const char *codec_name;
|
||||||
|
};
|
||||||
|
|
||||||
struct asoc_sdw_codec_info {
|
struct asoc_sdw_codec_info {
|
||||||
const int part_id;
|
const int part_id;
|
||||||
const int version_id;
|
const int version_id;
|
||||||
const char *codec_name;
|
const char *name_prefix;
|
||||||
int amp_num;
|
int amp_num;
|
||||||
const u8 acpi_id[ACPI_ID_LEN];
|
const u8 acpi_id[ACPI_ID_LEN];
|
||||||
const bool ignore_internal_dmic;
|
const bool ignore_internal_dmic;
|
||||||
const struct snd_soc_ops *ops;
|
const struct snd_soc_ops *ops;
|
||||||
struct asoc_sdw_dai_info dais[SOC_SDW_MAX_DAI_NUM];
|
struct asoc_sdw_dai_info dais[SOC_SDW_MAX_DAI_NUM];
|
||||||
const int 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);
|
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);
|
void asoc_sdw_shutdown(struct snd_pcm_substream *substream);
|
||||||
|
|
||||||
const char *asoc_sdw_get_codec_name(struct device *dev,
|
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,
|
const struct snd_soc_acpi_link_adr *adr_link,
|
||||||
int adr_index);
|
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),
|
int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd),
|
||||||
const struct snd_soc_ops *ops);
|
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,
|
struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
|
||||||
const struct snd_soc_acpi_endpoint *new);
|
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,
|
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_dailink *soc_dais,
|
||||||
struct asoc_sdw_endpoint *soc_ends,
|
struct asoc_sdw_endpoint *soc_ends,
|
||||||
int *num_devs);
|
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_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_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_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_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);
|
int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||||
/* TI */
|
/* TI */
|
||||||
|
|
|
||||||
|
|
@ -117,14 +117,20 @@ enum audio_device {
|
||||||
TAS2120,
|
TAS2120,
|
||||||
TAS2320,
|
TAS2320,
|
||||||
TAS2563,
|
TAS2563,
|
||||||
|
TAS2568,
|
||||||
TAS2570,
|
TAS2570,
|
||||||
TAS2572,
|
TAS2572,
|
||||||
|
TAS2574,
|
||||||
TAS2781,
|
TAS2781,
|
||||||
TAS5802,
|
TAS5802,
|
||||||
|
TAS5806M,
|
||||||
|
TAS5806MD,
|
||||||
TAS5815,
|
TAS5815,
|
||||||
|
TAS5822,
|
||||||
TAS5825,
|
TAS5825,
|
||||||
TAS5827,
|
TAS5827,
|
||||||
TAS5828,
|
TAS5828,
|
||||||
|
TAS5830,
|
||||||
TAS_OTHERS,
|
TAS_OTHERS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -197,7 +203,6 @@ struct tasdevice_priv {
|
||||||
struct acoustic_data acou_data;
|
struct acoustic_data acou_data;
|
||||||
#endif
|
#endif
|
||||||
struct tasdevice_fw *fmw;
|
struct tasdevice_fw *fmw;
|
||||||
struct gpio_desc *speaker_id;
|
|
||||||
struct gpio_desc *reset;
|
struct gpio_desc *reset;
|
||||||
struct mutex codec_lock;
|
struct mutex codec_lock;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
|
|
@ -215,6 +220,7 @@ struct tasdevice_priv {
|
||||||
unsigned int magic_num;
|
unsigned int magic_num;
|
||||||
unsigned int chip_id;
|
unsigned int chip_id;
|
||||||
unsigned int sysclk;
|
unsigned int sysclk;
|
||||||
|
int speaker_id;
|
||||||
|
|
||||||
int irq;
|
int irq;
|
||||||
int cur_prog;
|
int cur_prog;
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ DECLARE_EVENT_CLASS(snd_soc_dapm,
|
||||||
TP_ARGS(dapm, val),
|
TP_ARGS(dapm, val),
|
||||||
|
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__string( card_name, dapm->card->name)
|
__string( card_name, snd_soc_dapm_to_card(dapm)->name)
|
||||||
__string( comp_name, dapm->component ? dapm->component->name : "(none)")
|
__string( comp_name, snd_soc_dapm_to_component(dapm) ? snd_soc_dapm_to_component(dapm)->name : "(none)")
|
||||||
__field( int, val)
|
__field( int, val)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ enum avs_tplg_token {
|
||||||
AVS_TKN_MANIFEST_NUM_BINDINGS_U32 = 8,
|
AVS_TKN_MANIFEST_NUM_BINDINGS_U32 = 8,
|
||||||
AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32 = 9,
|
AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32 = 9,
|
||||||
AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32 = 10,
|
AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32 = 10,
|
||||||
|
AVS_TKN_MANIFEST_NUM_NHLT_CONFIGS_U32 = 11,
|
||||||
|
|
||||||
/* struct avs_tplg_library */
|
/* struct avs_tplg_library */
|
||||||
AVS_TKN_LIBRARY_ID_U32 = 101,
|
AVS_TKN_LIBRARY_ID_U32 = 101,
|
||||||
|
|
@ -124,6 +125,7 @@ enum avs_tplg_token {
|
||||||
AVS_TKN_MOD_KCONTROL_ID_U32 = 1707,
|
AVS_TKN_MOD_KCONTROL_ID_U32 = 1707,
|
||||||
AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32 = 1708,
|
AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32 = 1708,
|
||||||
AVS_TKN_MOD_INIT_CONFIG_ID_U32 = 1709,
|
AVS_TKN_MOD_INIT_CONFIG_ID_U32 = 1709,
|
||||||
|
AVS_TKN_MOD_NHLT_CONFIG_ID_U32 = 1710,
|
||||||
|
|
||||||
/* struct avs_tplg_path_template */
|
/* struct avs_tplg_path_template */
|
||||||
AVS_TKN_PATH_TMPL_ID_U32 = 1801,
|
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_ID_U32 = 2401,
|
||||||
AVS_TKN_INIT_CONFIG_PARAM_U8 = 2402,
|
AVS_TKN_INIT_CONFIG_PARAM_U8 = 2402,
|
||||||
AVS_TKN_INIT_CONFIG_LENGTH_U32 = 2403,
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -602,6 +602,18 @@ static void string_test_memtostr(struct kunit *test)
|
||||||
KUNIT_EXPECT_EQ(test, dest[7], '\0');
|
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[] = {
|
static struct kunit_case string_test_cases[] = {
|
||||||
KUNIT_CASE(string_test_memset16),
|
KUNIT_CASE(string_test_memset16),
|
||||||
KUNIT_CASE(string_test_memset32),
|
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_strlcat),
|
||||||
KUNIT_CASE(string_test_strtomem),
|
KUNIT_CASE(string_test_strtomem),
|
||||||
KUNIT_CASE(string_test_memtostr),
|
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
|
* @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
|
* 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
|
* first performs a warm reset. If @try_warm is false the function issues
|
||||||
* returns 1. Otherwise or if @try_warm is false the function issues cold reset
|
* cold reset followed by a warm reset. If @id is 0 any valid device ID
|
||||||
* followed by a warm reset. If this is successful the function returns 0,
|
* will be accepted, otherwise only the ID that matches @id and @id_mask
|
||||||
* otherwise a negative error code. If @id is 0 any valid device ID will be
|
* is accepted.
|
||||||
* 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,
|
int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
|
||||||
unsigned int id_mask)
|
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
|
* in console or for audio devices. Assume the highest speakers
|
||||||
* configuration, to _not_ prohibit multi-channel audio playback.
|
* configuration, to _not_ prohibit multi-channel audio playback.
|
||||||
*/
|
*/
|
||||||
if (!e->spk_alloc)
|
if (!e->spk_alloc && e->sad_count)
|
||||||
e->spk_alloc = 0xffff;
|
e->spk_alloc = 0xffff;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -2106,13 +2106,11 @@ EXPORT_SYMBOL(snd_rawmidi_set_ops);
|
||||||
|
|
||||||
static int __init alsa_rawmidi_init(void)
|
static int __init alsa_rawmidi_init(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
|
snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
|
||||||
snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
|
snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
|
||||||
#ifdef CONFIG_SND_OSSEMUL
|
#ifdef CONFIG_SND_OSSEMUL
|
||||||
{ int i;
|
|
||||||
/* check device map table */
|
/* 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) {
|
if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
|
||||||
pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n",
|
pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n",
|
||||||
i, midi_map[i]);
|
i, midi_map[i]);
|
||||||
|
|
@ -2124,7 +2122,6 @@ static int __init alsa_rawmidi_init(void)
|
||||||
amidi_map[i] = 1;
|
amidi_map[i] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif /* CONFIG_SND_OSSEMUL */
|
#endif /* CONFIG_SND_OSSEMUL */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -696,10 +696,10 @@ static int setup_patt_bufs(void)
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(patt_bufs); 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)
|
if (!patt_bufs[i].buf)
|
||||||
break;
|
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;
|
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 \
|
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-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \
|
||||||
dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.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
|
obj-$(CONFIG_SND_DICE) += snd-dice.o
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
base_offset += EXT_APP_STREAM_ENTRIES;
|
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,
|
err = read_stream_entries(dice, section_addr, base_offset,
|
||||||
stream_count, mode,
|
stream_count, mode,
|
||||||
dice->tx_pcm_chs,
|
dice->tx_pcm_chs,
|
||||||
|
|
@ -125,7 +125,7 @@ static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE;
|
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,
|
err = read_stream_entries(dice, section_addr, base_offset,
|
||||||
stream_count,
|
stream_count,
|
||||||
mode, dice->rx_pcm_chs,
|
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_PRESONUS 0x000a92
|
||||||
#define OUI_HARMAN 0x000fd7
|
#define OUI_HARMAN 0x000fd7
|
||||||
#define OUI_AVID 0x00a07e
|
#define OUI_AVID 0x00a07e
|
||||||
|
#define OUI_TEAC 0x00022e
|
||||||
|
|
||||||
#define DICE_CATEGORY_ID 0x04
|
#define DICE_CATEGORY_ID 0x04
|
||||||
#define WEISS_CATEGORY_ID 0x00
|
#define WEISS_CATEGORY_ID 0x00
|
||||||
|
|
@ -458,6 +459,18 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
||||||
.match_flags = IEEE1394_MATCH_VERSION,
|
.match_flags = IEEE1394_MATCH_VERSION,
|
||||||
.version = DICE_INTERFACE,
|
.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);
|
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_harman_formats(struct snd_dice *dice);
|
||||||
int snd_dice_detect_focusrite_pro40_tcd3070_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_weiss_formats(struct snd_dice *dice);
|
||||||
|
int snd_dice_detect_teac_formats(struct snd_dice *dice);
|
||||||
|
|
||||||
#endif
|
#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(0x80862820, "Lunar Lake HDMI", MODEL_ADLP),
|
||||||
HDA_CODEC_ID_MODEL(0x80862822, "Panther 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(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(0x80862882, "Valleyview2 HDMI", MODEL_BYT),
|
||||||
HDA_CODEC_ID_MODEL(0x80862883, "Braswell HDMI", MODEL_BYT),
|
HDA_CODEC_ID_MODEL(0x80862883, "Braswell HDMI", MODEL_BYT),
|
||||||
{} /* terminator */
|
{} /* 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->power_hook = alc287_s4_power_gpio3_default;
|
||||||
spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
|
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
|
* Clear COEF 0x0d (PCBEEP passthrough) bit 0x40 where BIOS sets it wrongly
|
||||||
* at PM resume
|
* 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);
|
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 {
|
enum {
|
||||||
ALC269_FIXUP_GPIO2,
|
ALC269_FIXUP_GPIO2,
|
||||||
ALC269_FIXUP_SONY_VAIO,
|
ALC269_FIXUP_SONY_VAIO,
|
||||||
|
|
@ -3737,6 +3787,10 @@ enum {
|
||||||
ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
|
ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
|
||||||
ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK,
|
ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK,
|
||||||
ALC256_FIXUP_VAIO_RPL_MIC_NO_PRESENCE,
|
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;
|
/* 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,
|
.type = HDA_FIXUP_FUNC,
|
||||||
.v.func = alc236_fixup_hp_mute_led_micmute_vref,
|
.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] = {
|
[ALC236_FIXUP_LENOVO_INV_DMIC] = {
|
||||||
.type = HDA_FIXUP_FUNC,
|
.type = HDA_FIXUP_FUNC,
|
||||||
.v.func = alc_fixup_inv_dmic,
|
.v.func = alc_fixup_inv_dmic,
|
||||||
|
|
@ -6183,7 +6243,19 @@ static const struct hda_fixup alc269_fixups[] = {
|
||||||
},
|
},
|
||||||
.chained = true,
|
.chained = true,
|
||||||
.chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
|
.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[] = {
|
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, 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, 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, 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, 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, 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),
|
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, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8e61, "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, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8ed5, "HP Merino13X", ALC245_FIXUP_TAS2781_SPI_2),
|
SND_PCI_QUIRK(0x103c, 0x8eb6, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8ed6, "HP Merino13", ALC245_FIXUP_TAS2781_SPI_2),
|
SND_PCI_QUIRK(0x103c, 0x8eb7, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8ed7, "HP Merino14", ALC245_FIXUP_TAS2781_SPI_2),
|
SND_PCI_QUIRK(0x103c, 0x8eb8, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8ed8, "HP Merino16", ALC245_FIXUP_TAS2781_SPI_2),
|
SND_PCI_QUIRK(0x103c, 0x8ec1, "HP 200 G2i", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8ed9, "HP Merino14W", ALC245_FIXUP_TAS2781_SPI_2),
|
SND_PCI_QUIRK(0x103c, 0x8ec4, "HP Bantie I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8eda, "HP Merino16W", ALC245_FIXUP_TAS2781_SPI_2),
|
SND_PCI_QUIRK(0x103c, 0x8ec5, "HP Bantie I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8f40, "HP Lampas14", ALC287_FIXUP_TXNW2781_I2C),
|
SND_PCI_QUIRK(0x103c, 0x8ece, "HP Abe I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8f41, "HP Lampas16", ALC287_FIXUP_TXNW2781_I2C),
|
SND_PCI_QUIRK(0x103c, 0x8ecf, "HP Abe I6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||||
SND_PCI_QUIRK(0x103c, 0x8f42, "HP LampasW14", ALC287_FIXUP_TXNW2781_I2C),
|
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, 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, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
|
||||||
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
|
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, 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, 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, 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, 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, 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),
|
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, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
|
||||||
SND_PCI_QUIRK(0x10ec, 0x12f6, "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(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, 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, 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),
|
SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP),
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@
|
||||||
#include "hda_jack.h"
|
#include "hda_jack.h"
|
||||||
#include "generic.h"
|
#include "generic.h"
|
||||||
|
|
||||||
|
/* GPIO node ID */
|
||||||
|
#define SENARY_GPIO_NODE 0x01
|
||||||
|
|
||||||
struct senary_spec {
|
struct senary_spec {
|
||||||
struct hda_gen_spec gen;
|
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;
|
unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
|
||||||
|
|
||||||
if (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);
|
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);
|
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);
|
spec->gpio_led);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,21 @@ config SND_HDA_SCODEC_CS35L56_SPI
|
||||||
Say Y or M here to include CS35L56 amplifier support with
|
Say Y or M here to include CS35L56 amplifier support with
|
||||||
SPI control.
|
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
|
config SND_HDA_SCODEC_TAS2781
|
||||||
tristate
|
tristate
|
||||||
select SND_HDA_GENERIC
|
select SND_HDA_GENERIC
|
||||||
|
|
|
||||||
|
|
@ -548,20 +548,24 @@ static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmw
|
||||||
kfree(coeff_filename);
|
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;
|
int ret;
|
||||||
|
|
||||||
if (!cs35l56->base.cal_data_valid || cs35l56->base.secured)
|
if (!cs35l56->base.cal_data_valid || cs35l56->base.secured)
|
||||||
return;
|
return -EACCES;
|
||||||
|
|
||||||
ret = cs_amp_write_cal_coeffs(&cs35l56->cs_dsp,
|
ret = cs_amp_write_cal_coeffs(&cs35l56->cs_dsp,
|
||||||
&cs35l56_calibration_controls,
|
&cs35l56_calibration_controls,
|
||||||
&cs35l56->base.cal_data);
|
&cs35l56->base.cal_data);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
dev_warn(cs35l56->base.dev, "Failed to write calibration: %d\n", ret);
|
dev_warn(cs35l56->base.dev, "Failed to write calibration: %d\n", ret);
|
||||||
else
|
return ret;
|
||||||
dev_info(cs35l56->base.dev, "Calibration applied\n");
|
}
|
||||||
|
|
||||||
|
dev_info(cs35l56->base.dev, "Calibration applied\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
|
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)
|
if (ret)
|
||||||
dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, 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);
|
cs35l56_hda_apply_calibration(cs35l56);
|
||||||
|
|
||||||
ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
|
ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
|
||||||
if (ret)
|
if (ret)
|
||||||
cs_dsp_stop(&cs35l56->cs_dsp);
|
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);
|
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)
|
static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)
|
||||||
{
|
{
|
||||||
struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
|
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);
|
cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root);
|
||||||
#endif
|
#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");
|
dev_dbg(cs35l56->base.dev, "Bound\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -735,6 +838,7 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *
|
||||||
|
|
||||||
cancel_work_sync(&cs35l56->dsp_work);
|
cancel_work_sync(&cs35l56->dsp_work);
|
||||||
|
|
||||||
|
cs35l56_remove_cal_debugfs(&cs35l56->base);
|
||||||
cs35l56_hda_remove_controls(cs35l56);
|
cs35l56_hda_remove_controls(cs35l56);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_SND_DEBUG)
|
#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.type = hid & 0xff;
|
||||||
cs35l56->base.cal_index = -1;
|
cs35l56->base.cal_index = cs35l56->index;
|
||||||
|
|
||||||
cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);
|
cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);
|
||||||
cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;
|
cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef __CS35L56_HDA_H__
|
#ifndef __CS35L56_HDA_H__
|
||||||
#define __CS35L56_HDA_H__
|
#define __CS35L56_HDA_H__
|
||||||
|
|
||||||
|
#include <linux/container_of.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/firmware/cirrus/cs_dsp.h>
|
#include <linux/firmware/cirrus/cs_dsp.h>
|
||||||
|
|
@ -42,6 +43,11 @@ struct cs35l56_hda {
|
||||||
#endif
|
#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;
|
extern const struct dev_pm_ops cs35l56_hda_pm_ops;
|
||||||
|
|
||||||
int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id);
|
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)
|
static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
|
||||||
{
|
{
|
||||||
|
struct gpio_desc *speaker_id;
|
||||||
struct acpi_device *adev;
|
struct acpi_device *adev;
|
||||||
struct device *physdev;
|
struct device *physdev;
|
||||||
LIST_HEAD(resources);
|
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. */
|
/* Speaker id was needed for ASUS projects. */
|
||||||
ret = kstrtou32(sub, 16, &subid);
|
ret = kstrtou32(sub, 16, &subid);
|
||||||
if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
|
if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
|
||||||
ret = devm_acpi_dev_add_driver_gpios(p->dev,
|
ret = acpi_dev_add_driver_gpios(adev, tas2781_speaker_id_gpios);
|
||||||
tas2781_speaker_id_gpios);
|
if (ret < 0) {
|
||||||
if (ret < 0)
|
|
||||||
dev_err(p->dev, "Failed to add driver gpio %d.\n",
|
dev_err(p->dev, "Failed to add driver gpio %d.\n",
|
||||||
ret);
|
ret);
|
||||||
p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN);
|
p->speaker_id = -1;
|
||||||
if (IS_ERR(p->speaker_id)) {
|
goto end_2563;
|
||||||
dev_err(p->dev, "Failed to get Speaker id.\n");
|
|
||||||
ret = PTR_ERR(p->speaker_id);
|
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = -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 {
|
} else {
|
||||||
p->speaker_id = NULL;
|
p->speaker_id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
end_2563:
|
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 *tas_hda = dev_get_drvdata(tas_priv->dev);
|
||||||
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
|
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
|
||||||
struct hda_codec *codec = tas_priv->codec;
|
struct hda_codec *codec = tas_priv->codec;
|
||||||
int ret, spk_id;
|
int ret;
|
||||||
|
|
||||||
tasdevice_dsp_remove(tas_priv);
|
tasdevice_dsp_remove(tas_priv);
|
||||||
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
|
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
|
||||||
if (tas_priv->speaker_id != NULL) {
|
if (tas_priv->speaker_id >= 0) {
|
||||||
// Speaker id need to be checked for ASUS only.
|
|
||||||
spk_id = gpiod_get_value(tas_priv->speaker_id);
|
|
||||||
if (spk_id < 0) {
|
|
||||||
// Speaker id is not valid, use default.
|
|
||||||
dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id);
|
|
||||||
spk_id = 0;
|
|
||||||
}
|
|
||||||
snprintf(tas_priv->coef_binaryname,
|
snprintf(tas_priv->coef_binaryname,
|
||||||
sizeof(tas_priv->coef_binaryname),
|
sizeof(tas_priv->coef_binaryname),
|
||||||
"TAS2XXX%04X%d.bin",
|
"TAS2XXX%04X%d.bin",
|
||||||
lower_16_bits(codec->core.subsystem_id),
|
lower_16_bits(codec->core.subsystem_id),
|
||||||
spk_id);
|
tas_priv->speaker_id);
|
||||||
} else {
|
} else {
|
||||||
snprintf(tas_priv->coef_binaryname,
|
snprintf(tas_priv->coef_binaryname,
|
||||||
sizeof(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