mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Merge tag 'sound-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"Nothing too thrilling here, but we see lots of driver updates and bug
fixes, including quirk additions and refactoring works, while there
have been little changes in the core functionality. Here are some
highlights:
Core:
- Add validation for the control API put callback
- Fixes in compress-offload API timestamp handling
- Continued ASoC core API cleanups
ASoC:
- Add support for bus keepers (for Apple devices in future)
- Enhancements to the SDCA support, including retaskable jacks
- Test improvements for Cirrus Logic drivers
- Lots of fixes for the NXP, nVidia and Qualcomm
- Support for AMD RPL DMIC, Cirrus Logic CS42L43 and CS47L47, nVidia
machines with CPCAP and WM8962
USB-audio:
- Quirks for Huawei Headset, Focusrite Novation, MV-Silicon, Studio
1824, Arturia AF16Rig, Hotone Audio, Feaulle Rainbow, PreSonus
AudioBox, Moondrop Ju Jiu, Scarlett 18i20, etc
- Extended mixer volume quirk handling
- UAF and other fixes for us144mkii, 6fire and caiaq drivers
HD-audio:
- Add quirks or fixes for Acer, Lenovo, HP, ASUS machines
- Fixes & cleanups of GPIO helper code
Misc:
- Add suspend/resume support for multiple legacy ISA and Apple
drivers
- Further regression fixes for ctxfi driver"
* tag 'sound-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (359 commits)
ALSA: control: Validate buf_len before strnlen() in snd_ctl_elem_init_enum_names()
ALSA: usb-audio: Fix missing error handling for get_min_max*()
ALSA: hda/realtek - fixed speaker no sound update
ALSA: hda/realtek: Add quirk for Acer PT316-51S headset mic
ALSA: usb-audio: Exclude Scarlett 18i20 1st Gen from SKIP_IFACE_SETUP
ALSA: hda/realtek: Add quirk for Legion S7 15IMH
ALSA: hda/realtek: Add quirk for HP Spectre x360 14-ea
ALSA: caiaq: take a reference on the USB device in create_card()
ASoC: dt-bindings: rockchip: convert rk3399-gru-sound to DT Schema
ALSA: sscape: Add suspend and resume support
ALSA: sscape: Cache per-card resources for board reinitialization
ALSA: usb-audio: Do not expose sticky mixers
ALSA: usb-audio: Move volume control resolution check into a function
ALSA: usb-audio: Add error checks against get_min_max*()
ALSA: usb-audio: Add quirk for PreSonus AudioBox USB
ALSA: interwave: guard PM-only restore helpers with CONFIG_PM
ALSA: usb-audio: Evaluate packsize caps at the right place
ALSA: sc6000: Restore board setup across suspend
ALSA: sc6000: Keep the programmed board state in card-private data
ALSA: 6fire: fix use-after-free on disconnect
...
This commit is contained in:
@@ -1,14 +0,0 @@
|
||||
Analog Devices SSM2305 Speaker Amplifier
|
||||
========================================
|
||||
|
||||
Required properties:
|
||||
- compatible : "adi,ssm2305"
|
||||
- shutdown-gpios : The gpio connected to the shutdown pin.
|
||||
The gpio signal is ACTIVE_LOW.
|
||||
|
||||
Example:
|
||||
|
||||
ssm2305: analog-amplifier {
|
||||
compatible = "adi,ssm2305";
|
||||
shutdown-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
46
Documentation/devicetree/bindings/sound/adi,ssm2305.yaml
Normal file
46
Documentation/devicetree/bindings/sound/adi,ssm2305.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/adi,ssm2305.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices SSM2305 Class-D Speaker Amplifier
|
||||
|
||||
maintainers:
|
||||
- Lars-Peter Clausen <lars@metafoo.de>
|
||||
|
||||
description:
|
||||
The SSM2305 is a filterless, high efficiency, mono 2.8 W Class-D
|
||||
audio amplifier with a micropower shutdown mode controlled via a
|
||||
dedicated active-low GPIO pin.
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: adi,ssm2305
|
||||
|
||||
shutdown-gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
GPIO connected to the shutdown pin (SD) of the SSM2305.
|
||||
The pin is active-low; asserting it puts the device into
|
||||
micropower shutdown mode.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- shutdown-gpios
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
analog-amplifier {
|
||||
compatible = "adi,ssm2305";
|
||||
shutdown-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
...
|
||||
@@ -35,6 +35,10 @@ properties:
|
||||
|
||||
dvdd-supply: true
|
||||
|
||||
firmware-name:
|
||||
maxItems: 1
|
||||
description: Name of the *_acf.bin file used for amplifier initialization
|
||||
|
||||
awinic,audio-channel:
|
||||
description:
|
||||
It is used to distinguish multiple PA devices, so that different
|
||||
|
||||
@@ -16,6 +16,8 @@ description: |
|
||||
DAC for headphone output, two integrated Class D amplifiers for
|
||||
loudspeakers, and two ADCs for wired headset microphone input or
|
||||
stereo line input. PDM inputs are provided for digital microphones.
|
||||
CS42L43B variant adds dedicated PDM interface, SoundWire Clock Gearing
|
||||
support and more decimators to ISRCs.
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
@@ -24,6 +26,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- cirrus,cs42l43
|
||||
- cirrus,cs42l43b
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
* Hisilicon 6210 i2s controller
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be one of the following:
|
||||
- "hisilicon,hi6210-i2s"
|
||||
- reg: physical base address of the i2s controller unit and length of
|
||||
memory mapped region.
|
||||
- interrupts: should contain the i2s interrupt.
|
||||
- clocks: a list of phandle + clock-specifier pairs, one for each entry
|
||||
in clock-names.
|
||||
- clock-names: should contain following:
|
||||
- "dacodec"
|
||||
- "i2s-base"
|
||||
- dmas: DMA specifiers for tx dma. See the DMA client binding,
|
||||
Documentation/devicetree/bindings/dma/dma.txt
|
||||
- dma-names: should be "tx" and "rx"
|
||||
- hisilicon,sysctrl-syscon: phandle to sysctrl syscon
|
||||
- #sound-dai-cells: Should be set to 1 (for multi-dai)
|
||||
- The dai cell indexes reference the following interfaces:
|
||||
0: S2 interface
|
||||
(Currently that is the only one available, but more may be
|
||||
supported in the future)
|
||||
|
||||
Example for the hi6210 i2s controller:
|
||||
|
||||
i2s0: i2s@f7118000{
|
||||
compatible = "hisilicon,hi6210-i2s";
|
||||
reg = <0x0 0xf7118000 0x0 0x8000>; /* i2s unit */
|
||||
interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>; /* 155 "DigACodec_intr"-32 */
|
||||
clocks = <&sys_ctrl HI6220_DACODEC_PCLK>,
|
||||
<&sys_ctrl HI6220_BBPPLL0_DIV>;
|
||||
clock-names = "dacodec", "i2s-base";
|
||||
dmas = <&dma0 15 &dma0 14>;
|
||||
dma-names = "rx", "tx";
|
||||
hisilicon,sysctrl-syscon = <&sys_ctrl>;
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
|
||||
Then when referencing the i2s controller:
|
||||
sound-dai = <&i2s0 0>; /* index 0 => S2 interface */
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/hisilicon,hi6210-i2s.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: HiSilicon hi6210 I2S controller
|
||||
|
||||
maintainers:
|
||||
- John Stultz <john.stultz@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: hisilicon,hi6210-i2s
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: dacodec
|
||||
- const: i2s-base
|
||||
|
||||
dmas:
|
||||
maxItems: 2
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
hisilicon,sysctrl-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: phandle to sysctrl syscon
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 1
|
||||
description: |
|
||||
The dai cell indexes reference the following interfaces:
|
||||
0: S2 interface
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- dmas
|
||||
- dma-names
|
||||
- hisilicon,sysctrl-syscon
|
||||
- "#sound-dai-cells"
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/hi6220-clock.h>
|
||||
|
||||
i2s@f7118000 {
|
||||
compatible = "hisilicon,hi6210-i2s";
|
||||
reg = <0xf7118000 0x8000>;
|
||||
interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&sys_ctrl HI6220_DACODEC_PCLK>,
|
||||
<&sys_ctrl HI6220_BBPPLL0_DIV>;
|
||||
clock-names = "dacodec", "i2s-base";
|
||||
dmas = <&dma0 14>, <&dma0 15>;
|
||||
dma-names = "tx", "rx";
|
||||
hisilicon,sysctrl-syscon = <&sys_ctrl>;
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
@@ -24,6 +24,7 @@ patternProperties:
|
||||
cpu/codec dais.
|
||||
|
||||
type: object
|
||||
$ref: tdm-slot.yaml#
|
||||
|
||||
properties:
|
||||
link-name:
|
||||
@@ -38,13 +39,9 @@ patternProperties:
|
||||
- i2s
|
||||
- dsp_b
|
||||
|
||||
dai-tdm-slot-num:
|
||||
description: see tdm-slot.txt.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
dai-tdm-slot-num: true
|
||||
|
||||
dai-tdm-slot-width:
|
||||
description: see tdm-slot.txt.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
dai-tdm-slot-width: true
|
||||
|
||||
playback-only:
|
||||
description: link is used only for playback
|
||||
|
||||
@@ -28,8 +28,6 @@ properties:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: The phandle of the WM8960 audio codec.
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- mediatek,platform
|
||||
@@ -38,6 +36,8 @@ required:
|
||||
- pinctrl-names
|
||||
- pinctrl-0
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sound {
|
||||
|
||||
@@ -36,14 +36,14 @@ properties:
|
||||
required:
|
||||
- sound-dai
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- audio-routing
|
||||
- platform
|
||||
- codec
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sound {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/mediatek,mt8173-rt5650-rt5514.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mediatek MT8173 with RT5650 and RT5514 audio codecs
|
||||
|
||||
maintainers:
|
||||
- Koro Chen <koro.chen@mediatek.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mediatek,mt8173-rt5650-rt5514
|
||||
|
||||
mediatek,audio-codec:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: Phandles of rt5650 and rt5514 codecs
|
||||
items:
|
||||
- description: phandle of rt5650 codec
|
||||
- description: phandle of rt5514 codec
|
||||
|
||||
mediatek,platform:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: The phandle of MT8173 ASoC platform.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- mediatek,audio-codec
|
||||
- mediatek,platform
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sound {
|
||||
compatible = "mediatek,mt8173-rt5650-rt5514";
|
||||
mediatek,audio-codec = <&rt5650>, <&rt5514>;
|
||||
mediatek,platform = <&afe>;
|
||||
};
|
||||
...
|
||||
@@ -105,12 +105,12 @@ patternProperties:
|
||||
required:
|
||||
- link-name
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- mediatek,platform
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sound {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
MT8173 with RT5650 RT5514 CODECS
|
||||
|
||||
Required properties:
|
||||
- compatible : "mediatek,mt8173-rt5650-rt5514"
|
||||
- mediatek,audio-codec: the phandles of rt5650 and rt5514 codecs
|
||||
- mediatek,platform: the phandle of MT8173 ASoC platform
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "mediatek,mt8173-rt5650-rt5514";
|
||||
mediatek,audio-codec = <&rt5650 &rt5514>;
|
||||
mediatek,platform = <&afe>;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-cpcap.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NVIDIA Tegra audio complex with CPCAP CODEC
|
||||
|
||||
maintainers:
|
||||
- Svyatoslav Ryhel <clamor95@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: nvidia,tegra-audio-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- pattern: '^motorola,tegra-audio-cpcap(-[a-z0-9]+)+$'
|
||||
- const: nvidia,tegra-audio-cpcap
|
||||
|
||||
nvidia,audio-routing:
|
||||
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||
description:
|
||||
A list of the connections between audio components. Each entry is a
|
||||
pair of strings, the first being the connection's sink, the second
|
||||
being the connection's source. Valid names for sources and sinks are
|
||||
the pins (documented in the binding document), and the jacks on the
|
||||
board.
|
||||
minItems: 2
|
||||
items:
|
||||
enum:
|
||||
# Board Connectors
|
||||
- Speakers
|
||||
- Int Spk
|
||||
- Earpiece
|
||||
- Int Mic
|
||||
- Headset Mic
|
||||
- Internal Mic 1
|
||||
- Internal Mic 2
|
||||
- Headphone
|
||||
- Headphones
|
||||
- Headphone Jack
|
||||
- Mic Jack
|
||||
|
||||
# CODEC Pins
|
||||
- MICR
|
||||
- HSMIC
|
||||
- EMUMIC
|
||||
- MICL
|
||||
- EXTR
|
||||
- EXTL
|
||||
- EP
|
||||
- SPKR
|
||||
- SPKL
|
||||
- LINER
|
||||
- LINEL
|
||||
- HSR
|
||||
- HSL
|
||||
- EMUR
|
||||
- EMUL
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/tegra20-car.h>
|
||||
#include <dt-bindings/soc/tegra-pmc.h>
|
||||
sound {
|
||||
compatible = "motorola,tegra-audio-cpcap-olympus",
|
||||
"nvidia,tegra-audio-cpcap";
|
||||
nvidia,model = "Motorola Atrix 4G (MB860) CPCAP";
|
||||
|
||||
nvidia,audio-routing =
|
||||
"Headphones", "HSR",
|
||||
"Headphones", "HSL",
|
||||
"Int Spk", "SPKR",
|
||||
"Int Spk", "SPKL",
|
||||
"Earpiece", "EP",
|
||||
"HSMIC", "Mic Jack",
|
||||
"MICR", "Internal Mic 1",
|
||||
"MICL", "Internal Mic 2";
|
||||
|
||||
nvidia,i2s-controller = <&tegra_i2s1>;
|
||||
nvidia,audio-codec = <&cpcap_audio>;
|
||||
|
||||
clocks = <&tegra_car TEGRA20_CLK_PLL_A>,
|
||||
<&tegra_car TEGRA20_CLK_PLL_A_OUT0>,
|
||||
<&tegra_car TEGRA20_CLK_CDEV1>;
|
||||
clock-names = "pll_a", "pll_a_out0", "mclk";
|
||||
};
|
||||
@@ -35,10 +35,15 @@ properties:
|
||||
items:
|
||||
enum:
|
||||
# Board Connectors
|
||||
- Speakers
|
||||
- Int Spk
|
||||
- Headphone
|
||||
- Headphones
|
||||
- Headphone Jack
|
||||
- Earpiece
|
||||
- Headset Mic
|
||||
- Mic Jack
|
||||
- Int Mic
|
||||
- Internal Mic 1
|
||||
- Internal Mic 2
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-wm8962.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NVIDIA Tegra audio complex with WM8962 CODEC
|
||||
|
||||
maintainers:
|
||||
- Svyatoslav Ryhel <clamor95@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: nvidia,tegra-audio-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- pattern: '^[a-z0-9]+,tegra-audio-wm8962(-[a-z0-9]+)+$'
|
||||
- const: nvidia,tegra-audio-wm8962
|
||||
|
||||
nvidia,audio-routing:
|
||||
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||
description:
|
||||
A list of the connections between audio components. Each entry is a
|
||||
pair of strings, the first being the connection's sink, the second
|
||||
being the connection's source. Valid names for sources and sinks are
|
||||
the pins (documented in the binding document), and the jacks on the
|
||||
board.
|
||||
minItems: 2
|
||||
items:
|
||||
enum:
|
||||
# Board Connectors
|
||||
- Speakers
|
||||
- Int Spk
|
||||
- Earpiece
|
||||
- Int Mic
|
||||
- Headset Mic
|
||||
- Internal Mic 1
|
||||
- Internal Mic 2
|
||||
- Headphone
|
||||
- Headphones
|
||||
- Headphone Jack
|
||||
- Mic Jack
|
||||
|
||||
# CODEC Pins
|
||||
- IN1L
|
||||
- IN1R
|
||||
- IN2L
|
||||
- IN2R
|
||||
- IN3L
|
||||
- IN3R
|
||||
- IN4L
|
||||
- IN4R
|
||||
- DMICDAT
|
||||
- HPOUTL
|
||||
- HPOUTR
|
||||
- SPKOUT
|
||||
- SPKOUTL
|
||||
- SPKOUTR
|
||||
|
||||
required:
|
||||
- nvidia,i2s-controller
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/tegra30-car.h>
|
||||
#include <dt-bindings/soc/tegra-pmc.h>
|
||||
sound {
|
||||
compatible = "microsoft,tegra-audio-wm8962-surface-rt",
|
||||
"nvidia,tegra-audio-wm8962";
|
||||
nvidia,model = "Microsoft Surface RT WM8962";
|
||||
|
||||
nvidia,audio-routing =
|
||||
"Headphone Jack", "HPOUTR",
|
||||
"Headphone Jack", "HPOUTL",
|
||||
"Int Spk", "SPKOUTR",
|
||||
"Int Spk", "SPKOUTL";
|
||||
|
||||
nvidia,i2s-controller = <&tegra_i2s1>;
|
||||
nvidia,audio-codec = <&wm8962>;
|
||||
|
||||
clocks = <&tegra_car TEGRA30_CLK_PLL_A>,
|
||||
<&tegra_car TEGRA30_CLK_PLL_A_OUT0>,
|
||||
<&tegra_pmc TEGRA_PMC_CLK_OUT_1>;
|
||||
clock-names = "pll_a", "pll_a_out0", "mclk";
|
||||
};
|
||||
@@ -126,13 +126,16 @@ patternProperties:
|
||||
reg:
|
||||
contains:
|
||||
# MI2S DAI ID range PRIMARY_MI2S_RX - QUATERNARY_MI2S_TX and
|
||||
# QUINARY_MI2S_RX - QUINARY_MI2S_TX
|
||||
# QUINARY_MI2S_RX - QUINARY_MI2S_TX and
|
||||
# LPI_MI2S_RX_0 - SENARY_MI2S_TX
|
||||
items:
|
||||
oneOf:
|
||||
- minimum: 16
|
||||
maximum: 23
|
||||
- minimum: 127
|
||||
maximum: 128
|
||||
- minimum: 137
|
||||
maximum: 148
|
||||
then:
|
||||
required:
|
||||
- qcom,sd-lines
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards
|
||||
|
||||
Required properties:
|
||||
- compatible: "rockchip,rk3399-gru-sound"
|
||||
- rockchip,cpu: The phandle of the Rockchip I2S controller that's
|
||||
connected to the codecs
|
||||
- rockchip,codec: The phandle of the audio codecs
|
||||
|
||||
Optional properties:
|
||||
- dmic-wakeup-delay-ms : specify delay time (ms) for DMIC ready.
|
||||
If this option is specified, which means it's required dmic need
|
||||
delay for DMIC to ready so that rt5514 can avoid recording before
|
||||
DMIC send valid data
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "rockchip,rk3399-gru-sound";
|
||||
rockchip,cpu = <&i2s0>;
|
||||
rockchip,codec = <&max98357a &rt5514 &da7219>;
|
||||
dmic-wakeup-delay-ms = <20>;
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/rockchip,rk3399-gru-sound.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip with MAX98357A/RT5514/DA7219 codecs on GRU boards
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rockchip,rk3399-gru-sound
|
||||
|
||||
rockchip,cpu:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: |
|
||||
List of phandles to the Rockchip CPU DAI controllers connected to codecs
|
||||
minItems: 1
|
||||
items:
|
||||
- items:
|
||||
- description: Phandle to the Rockchip I2S controllers
|
||||
- items:
|
||||
- description: |
|
||||
Phandle to the Rockchip SPDIF controller. Required when a
|
||||
DisplayPort audio codec is referenced in rockchip,codec
|
||||
|
||||
rockchip,codec:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description: |
|
||||
The phandles of the audio codecs connected to the Rockchip CPU DAI
|
||||
controllers
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
items:
|
||||
maxItems: 1
|
||||
|
||||
dmic-wakeup-delay-ms:
|
||||
description: |
|
||||
specify delay time (ms) for DMIC ready.
|
||||
If this option is specified, a delay is required for DMIC to get ready
|
||||
so that rt5514 can avoid recording before DMIC sends valid data
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- rockchip,cpu
|
||||
- rockchip,codec
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sound {
|
||||
compatible = "rockchip,rk3399-gru-sound";
|
||||
rockchip,cpu = <&i2s0 &spdif>;
|
||||
rockchip,codec = <&max98357a &rt5514 &da7219 &cdn_dp>;
|
||||
dmic-wakeup-delay-ms = <20>;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/rockchip,rockchip-audio-max98090.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip audio complex with MAX98090 codec
|
||||
|
||||
maintainers:
|
||||
- Fabio Estevam <festevam@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rockchip,rockchip-audio-max98090
|
||||
|
||||
rockchip,model:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: The user-visible name of this sound complex.
|
||||
|
||||
rockchip,i2s-controller:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: Phandle to the Rockchip I2S controller.
|
||||
|
||||
rockchip,audio-codec:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: Phandle to the MAX98090 audio codec.
|
||||
|
||||
rockchip,headset-codec:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: Phandle to the external chip for jack detection.
|
||||
|
||||
rockchip,hdmi-codec:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: Phandle to the HDMI device for HDMI codec.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- rockchip,model
|
||||
- rockchip,i2s-controller
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
required:
|
||||
- rockchip,audio-codec
|
||||
then:
|
||||
required:
|
||||
- rockchip,headset-codec
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sound {
|
||||
compatible = "rockchip,rockchip-audio-max98090";
|
||||
rockchip,model = "ROCKCHIP-I2S";
|
||||
rockchip,i2s-controller = <&i2s>;
|
||||
rockchip,audio-codec = <&max98090>;
|
||||
rockchip,headset-codec = <&headsetcodec>;
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
ROCKCHIP with MAX98090 CODEC
|
||||
|
||||
Required properties:
|
||||
- compatible: "rockchip,rockchip-audio-max98090"
|
||||
- rockchip,model: The user-visible name of this sound complex
|
||||
- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's
|
||||
connected to the CODEC
|
||||
|
||||
Optional properties:
|
||||
- rockchip,audio-codec: The phandle of the MAX98090 audio codec.
|
||||
- rockchip,headset-codec: The phandle of Ext chip for jack detection. This is
|
||||
required if there is rockchip,audio-codec.
|
||||
- rockchip,hdmi-codec: The phandle of HDMI device for HDMI codec.
|
||||
|
||||
Example:
|
||||
|
||||
/* For max98090-only board. */
|
||||
sound {
|
||||
compatible = "rockchip,rockchip-audio-max98090";
|
||||
rockchip,model = "ROCKCHIP-I2S";
|
||||
rockchip,i2s-controller = <&i2s>;
|
||||
rockchip,audio-codec = <&max98090>;
|
||||
rockchip,headset-codec = <&headsetcodec>;
|
||||
};
|
||||
|
||||
/* For HDMI-only board. */
|
||||
sound {
|
||||
compatible = "rockchip,rockchip-audio-max98090";
|
||||
rockchip,model = "ROCKCHIP-I2S";
|
||||
rockchip,i2s-controller = <&i2s>;
|
||||
rockchip,hdmi-codec = <&hdmi>;
|
||||
};
|
||||
|
||||
/* For max98090 plus HDMI board. */
|
||||
sound {
|
||||
compatible = "rockchip,rockchip-audio-max98090";
|
||||
rockchip,model = "ROCKCHIP-I2S";
|
||||
rockchip,i2s-controller = <&i2s>;
|
||||
rockchip,audio-codec = <&max98090>;
|
||||
rockchip,headset-codec = <&headsetcodec>;
|
||||
rockchip,hdmi-codec = <&hdmi>;
|
||||
};
|
||||
@@ -27,14 +27,6 @@ definitions:
|
||||
description: dai-link uses bit clock inversion
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
dai-tdm-slot-num:
|
||||
description: see tdm-slot.txt.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
dai-tdm-slot-width:
|
||||
description: see tdm-slot.txt.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
system-clock-frequency:
|
||||
description: |
|
||||
If a clock is specified and a multiplication factor is given with
|
||||
@@ -115,6 +107,8 @@ definitions:
|
||||
|
||||
dai:
|
||||
type: object
|
||||
$ref: tdm-slot.yaml#
|
||||
|
||||
properties:
|
||||
sound-dai:
|
||||
maxItems: 1
|
||||
@@ -133,10 +127,6 @@ definitions:
|
||||
bitclock-master:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
dai-tdm-slot-num:
|
||||
$ref: "#/definitions/dai-tdm-slot-num"
|
||||
dai-tdm-slot-width:
|
||||
$ref: "#/definitions/dai-tdm-slot-width"
|
||||
clocks:
|
||||
maxItems: 1
|
||||
system-clock-frequency:
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
TDM slot:
|
||||
|
||||
This specifies audio DAI's TDM slot.
|
||||
|
||||
TDM slot properties:
|
||||
dai-tdm-slot-num : Number of slots in use.
|
||||
dai-tdm-slot-width : Width in bits for each slot.
|
||||
dai-tdm-slot-tx-mask : Transmit direction slot mask, optional
|
||||
dai-tdm-slot-rx-mask : Receive direction slot mask, optional
|
||||
|
||||
For instance:
|
||||
dai-tdm-slot-num = <2>;
|
||||
dai-tdm-slot-width = <8>;
|
||||
dai-tdm-slot-tx-mask = <0 1>;
|
||||
dai-tdm-slot-rx-mask = <1 0>;
|
||||
|
||||
And for each specified driver, there could be one .of_xlate_tdm_slot_mask()
|
||||
to specify an explicit mapping of the channels and the slots. If it's absent
|
||||
the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the
|
||||
tx and rx masks.
|
||||
|
||||
For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit
|
||||
for an active slot as default, and the default active bits are at the LSB of
|
||||
the masks.
|
||||
|
||||
The explicit masks are given as array of integers, where the first
|
||||
number presents bit-0 (LSB), second presents bit-1, etc. Any non zero
|
||||
number is considered 1 and 0 is 0. snd_soc_of_xlate_tdm_slot_mask()
|
||||
does not do anything, if either mask is set non zero value.
|
||||
52
Documentation/devicetree/bindings/sound/tdm-slot.yaml
Normal file
52
Documentation/devicetree/bindings/sound/tdm-slot.yaml
Normal file
@@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/tdm-slot.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Time Division Multiplexing (TDM) Slot Parameters
|
||||
|
||||
maintainers:
|
||||
- Liam Girdwood <lgirdwood@gmail.com>
|
||||
|
||||
select: false
|
||||
|
||||
properties:
|
||||
dai-tdm-slot-num:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Number of slots in use
|
||||
|
||||
dai-tdm-slot-width:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Width, in bits, of each slot
|
||||
|
||||
dai-tdm-idle-mode:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum:
|
||||
- none
|
||||
- off
|
||||
- zero
|
||||
- pulldown
|
||||
- hiz
|
||||
- pullup
|
||||
- drivehigh
|
||||
description: Drive mode for inactive/idle TDM slots. For hardware that
|
||||
implements .set_tdm_idle(). Optional. "None" represents undefined
|
||||
behaviour and is the same as not setting this property.
|
||||
|
||||
patternProperties:
|
||||
'^dai-tdm-slot-[rt]x-mask$':
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description: Slot mask for active TDM slots. Optional. Drivers may
|
||||
specify .xlate_tdm_slot_mask() to generate a slot mask dynamically. If
|
||||
neither this property nor a driver-specific function are specified, the
|
||||
default snd_soc_xlate_tdm_slot_mask() function will be used to generate
|
||||
a mask. The first element of the array is slot 0 (LSB). Any nonzero
|
||||
value will be treated as 1.
|
||||
|
||||
'^dai-tdm-slot-[rt]x-idle-mask$':
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Idle slot mask. Optional. A bit being set to 1 indicates
|
||||
that the corresponding TDM slot is inactive/idle.
|
||||
|
||||
additionalProperties: true
|
||||
@@ -30,7 +30,7 @@ properties:
|
||||
description: |
|
||||
I2C address of the device can be between 0x41 to 0x48.
|
||||
|
||||
reset-gpio:
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO used to reset the device.
|
||||
|
||||
@@ -82,7 +82,7 @@ examples:
|
||||
#sound-dai-cells = <0>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <14>;
|
||||
reset-gpio = <&gpio1 15 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
|
||||
shutdown-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
|
||||
ti,imon-slot-no = <0>;
|
||||
ti,vmon-slot-no = <2>;
|
||||
|
||||
@@ -2376,6 +2376,13 @@ quirk_flags
|
||||
Skip the probe-time interface setup (usb_set_interface,
|
||||
init_pitch, init_sample_rate); redundant with
|
||||
snd_usb_endpoint_prepare() at stream-open time
|
||||
* bit 27: ``mixer_playback_linear_vol``
|
||||
Set linear volume mapping for devices where the playback volume
|
||||
control value is mapped to voltage (instead of dB) level linearly.
|
||||
In short: ``x(raw) = (raw - raw_min) / (raw_max - raw_min)``;
|
||||
``V(x) = k * x``; ``dB(x) = 20 * log10(x)``. Overrides bit 24
|
||||
* bit 28: ``mixer_capture_linear_vol``
|
||||
Similar to bit 27 but for capture streams. Overrides bit 25
|
||||
|
||||
This module supports multiple devices, autoprobe and hotplugging.
|
||||
|
||||
|
||||
@@ -239,7 +239,6 @@ static struct gpiod_lookup_table wm8994_gpiod_table = {
|
||||
static struct arizona_pdata wm5102_reva_pdata = {
|
||||
.gpio_base = CODEC_GPIO_BASE,
|
||||
.irq_flags = IRQF_TRIGGER_HIGH,
|
||||
.micd_pol_gpio = CODEC_GPIO_BASE + 4,
|
||||
.micd_rate = 6,
|
||||
.gpio_defaults = {
|
||||
[2] = 0x10000, /* AIF3TXLRCLK */
|
||||
@@ -265,6 +264,8 @@ static struct gpiod_lookup_table wm5102_reva_gpiod_table = {
|
||||
.table = {
|
||||
GPIO_LOOKUP("GPION", 7,
|
||||
"wlf,ldoena", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("arizona", 4,
|
||||
"wlf,micd-pol", GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
@@ -272,7 +273,6 @@ static struct gpiod_lookup_table wm5102_reva_gpiod_table = {
|
||||
static struct arizona_pdata wm5102_pdata = {
|
||||
.gpio_base = CODEC_GPIO_BASE,
|
||||
.irq_flags = IRQF_TRIGGER_HIGH,
|
||||
.micd_pol_gpio = CODEC_GPIO_BASE + 2,
|
||||
.gpio_defaults = {
|
||||
[2] = 0x10000, /* AIF3TXLRCLK */
|
||||
[3] = 0x4, /* OPCLK */
|
||||
@@ -297,6 +297,8 @@ static struct gpiod_lookup_table wm5102_gpiod_table = {
|
||||
.table = {
|
||||
GPIO_LOOKUP("GPION", 7,
|
||||
"wlf,ldo1ena", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("arizona", 2,
|
||||
"wlf,micd-pol", GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* Cirrus Logic International Semiconductor Ltd.
|
||||
*/
|
||||
|
||||
#include <kunit/static_stub.h>
|
||||
#include <kunit/visibility.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/ctype.h>
|
||||
@@ -18,6 +19,7 @@
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
@@ -30,45 +32,47 @@
|
||||
/*
|
||||
* When the KUnit test is running the error-case tests will cause a lot
|
||||
* of messages. Rate-limit to prevent overflowing the kernel log buffer
|
||||
* during KUnit test runs.
|
||||
* during KUnit test runs and allow the test to redirect this function.
|
||||
* In normal (not KUnit) builds this collapses to only return true.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_FW_CS_DSP_KUNIT_TEST)
|
||||
bool cs_dsp_suppress_err_messages;
|
||||
EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_err_messages);
|
||||
VISIBLE_IF_KUNIT bool cs_dsp_can_emit_message(void)
|
||||
{
|
||||
KUNIT_STATIC_STUB_REDIRECT(cs_dsp_can_emit_message);
|
||||
|
||||
bool cs_dsp_suppress_warn_messages;
|
||||
EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_warn_messages);
|
||||
if (IS_ENABLED(CONFIG_FW_CS_DSP_KUNIT_TEST)) {
|
||||
static DEFINE_RATELIMIT_STATE(_rs,
|
||||
DEFAULT_RATELIMIT_INTERVAL,
|
||||
DEFAULT_RATELIMIT_BURST);
|
||||
return __ratelimit(&_rs);
|
||||
}
|
||||
|
||||
bool cs_dsp_suppress_info_messages;
|
||||
EXPORT_SYMBOL_IF_KUNIT(cs_dsp_suppress_info_messages);
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(cs_dsp_can_emit_message);
|
||||
|
||||
#define cs_dsp_err(_dsp, fmt, ...) \
|
||||
do { \
|
||||
if (!cs_dsp_suppress_err_messages) \
|
||||
dev_err_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
|
||||
#define cs_dsp_err(_dsp, fmt, ...) \
|
||||
do { \
|
||||
if (cs_dsp_can_emit_message()) \
|
||||
dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
|
||||
} while (false)
|
||||
#define cs_dsp_warn(_dsp, fmt, ...) \
|
||||
do { \
|
||||
if (!cs_dsp_suppress_warn_messages) \
|
||||
dev_warn_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
|
||||
|
||||
#define cs_dsp_warn(_dsp, fmt, ...) \
|
||||
do { \
|
||||
if (cs_dsp_can_emit_message()) \
|
||||
dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
|
||||
} while (false)
|
||||
#define cs_dsp_info(_dsp, fmt, ...) \
|
||||
do { \
|
||||
if (!cs_dsp_suppress_info_messages) \
|
||||
dev_info_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
|
||||
|
||||
#define cs_dsp_info(_dsp, fmt, ...) \
|
||||
do { \
|
||||
if (cs_dsp_can_emit_message()) \
|
||||
dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
|
||||
} while (false)
|
||||
|
||||
#define cs_dsp_dbg(_dsp, fmt, ...) \
|
||||
do { \
|
||||
if (cs_dsp_can_emit_message()) \
|
||||
dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__); \
|
||||
} while (false)
|
||||
#define cs_dsp_dbg(_dsp, fmt, ...) \
|
||||
dev_dbg_ratelimited(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
#else
|
||||
#define cs_dsp_err(_dsp, fmt, ...) \
|
||||
dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
#define cs_dsp_warn(_dsp, fmt, ...) \
|
||||
dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
#define cs_dsp_info(_dsp, fmt, ...) \
|
||||
dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
#define cs_dsp_dbg(_dsp, fmt, ...) \
|
||||
dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define ADSP1_CONTROL_1 0x00
|
||||
#define ADSP1_CONTROL_2 0x02
|
||||
@@ -515,6 +519,7 @@ void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root)
|
||||
|
||||
debugfs_create_bool("booted", 0444, root, &dsp->booted);
|
||||
debugfs_create_bool("running", 0444, root, &dsp->running);
|
||||
debugfs_create_bool("hibernating", 0444, root, &dsp->hibernating);
|
||||
debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
|
||||
debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
|
||||
|
||||
@@ -703,7 +708,7 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int
|
||||
|
||||
lockdep_assert_held(&dsp->pwr_lock);
|
||||
|
||||
if (!dsp->running)
|
||||
if (!dsp->running || dsp->hibernating)
|
||||
return -EPERM;
|
||||
|
||||
ret = cs_dsp_coeff_base_reg(ctl, ®, 0);
|
||||
@@ -827,7 +832,7 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
|
||||
}
|
||||
|
||||
ctl->set = 1;
|
||||
if (ctl->enabled && ctl->dsp->running)
|
||||
if (ctl->enabled && ctl->dsp->running && !ctl->dsp->hibernating)
|
||||
ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len);
|
||||
|
||||
if (ret < 0)
|
||||
@@ -920,12 +925,12 @@ int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl,
|
||||
return -EINVAL;
|
||||
|
||||
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
|
||||
if (ctl->enabled && ctl->dsp->running)
|
||||
if (ctl->enabled && ctl->dsp->running && !ctl->dsp->hibernating)
|
||||
return cs_dsp_coeff_read_ctrl_raw(ctl, off, buf, len);
|
||||
else
|
||||
return -EPERM;
|
||||
} else {
|
||||
if (!ctl->flags && ctl->enabled && ctl->dsp->running)
|
||||
if (!ctl->flags && ctl->enabled && ctl->dsp->running && !ctl->dsp->hibernating)
|
||||
ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len);
|
||||
|
||||
if (buf != ctl->cache)
|
||||
@@ -1108,6 +1113,44 @@ err_ctl:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* cs_dsp_hibernate() - Disable or enable all controls for a DSP
|
||||
* @dsp: pointer to DSP structure
|
||||
* @hibernate: whether to set controls to cache only mode
|
||||
*
|
||||
* When @hibernate is true, the DSP is entering hibernation mode where the
|
||||
* regmap is inaccessible, and all controls become cache only.
|
||||
* When @hibernate is false, the DSP has exited hibernation mode. If the DSP
|
||||
* is running, all controls are re-synced to the DSP.
|
||||
*
|
||||
*/
|
||||
void cs_dsp_hibernate(struct cs_dsp *dsp, bool hibernate)
|
||||
{
|
||||
mutex_lock(&dsp->pwr_lock);
|
||||
|
||||
if (!dsp->running) {
|
||||
cs_dsp_dbg(dsp, "Cannot hibernate, DSP not running\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dsp->hibernating == hibernate)
|
||||
goto out;
|
||||
|
||||
cs_dsp_dbg(dsp, "Set hibernating to %d\n", hibernate);
|
||||
dsp->hibernating = hibernate;
|
||||
|
||||
if (!dsp->hibernating && dsp->running) {
|
||||
int ret = cs_dsp_coeff_sync_controls(dsp);
|
||||
|
||||
if (ret)
|
||||
cs_dsp_err(dsp, "Error syncing controls: %d\n", ret);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cs_dsp_hibernate, "FW_CS_DSP");
|
||||
|
||||
struct cs_dsp_coeff_parsed_alg {
|
||||
int id;
|
||||
const u8 *name;
|
||||
@@ -2510,6 +2553,7 @@ int cs_dsp_adsp1_power_up(struct cs_dsp *dsp,
|
||||
goto err_ena;
|
||||
|
||||
dsp->booted = true;
|
||||
dsp->hibernating = false;
|
||||
|
||||
/* Start the core running */
|
||||
regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
|
||||
@@ -2788,6 +2832,7 @@ int cs_dsp_power_up(struct cs_dsp *dsp,
|
||||
dsp->ops->disable_core(dsp);
|
||||
|
||||
dsp->booted = true;
|
||||
dsp->hibernating = false;
|
||||
|
||||
mutex_unlock(&dsp->pwr_lock);
|
||||
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
#define FW_CS_DSP_H
|
||||
|
||||
#if IS_ENABLED(CONFIG_KUNIT)
|
||||
extern bool cs_dsp_suppress_err_messages;
|
||||
extern bool cs_dsp_suppress_warn_messages;
|
||||
extern bool cs_dsp_suppress_info_messages;
|
||||
bool cs_dsp_can_emit_message(void);
|
||||
#endif
|
||||
|
||||
#endif /* ifndef FW_CS_DSP_H */
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <kunit/device.h>
|
||||
#include <kunit/resource.h>
|
||||
#include <kunit/static_stub.h>
|
||||
#include <kunit/test.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/firmware/cirrus/cs_dsp.h>
|
||||
@@ -2155,6 +2156,15 @@ static void bin_patch_name_and_info(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, reg_val, payload_data);
|
||||
}
|
||||
|
||||
static bool cs_dsp_bin_test_can_emit_message_hook(void)
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int cs_dsp_bin_test_common_init(struct kunit *test, struct cs_dsp *dsp,
|
||||
int wmdr_ver)
|
||||
{
|
||||
@@ -2239,16 +2249,12 @@ static int cs_dsp_bin_test_common_init(struct kunit *test, struct cs_dsp *dsp,
|
||||
* The large number of test cases will cause an unusually large amount
|
||||
* of dev_info() messages from cs_dsp, so suppress these.
|
||||
*/
|
||||
cs_dsp_suppress_info_messages = true;
|
||||
kunit_activate_static_stub(test, cs_dsp_can_emit_message,
|
||||
cs_dsp_bin_test_can_emit_message_hook);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cs_dsp_bin_test_exit(struct kunit *test)
|
||||
{
|
||||
cs_dsp_suppress_info_messages = false;
|
||||
}
|
||||
|
||||
static int cs_dsp_bin_test_halo_init_common(struct kunit *test, int wmdr_ver)
|
||||
{
|
||||
struct cs_dsp *dsp;
|
||||
@@ -2833,28 +2839,29 @@ static struct kunit_case cs_dsp_bin_test_cases_adsp2[] = {
|
||||
static struct kunit_suite cs_dsp_bin_test_halo = {
|
||||
.name = "cs_dsp_bin_halo",
|
||||
.init = cs_dsp_bin_test_halo_init,
|
||||
.exit = cs_dsp_bin_test_exit,
|
||||
.test_cases = cs_dsp_bin_test_cases_halo,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_bin_test_halo_wmdr3 = {
|
||||
.name = "cs_dsp_bin_halo_wmdr_v3",
|
||||
.init = cs_dsp_bin_test_halo_wmdr3_init,
|
||||
.test_cases = cs_dsp_bin_test_cases_halo_wmdr3,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_bin_test_adsp2_32bit = {
|
||||
.name = "cs_dsp_bin_adsp2_32bit",
|
||||
.init = cs_dsp_bin_test_adsp2_32bit_init,
|
||||
.exit = cs_dsp_bin_test_exit,
|
||||
.test_cases = cs_dsp_bin_test_cases_adsp2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_bin_test_adsp2_16bit = {
|
||||
.name = "cs_dsp_bin_adsp2_16bit",
|
||||
.init = cs_dsp_bin_test_adsp2_16bit_init,
|
||||
.exit = cs_dsp_bin_test_exit,
|
||||
.test_cases = cs_dsp_bin_test_cases_adsp2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
kunit_test_suites(&cs_dsp_bin_test_halo,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <kunit/device.h>
|
||||
#include <kunit/resource.h>
|
||||
#include <kunit/static_stub.h>
|
||||
#include <kunit/test.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/firmware/cirrus/cs_dsp.h>
|
||||
@@ -380,11 +381,13 @@ static void bin_block_payload_len_garbage(struct kunit *test)
|
||||
0);
|
||||
}
|
||||
|
||||
static void cs_dsp_bin_err_test_exit(struct kunit *test)
|
||||
static bool cs_dsp_bin_err_test_can_emit_message_hook(void)
|
||||
{
|
||||
cs_dsp_suppress_err_messages = false;
|
||||
cs_dsp_suppress_warn_messages = false;
|
||||
cs_dsp_suppress_info_messages = false;
|
||||
#if defined(DEBUG)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int cs_dsp_bin_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
|
||||
@@ -482,9 +485,8 @@ static int cs_dsp_bin_err_test_common_init(struct kunit *test, struct cs_dsp *ds
|
||||
* Testing error conditions can produce a lot of log output
|
||||
* from cs_dsp error messages, so suppress messages.
|
||||
*/
|
||||
cs_dsp_suppress_err_messages = true;
|
||||
cs_dsp_suppress_warn_messages = true;
|
||||
cs_dsp_suppress_info_messages = true;
|
||||
kunit_activate_static_stub(test, cs_dsp_can_emit_message,
|
||||
cs_dsp_bin_err_test_can_emit_message_hook);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -584,22 +586,22 @@ static struct kunit_case cs_dsp_bin_err_test_cases[] = {
|
||||
static struct kunit_suite cs_dsp_bin_err_test_halo = {
|
||||
.name = "cs_dsp_bin_err_halo",
|
||||
.init = cs_dsp_bin_err_test_halo_init,
|
||||
.exit = cs_dsp_bin_err_test_exit,
|
||||
.test_cases = cs_dsp_bin_err_test_cases,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_bin_err_test_adsp2_32bit = {
|
||||
.name = "cs_dsp_bin_err_adsp2_32bit",
|
||||
.init = cs_dsp_bin_err_test_adsp2_32bit_init,
|
||||
.exit = cs_dsp_bin_err_test_exit,
|
||||
.test_cases = cs_dsp_bin_err_test_cases,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_bin_err_test_adsp2_16bit = {
|
||||
.name = "cs_dsp_bin_err_adsp2_16bit",
|
||||
.init = cs_dsp_bin_err_test_adsp2_16bit_init,
|
||||
.exit = cs_dsp_bin_err_test_exit,
|
||||
.test_cases = cs_dsp_bin_err_test_cases,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
kunit_test_suites(&cs_dsp_bin_err_test_halo,
|
||||
|
||||
@@ -3248,30 +3248,35 @@ static struct kunit_suite cs_dsp_ctl_cache_test_halo = {
|
||||
.name = "cs_dsp_ctl_cache_wmfwV3_halo",
|
||||
.init = cs_dsp_ctl_cache_test_halo_init,
|
||||
.test_cases = cs_dsp_ctl_cache_test_cases_v3,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_cache_test_adsp2_32bit_wmfw1 = {
|
||||
.name = "cs_dsp_ctl_cache_wmfwV1_adsp2_32bit",
|
||||
.init = cs_dsp_ctl_cache_test_adsp2_32bit_wmfw1_init,
|
||||
.test_cases = cs_dsp_ctl_cache_test_cases_v1,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_cache_test_adsp2_32bit_wmfw2 = {
|
||||
.name = "cs_dsp_ctl_cache_wmfwV2_adsp2_32bit",
|
||||
.init = cs_dsp_ctl_cache_test_adsp2_32bit_wmfw2_init,
|
||||
.test_cases = cs_dsp_ctl_cache_test_cases_v2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_cache_test_adsp2_16bit_wmfw1 = {
|
||||
.name = "cs_dsp_ctl_cache_wmfwV1_adsp2_16bit",
|
||||
.init = cs_dsp_ctl_cache_test_adsp2_16bit_wmfw1_init,
|
||||
.test_cases = cs_dsp_ctl_cache_test_cases_v1,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_cache_test_adsp2_16bit_wmfw2 = {
|
||||
.name = "cs_dsp_ctl_cache_wmfwV2_adsp2_16bit",
|
||||
.init = cs_dsp_ctl_cache_test_adsp2_16bit_wmfw2_init,
|
||||
.test_cases = cs_dsp_ctl_cache_test_cases_v2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
kunit_test_suites(&cs_dsp_ctl_cache_test_halo,
|
||||
|
||||
@@ -1805,30 +1805,35 @@ static struct kunit_suite cs_dsp_ctl_parse_test_halo = {
|
||||
.name = "cs_dsp_ctl_parse_wmfwV3_halo",
|
||||
.init = cs_dsp_ctl_parse_test_halo_init,
|
||||
.test_cases = cs_dsp_ctl_parse_test_cases_v2_v3,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1 = {
|
||||
.name = "cs_dsp_ctl_parse_wmfwV1_adsp2_32bit",
|
||||
.init = cs_dsp_ctl_parse_test_adsp2_32bit_wmfw1_init,
|
||||
.test_cases = cs_dsp_ctl_parse_test_cases_v1,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2 = {
|
||||
.name = "cs_dsp_ctl_parse_wmfwV2_adsp2_32bit",
|
||||
.init = cs_dsp_ctl_parse_test_adsp2_32bit_wmfw2_init,
|
||||
.test_cases = cs_dsp_ctl_parse_test_cases_v2_v3,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1 = {
|
||||
.name = "cs_dsp_ctl_parse_wmfwV1_adsp2_16bit",
|
||||
.init = cs_dsp_ctl_parse_test_adsp2_16bit_wmfw1_init,
|
||||
.test_cases = cs_dsp_ctl_parse_test_cases_v1,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2 = {
|
||||
.name = "cs_dsp_ctl_parse_wmfwV2_adsp2_16bit",
|
||||
.init = cs_dsp_ctl_parse_test_adsp2_16bit_wmfw2_init,
|
||||
.test_cases = cs_dsp_ctl_parse_test_cases_v2_v3,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
kunit_test_suites(&cs_dsp_ctl_parse_test_halo,
|
||||
|
||||
@@ -2636,30 +2636,35 @@ static struct kunit_suite cs_dsp_ctl_rw_test_halo = {
|
||||
.name = "cs_dsp_ctl_rw_wmfwV3_halo",
|
||||
.init = cs_dsp_ctl_rw_test_halo_init,
|
||||
.test_cases = cs_dsp_ctl_rw_test_cases_halo,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_rw_test_adsp2_32bit_wmfw1 = {
|
||||
.name = "cs_dsp_ctl_rw_wmfwV1_adsp2_32bit",
|
||||
.init = cs_dsp_ctl_rw_test_adsp2_32bit_wmfw1_init,
|
||||
.test_cases = cs_dsp_ctl_rw_test_cases_adsp,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_rw_test_adsp2_32bit_wmfw2 = {
|
||||
.name = "cs_dsp_ctl_rw_wmfwV2_adsp2_32bit",
|
||||
.init = cs_dsp_ctl_rw_test_adsp2_32bit_wmfw2_init,
|
||||
.test_cases = cs_dsp_ctl_rw_test_cases_adsp,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_rw_test_adsp2_16bit_wmfw1 = {
|
||||
.name = "cs_dsp_ctl_rw_wmfwV1_adsp2_16bit",
|
||||
.init = cs_dsp_ctl_rw_test_adsp2_16bit_wmfw1_init,
|
||||
.test_cases = cs_dsp_ctl_rw_test_cases_adsp,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_ctl_rw_test_adsp2_16bit_wmfw2 = {
|
||||
.name = "cs_dsp_ctl_rw_wmfwV2_adsp2_16bit",
|
||||
.init = cs_dsp_ctl_rw_test_adsp2_16bit_wmfw2_init,
|
||||
.test_cases = cs_dsp_ctl_rw_test_cases_adsp,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
kunit_test_suites(&cs_dsp_ctl_rw_test_halo,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <kunit/device.h>
|
||||
#include <kunit/resource.h>
|
||||
#include <kunit/static_stub.h>
|
||||
#include <kunit/test.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/firmware/cirrus/cs_dsp.h>
|
||||
@@ -1775,6 +1776,15 @@ static void wmfw_load_with_info(struct kunit *test)
|
||||
KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes);
|
||||
}
|
||||
|
||||
static bool cs_dsp_wmfw_test_can_emit_message_hook(void)
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int cs_dsp_wmfw_test_common_init(struct kunit *test, struct cs_dsp *dsp,
|
||||
int wmfw_version)
|
||||
{
|
||||
@@ -1863,16 +1873,12 @@ static int cs_dsp_wmfw_test_common_init(struct kunit *test, struct cs_dsp *dsp,
|
||||
* The large number of test cases will cause an unusually large amount
|
||||
* of dev_info() messages from cs_dsp, so suppress these.
|
||||
*/
|
||||
cs_dsp_suppress_info_messages = true;
|
||||
kunit_activate_static_stub(test, cs_dsp_can_emit_message,
|
||||
cs_dsp_wmfw_test_can_emit_message_hook);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cs_dsp_wmfw_test_exit(struct kunit *test)
|
||||
{
|
||||
cs_dsp_suppress_info_messages = false;
|
||||
}
|
||||
|
||||
static int cs_dsp_wmfw_test_halo_init(struct kunit *test)
|
||||
{
|
||||
struct cs_dsp *dsp;
|
||||
@@ -2180,50 +2186,50 @@ static struct kunit_case cs_dsp_wmfw_test_cases_adsp2[] = {
|
||||
static struct kunit_suite cs_dsp_wmfw_test_halo = {
|
||||
.name = "cs_dsp_wmfwV3_halo",
|
||||
.init = cs_dsp_wmfw_test_halo_init,
|
||||
.exit = cs_dsp_wmfw_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_test_cases_halo,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw0 = {
|
||||
.name = "cs_dsp_wmfwV0_adsp2_32bit",
|
||||
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw0_init,
|
||||
.exit = cs_dsp_wmfw_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw1 = {
|
||||
.name = "cs_dsp_wmfwV1_adsp2_32bit",
|
||||
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw1_init,
|
||||
.exit = cs_dsp_wmfw_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_test_adsp2_32bit_wmfw2 = {
|
||||
.name = "cs_dsp_wmfwV2_adsp2_32bit",
|
||||
.init = cs_dsp_wmfw_test_adsp2_32bit_wmfw2_init,
|
||||
.exit = cs_dsp_wmfw_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw0 = {
|
||||
.name = "cs_dsp_wmfwV0_adsp2_16bit",
|
||||
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw0_init,
|
||||
.exit = cs_dsp_wmfw_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw1 = {
|
||||
.name = "cs_dsp_wmfwV1_adsp2_16bit",
|
||||
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw1_init,
|
||||
.exit = cs_dsp_wmfw_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_test_adsp2_16bit_wmfw2 = {
|
||||
.name = "cs_dsp_wmfwV2_adsp2_16bit",
|
||||
.init = cs_dsp_wmfw_test_adsp2_16bit_wmfw2_init,
|
||||
.exit = cs_dsp_wmfw_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_test_cases_adsp2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
kunit_test_suites(&cs_dsp_wmfw_test_halo,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <kunit/device.h>
|
||||
#include <kunit/resource.h>
|
||||
#include <kunit/static_stub.h>
|
||||
#include <kunit/test.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/firmware/cirrus/cs_dsp.h>
|
||||
@@ -989,11 +990,13 @@ static void wmfw_v2_coeff_description_exceeds_block(struct kunit *test)
|
||||
-EOVERFLOW);
|
||||
}
|
||||
|
||||
static void cs_dsp_wmfw_err_test_exit(struct kunit *test)
|
||||
static bool cs_dsp_wmfw_err_test_can_emit_message_hook(void)
|
||||
{
|
||||
cs_dsp_suppress_err_messages = false;
|
||||
cs_dsp_suppress_warn_messages = false;
|
||||
cs_dsp_suppress_info_messages = false;
|
||||
#if defined(DEBUG)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
|
||||
@@ -1080,9 +1083,8 @@ static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *d
|
||||
* Testing error conditions can produce a lot of log output
|
||||
* from cs_dsp error messages, so suppress messages.
|
||||
*/
|
||||
cs_dsp_suppress_err_messages = true;
|
||||
cs_dsp_suppress_warn_messages = true;
|
||||
cs_dsp_suppress_info_messages = true;
|
||||
kunit_activate_static_stub(test, cs_dsp_can_emit_message,
|
||||
cs_dsp_wmfw_err_test_can_emit_message_hook);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1304,50 +1306,50 @@ static struct kunit_case cs_dsp_wmfw_err_test_cases_v3[] = {
|
||||
static struct kunit_suite cs_dsp_wmfw_err_test_halo = {
|
||||
.name = "cs_dsp_wmfwV3_err_halo",
|
||||
.init = cs_dsp_wmfw_err_test_halo_init,
|
||||
.exit = cs_dsp_wmfw_err_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_err_test_cases_v3,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0 = {
|
||||
.name = "cs_dsp_wmfwV0_err_adsp2_32bit",
|
||||
.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0_init,
|
||||
.exit = cs_dsp_wmfw_err_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_err_test_cases_v0,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1 = {
|
||||
.name = "cs_dsp_wmfwV1_err_adsp2_32bit",
|
||||
.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1_init,
|
||||
.exit = cs_dsp_wmfw_err_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_err_test_cases_v1,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2 = {
|
||||
.name = "cs_dsp_wmfwV2_err_adsp2_32bit",
|
||||
.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2_init,
|
||||
.exit = cs_dsp_wmfw_err_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_err_test_cases_v2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0 = {
|
||||
.name = "cs_dsp_wmfwV0_err_adsp2_16bit",
|
||||
.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0_init,
|
||||
.exit = cs_dsp_wmfw_err_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_err_test_cases_v0,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1 = {
|
||||
.name = "cs_dsp_wmfwV1_err_adsp2_16bit",
|
||||
.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1_init,
|
||||
.exit = cs_dsp_wmfw_err_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_err_test_cases_v1,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2 = {
|
||||
.name = "cs_dsp_wmfwV2_err_adsp2_16bit",
|
||||
.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2_init,
|
||||
.exit = cs_dsp_wmfw_err_test_exit,
|
||||
.test_cases = cs_dsp_wmfw_err_test_cases_v2,
|
||||
.attr.speed = KUNIT_SPEED_SLOW,
|
||||
};
|
||||
|
||||
kunit_test_suites(&cs_dsp_wmfw_err_test_halo,
|
||||
|
||||
@@ -47,6 +47,7 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c)
|
||||
cs42l43->irq = i2c->irq;
|
||||
/* A device on an I2C is always attached by definition. */
|
||||
cs42l43->attached = true;
|
||||
cs42l43->variant_id = (long)device_get_match_data(cs42l43->dev);
|
||||
|
||||
cs42l43->regmap = devm_regmap_init_i2c(i2c, &cs42l43_i2c_regmap);
|
||||
if (IS_ERR(cs42l43->regmap))
|
||||
@@ -58,7 +59,8 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c)
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id cs42l43_of_match[] = {
|
||||
{ .compatible = "cirrus,cs42l43", },
|
||||
{ .compatible = "cirrus,cs42l43", .data = (void *)CS42L43_DEVID_VAL },
|
||||
{ .compatible = "cirrus,cs42l43b", .data = (void *)CS42L43B_DEVID_VAL },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs42l43_of_match);
|
||||
@@ -66,7 +68,8 @@ MODULE_DEVICE_TABLE(of, cs42l43_of_match);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
static const struct acpi_device_id cs42l43_acpi_match[] = {
|
||||
{ "CSC4243", 0 },
|
||||
{ "CSC4243", CS42L43_DEVID_VAL },
|
||||
{ "CSC2A3B", CS42L43B_DEVID_VAL },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cs42l43_acpi_match);
|
||||
|
||||
@@ -178,6 +178,7 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *
|
||||
|
||||
cs42l43->dev = dev;
|
||||
cs42l43->sdw = sdw;
|
||||
cs42l43->variant_id = (long)id->driver_data;
|
||||
|
||||
cs42l43->regmap = devm_regmap_init_sdw(sdw, &cs42l43_sdw_regmap);
|
||||
if (IS_ERR(cs42l43->regmap))
|
||||
@@ -188,7 +189,8 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *
|
||||
}
|
||||
|
||||
static const struct sdw_device_id cs42l43_sdw_id[] = {
|
||||
SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0),
|
||||
SDW_SLAVE_ENTRY(0x01FA, 0x4243, (void *) CS42L43_DEVID_VAL),
|
||||
SDW_SLAVE_ENTRY(0x01FA, 0x2A3B, (void *) CS42L43B_DEVID_VAL),
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(sdw, cs42l43_sdw_id);
|
||||
|
||||
@@ -115,9 +115,14 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
|
||||
{ CS42L43_DECIM_HPF_WNF_CTRL2, 0x00000001 },
|
||||
{ CS42L43_DECIM_HPF_WNF_CTRL3, 0x00000001 },
|
||||
{ CS42L43_DECIM_HPF_WNF_CTRL4, 0x00000001 },
|
||||
{ CS42L43B_DECIM_HPF_WNF_CTRL5, 0x00000001 },
|
||||
{ CS42L43B_DECIM_HPF_WNF_CTRL6, 0x00000001 },
|
||||
{ CS42L43_DMIC_PDM_CTRL, 0x00000000 },
|
||||
{ CS42L43_DECIM_VOL_CTRL_CH1_CH2, 0x20122012 },
|
||||
{ CS42L43_DECIM_VOL_CTRL_CH3_CH4, 0x20122012 },
|
||||
{ CS42L43B_DECIM_VOL_CTRL_CH1_CH2, 0x20122012 },
|
||||
{ CS42L43B_DECIM_VOL_CTRL_CH3_CH4, 0x20122012 },
|
||||
{ CS42L43B_DECIM_VOL_CTRL_CH5_CH6, 0x20122012 },
|
||||
{ CS42L43_INTP_VOLUME_CTRL1, 0x00000180 },
|
||||
{ CS42L43_INTP_VOLUME_CTRL2, 0x00000180 },
|
||||
{ CS42L43_AMP1_2_VOL_RAMP, 0x00000022 },
|
||||
@@ -155,8 +160,12 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
|
||||
{ CS42L43_SWIRE_DP2_CH2_INPUT, 0x00000000 },
|
||||
{ CS42L43_SWIRE_DP3_CH1_INPUT, 0x00000000 },
|
||||
{ CS42L43_SWIRE_DP3_CH2_INPUT, 0x00000000 },
|
||||
{ CS42L43B_SWIRE_DP3_CH3_INPUT, 0x00000000 },
|
||||
{ CS42L43B_SWIRE_DP3_CH4_INPUT, 0x00000000 },
|
||||
{ CS42L43_SWIRE_DP4_CH1_INPUT, 0x00000000 },
|
||||
{ CS42L43_SWIRE_DP4_CH2_INPUT, 0x00000000 },
|
||||
{ CS42L43B_SWIRE_DP4_CH3_INPUT, 0x00000000 },
|
||||
{ CS42L43B_SWIRE_DP4_CH4_INPUT, 0x00000000 },
|
||||
{ CS42L43_ASRC_INT1_INPUT1, 0x00000000 },
|
||||
{ CS42L43_ASRC_INT2_INPUT1, 0x00000000 },
|
||||
{ CS42L43_ASRC_INT3_INPUT1, 0x00000000 },
|
||||
@@ -169,10 +178,14 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
|
||||
{ CS42L43_ISRC1INT2_INPUT1, 0x00000000 },
|
||||
{ CS42L43_ISRC1DEC1_INPUT1, 0x00000000 },
|
||||
{ CS42L43_ISRC1DEC2_INPUT1, 0x00000000 },
|
||||
{ CS42L43B_ISRC1DEC3_INPUT1, 0x00000000 },
|
||||
{ CS42L43B_ISRC1DEC4_INPUT1, 0x00000000 },
|
||||
{ CS42L43_ISRC2INT1_INPUT1, 0x00000000 },
|
||||
{ CS42L43_ISRC2INT2_INPUT1, 0x00000000 },
|
||||
{ CS42L43_ISRC2DEC1_INPUT1, 0x00000000 },
|
||||
{ CS42L43_ISRC2DEC2_INPUT1, 0x00000000 },
|
||||
{ CS42L43B_ISRC2DEC3_INPUT1, 0x00000000 },
|
||||
{ CS42L43B_ISRC2DEC4_INPUT1, 0x00000000 },
|
||||
{ CS42L43_EQ1MIX_INPUT1, 0x00800000 },
|
||||
{ CS42L43_EQ1MIX_INPUT2, 0x00800000 },
|
||||
{ CS42L43_EQ1MIX_INPUT3, 0x00800000 },
|
||||
@@ -269,6 +282,8 @@ EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, "MFD_CS42L43");
|
||||
|
||||
bool cs42l43_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
|
||||
|
||||
switch (reg) {
|
||||
case CS42L43_DEVID:
|
||||
case CS42L43_REVID:
|
||||
@@ -292,7 +307,6 @@ bool cs42l43_readable_register(struct device *dev, unsigned int reg)
|
||||
case CS42L43_ADC_B_CTRL1 ... CS42L43_ADC_B_CTRL2:
|
||||
case CS42L43_DECIM_HPF_WNF_CTRL1 ... CS42L43_DECIM_HPF_WNF_CTRL4:
|
||||
case CS42L43_DMIC_PDM_CTRL:
|
||||
case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4:
|
||||
case CS42L43_INTP_VOLUME_CTRL1 ... CS42L43_INTP_VOLUME_CTRL2:
|
||||
case CS42L43_AMP1_2_VOL_RAMP:
|
||||
case CS42L43_ASP_CTRL:
|
||||
@@ -387,8 +401,16 @@ bool cs42l43_readable_register(struct device *dev, unsigned int reg)
|
||||
case CS42L43_BOOT_CONTROL:
|
||||
case CS42L43_BLOCK_EN:
|
||||
case CS42L43_SHUTTER_CONTROL:
|
||||
case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX:
|
||||
return true;
|
||||
case CS42L43B_MCU_SW_REV ... CS42L43B_MCU_RAM_MAX:
|
||||
return true; // registers present on all variants
|
||||
case CS42L43_MCU_SW_REV ... CS42L43B_MCU_SW_REV - 1:
|
||||
case CS42L43B_MCU_RAM_MAX + 1 ... CS42L43_MCU_RAM_MAX:
|
||||
case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4:
|
||||
return cs42l43->variant_id == CS42L43_DEVID_VAL; // regs only in CS42L43 variant
|
||||
case CS42L43B_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43B_DECIM_HPF_WNF_CTRL6:
|
||||
case CS42L43B_SWIRE_DP3_CH3_INPUT ... CS42L43B_SWIRE_DP4_CH4_INPUT:
|
||||
case CS42L43B_ISRC1DEC3_INPUT1 ... CS42L43B_ISRC2DEC4_INPUT1:
|
||||
return cs42l43->variant_id == CS42L43B_DEVID_VAL; // regs only in CS42L43B variant
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -597,15 +619,27 @@ static int cs42l43_wait_for_attach(struct cs42l43 *cs42l43)
|
||||
static int cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow)
|
||||
{
|
||||
unsigned int need_reg = CS42L43_NEED_CONFIGS;
|
||||
unsigned int boot_reg;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
if (shadow)
|
||||
need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS;
|
||||
switch (cs42l43->variant_id) {
|
||||
case CS42L43_DEVID_VAL:
|
||||
if (shadow)
|
||||
need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS;
|
||||
boot_reg = CS42L43_BOOT_STATUS;
|
||||
break;
|
||||
case CS42L43B_DEVID_VAL:
|
||||
need_reg = CS42L43B_NEED_CONFIGS;
|
||||
boot_reg = CS42L43B_BOOT_STATUS;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_write(cs42l43->regmap, need_reg, 0);
|
||||
|
||||
ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS,
|
||||
ret = regmap_read_poll_timeout(cs42l43->regmap, boot_reg,
|
||||
val, (val == CS42L43_MCU_BOOT_STAGE3),
|
||||
CS42L43_MCU_POLL_US, CS42L43_MCU_CMD_TIMEOUT_US);
|
||||
if (ret) {
|
||||
@@ -644,13 +678,25 @@ static int cs42l43_mcu_stage_3_2(struct cs42l43 *cs42l43)
|
||||
*/
|
||||
static int cs42l43_mcu_disable(struct cs42l43 *cs42l43)
|
||||
{
|
||||
unsigned int val;
|
||||
unsigned int val, cfg_reg, ctrl_reg;
|
||||
int ret;
|
||||
|
||||
regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG,
|
||||
CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL);
|
||||
regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION,
|
||||
CS42L43_FW_MM_CTRL_MCU_SEL_MASK);
|
||||
switch (cs42l43->variant_id) {
|
||||
case CS42L43_DEVID_VAL:
|
||||
cfg_reg = CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG;
|
||||
ctrl_reg = CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION;
|
||||
break;
|
||||
case CS42L43B_DEVID_VAL:
|
||||
cfg_reg = CS42L43B_FW_MISSION_CTRL_MM_MCU_CFG_REG;
|
||||
ctrl_reg = CS42L43B_FW_MISSION_CTRL_MM_CTRL_SELECTION;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_write(cs42l43->regmap, cfg_reg, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL);
|
||||
regmap_write(cs42l43->regmap, ctrl_reg, CS42L43_FW_MM_CTRL_MCU_SEL_MASK);
|
||||
|
||||
regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_CONTROL_IND_MASK);
|
||||
regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0);
|
||||
|
||||
@@ -740,18 +786,32 @@ static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43)
|
||||
{
|
||||
unsigned int mcu_rev, bios_rev, boot_status, secure_cfg;
|
||||
bool patched, shadow;
|
||||
int boot_status_reg, mcu_sw_rev_reg;
|
||||
int ret;
|
||||
|
||||
switch (cs42l43->variant_id) {
|
||||
case CS42L43_DEVID_VAL:
|
||||
boot_status_reg = CS42L43_BOOT_STATUS;
|
||||
mcu_sw_rev_reg = CS42L43_MCU_SW_REV;
|
||||
break;
|
||||
case CS42L43B_DEVID_VAL:
|
||||
boot_status_reg = CS42L43B_BOOT_STATUS;
|
||||
mcu_sw_rev_reg = CS42L43B_MCU_SW_REV;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clear any stale software interrupt bits. */
|
||||
regmap_read(cs42l43->regmap, CS42L43_SOFT_INT, &mcu_rev);
|
||||
|
||||
ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_STATUS, &boot_status);
|
||||
ret = regmap_read(cs42l43->regmap, boot_status_reg, &boot_status);
|
||||
if (ret) {
|
||||
dev_err(cs42l43->dev, "Failed to read boot status: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(cs42l43->regmap, CS42L43_MCU_SW_REV, &mcu_rev);
|
||||
ret = regmap_read(cs42l43->regmap, mcu_sw_rev_reg, &mcu_rev);
|
||||
if (ret) {
|
||||
dev_err(cs42l43->dev, "Failed to read firmware revision: %d\n", ret);
|
||||
return ret;
|
||||
@@ -918,6 +978,13 @@ static void cs42l43_boot_work(struct work_struct *work)
|
||||
|
||||
switch (devid) {
|
||||
case CS42L43_DEVID_VAL:
|
||||
case CS42L43B_DEVID_VAL:
|
||||
if (devid != cs42l43->variant_id) {
|
||||
dev_err(cs42l43->dev,
|
||||
"Device ID (0x%06x) does not match variant ID (0x%06lx)\n",
|
||||
devid, cs42l43->variant_id);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(cs42l43->dev, "Unrecognised devid: 0x%06x\n", devid);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#ifndef CS42L43_CORE_INT_H
|
||||
#define CS42L43_CORE_INT_H
|
||||
|
||||
#define CS42L43_N_DEFAULTS 176
|
||||
#define CS42L43_N_DEFAULTS 189
|
||||
|
||||
struct dev_pm_ops;
|
||||
struct device;
|
||||
|
||||
@@ -140,6 +140,18 @@
|
||||
#define DISPLAY_PORT_RX_6 134
|
||||
#define DISPLAY_PORT_RX_7 135
|
||||
#define USB_RX 136
|
||||
#define LPI_MI2S_RX_0 137
|
||||
#define LPI_MI2S_TX_0 138
|
||||
#define LPI_MI2S_RX_1 139
|
||||
#define LPI_MI2S_TX_1 140
|
||||
#define LPI_MI2S_RX_2 141
|
||||
#define LPI_MI2S_TX_2 142
|
||||
#define LPI_MI2S_RX_3 143
|
||||
#define LPI_MI2S_TX_3 144
|
||||
#define LPI_MI2S_RX_4 145
|
||||
#define LPI_MI2S_TX_4 146
|
||||
#define SENARY_MI2S_RX 147
|
||||
#define SENARY_MI2S_TX 148
|
||||
|
||||
#define LPASS_CLK_ID_PRI_MI2S_IBIT 1
|
||||
#define LPASS_CLK_ID_PRI_MI2S_EBIT 2
|
||||
|
||||
@@ -179,6 +179,7 @@ struct cs_dsp {
|
||||
|
||||
bool booted;
|
||||
bool running;
|
||||
bool hibernating;
|
||||
|
||||
struct list_head ctl_list;
|
||||
|
||||
@@ -354,4 +355,6 @@ int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val);
|
||||
int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch);
|
||||
int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits);
|
||||
|
||||
void cs_dsp_hibernate(struct cs_dsp *dsp, bool hibernating);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -117,11 +117,6 @@ struct arizona_pdata {
|
||||
/** Check for line output with HPDET method */
|
||||
bool hpdet_acc_id_line;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_LEGACY
|
||||
/** GPIO used for mic isolation with HPDET */
|
||||
int hpdet_id_gpio;
|
||||
#endif
|
||||
|
||||
/** Channel to use for headphone detection */
|
||||
unsigned int hpdet_channel;
|
||||
|
||||
@@ -131,11 +126,6 @@ struct arizona_pdata {
|
||||
/** Extra debounce timeout used during initial mic detection (ms) */
|
||||
unsigned int micd_detect_debounce;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_LEGACY
|
||||
/** GPIO for mic detection polarity */
|
||||
int micd_pol_gpio;
|
||||
#endif
|
||||
|
||||
/** Mic detect ramp rate */
|
||||
unsigned int micd_bias_start_time;
|
||||
|
||||
|
||||
@@ -1181,4 +1181,80 @@
|
||||
/* CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG */
|
||||
#define CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL 0xF05AA50F
|
||||
|
||||
/* CS42L43B VARIANT REGISTERS */
|
||||
#define CS42L43B_DEVID_VAL 0x0042A43B
|
||||
|
||||
#define CS42L43B_DECIM_VOL_CTRL_CH1_CH2 0x00008280
|
||||
#define CS42L43B_DECIM_VOL_CTRL_CH3_CH4 0x00008284
|
||||
|
||||
#define CS42L43B_DECIM_VOL_CTRL_CH5_CH6 0x00008290
|
||||
#define CS42L43B_DECIM_VOL_CTRL_UPDATE 0x0000829C
|
||||
|
||||
#define CS42L43B_DECIM_HPF_WNF_CTRL5 0x000082A0
|
||||
#define CS42L43B_DECIM_HPF_WNF_CTRL6 0x000082A4
|
||||
|
||||
#define CS42L43B_SWIRE_DP3_CH3_INPUT 0x0000C320
|
||||
#define CS42L43B_SWIRE_DP3_CH4_INPUT 0x0000C330
|
||||
#define CS42L43B_SWIRE_DP4_CH3_INPUT 0x0000C340
|
||||
#define CS42L43B_SWIRE_DP4_CH4_INPUT 0x0000C350
|
||||
|
||||
#define CS42L43B_ISRC1DEC3_INPUT1 0x0000C780
|
||||
#define CS42L43B_ISRC1DEC4_INPUT1 0x0000C790
|
||||
#define CS42L43B_ISRC2DEC3_INPUT1 0x0000C7A0
|
||||
#define CS42L43B_ISRC2DEC4_INPUT1 0x0000C7B0
|
||||
|
||||
#define CS42L43B_FW_MISSION_CTRL_NEED_CONFIGS 0x00117E00
|
||||
#define CS42L43B_FW_MISSION_CTRL_HAVE_CONFIGS 0x00117E04
|
||||
#define CS42L43B_FW_MISSION_CTRL_PATCH_START_ADDR_REG 0x00117E08
|
||||
#define CS42L43B_FW_MISSION_CTRL_MM_CTRL_SELECTION 0x00117E0C
|
||||
#define CS42L43B_FW_MISSION_CTRL_MM_MCU_CFG_REG 0x00117E10
|
||||
|
||||
#define CS42L43B_MCU_SW_REV 0x00117314
|
||||
#define CS42L43B_PATCH_START_ADDR 0x00117318
|
||||
#define CS42L43B_CONFIG_SELECTION 0x0011731C
|
||||
#define CS42L43B_NEED_CONFIGS 0x00117320
|
||||
#define CS42L43B_BOOT_STATUS 0x00117330
|
||||
|
||||
#define CS42L43B_FW_MISSION_CTRL_NEED_CONFIGS 0x00117E00
|
||||
#define CS42L43B_FW_MISSION_CTRL_HAVE_CONFIGS 0x00117E04
|
||||
#define CS42L43B_FW_MISSION_CTRL_PATCH_START_ADDR_REG 0x00117E08
|
||||
#define CS42L43B_FW_MISSION_CTRL_MM_CTRL_SELECTION 0x00117E0C
|
||||
#define CS42L43B_FW_MISSION_CTRL_MM_MCU_CFG_REG 0x00117E10
|
||||
|
||||
#define CS42L43B_MCU_RAM_MAX 0x00117FFF
|
||||
|
||||
/* CS42L43B_DECIM_DECIM_VOL_CTRL_CH5_CH6 */
|
||||
#define CS42L43B_DECIM6_MUTE_MASK 0x80000000
|
||||
#define CS42L43B_DECIM6_MUTE_SHIFT 31
|
||||
#define CS42L43B_DECIM6_VOL_MASK 0x3FC00000
|
||||
#define CS42L43B_DECIM6_VOL_SHIFT 22
|
||||
#define CS42L43B_DECIM6_PATH1_VOL_FALL_RATE_MASK 0x00380000
|
||||
#define CS42L43B_DECIM6_PATH1_VOL_FALL_RATE_SHIFT 19
|
||||
#define CS42L43B_DECIM6_PATH1_VOL_RISE_RATE_MASK 0x00070000
|
||||
#define CS42L43B_DECIM6_PATH1_VOL_RISE_RATE_SHIFT 16
|
||||
#define CS42L43B_DECIM5_MUTE_MASK 0x00008000
|
||||
#define CS42L43B_DECIM5_MUTE_SHIFT 15
|
||||
#define CS42L43B_DECIM5_VOL_MASK 0x00003FC0
|
||||
#define CS42L43B_DECIM5_VOL_SHIFT 6
|
||||
#define CS42L43B_DECIM5_PATH1_VOL_FALL_RATE_MASK 0x00000038
|
||||
#define CS42L43B_DECIM5_PATH1_VOL_FALL_RATE_SHIFT 3
|
||||
#define CS42L43B_DECIM5_PATH1_VOL_RISE_RATE_MASK 0x00000007
|
||||
#define CS42L43B_DECIM5_PATH1_VOL_RISE_RATE_SHIFT 0
|
||||
|
||||
/* CS42L43B_DECIM_VOL_CTRL_UPDATE */
|
||||
#define CS42L43B_DECIM6_PATH1_VOL_TRIG_MASK 0x00000800
|
||||
#define CS42L43B_DECIM6_PATH1_VOL_TRIG_SHIFT 11
|
||||
#define CS42L43B_DECIM5_PATH1_VOL_TRIG_MASK 0x00000100
|
||||
#define CS42L43B_DECIM5_PATH1_VOL_TRIG_SHIFT 8
|
||||
#define CS42L43B_DECIM4_VOL_UPDATE_MASK 0x00000020
|
||||
#define CS42L43B_DECIM4_VOL_UPDATE_SHIFT 5
|
||||
|
||||
/* CS42L43_ISRC1_CTRL..CS42L43_ISRC2_CTRL */
|
||||
#define CS42L43B_ISRC_DEC4_EN_MASK 0x00000008
|
||||
#define CS42L43B_ISRC_DEC4_EN_SHIFT 3
|
||||
#define CS42L43B_ISRC_DEC4_EN_WIDTH 1
|
||||
#define CS42L43B_ISRC_DEC3_EN_MASK 0x00000004
|
||||
#define CS42L43B_ISRC_DEC3_EN_SHIFT 2
|
||||
#define CS42L43B_ISRC_DEC3_EN_WIDTH 1
|
||||
|
||||
#endif /* CS42L43_CORE_REGS_H */
|
||||
|
||||
@@ -98,6 +98,7 @@ struct cs42l43 {
|
||||
bool sdw_pll_active;
|
||||
bool attached;
|
||||
bool hw_lock;
|
||||
long variant_id;
|
||||
};
|
||||
|
||||
#endif /* CS42L43_CORE_EXT_H */
|
||||
|
||||
@@ -133,6 +133,9 @@ struct snd_card {
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
struct dentry *debugfs_root; /* debugfs root for card */
|
||||
#endif
|
||||
#ifdef CONFIG_SND_CTL_DEBUG
|
||||
struct snd_ctl_elem_value *value_buf; /* buffer for kctl->put() verification */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
unsigned int power_state; /* power state */
|
||||
|
||||
@@ -32,9 +32,6 @@ struct snd_ctl_elem_value;
|
||||
#define CS35L56_UPDATE_REGS 0x0002A0C
|
||||
#define CS35L56_REFCLK_INPUT 0x0002C04
|
||||
#define CS35L56_GLOBAL_SAMPLE_RATE 0x0002C0C
|
||||
#define CS35L56_OTP_MEM_53 0x00300D4
|
||||
#define CS35L56_OTP_MEM_54 0x00300D8
|
||||
#define CS35L56_OTP_MEM_55 0x00300DC
|
||||
#define CS35L56_ASP1_ENABLES1 0x0004800
|
||||
#define CS35L56_ASP1_CONTROL1 0x0004804
|
||||
#define CS35L56_ASP1_CONTROL2 0x0004808
|
||||
@@ -86,6 +83,9 @@ struct snd_ctl_elem_value;
|
||||
#define CS35L56_DIE_STS1 0x0017040
|
||||
#define CS35L56_DIE_STS2 0x0017044
|
||||
#define CS35L56_DSP_RESTRICT_STS1 0x00190F0
|
||||
#define CS35L56_OTP_MEM_53 0x00300D4
|
||||
#define CS35L56_OTP_MEM_54 0x00300D8
|
||||
#define CS35L56_OTP_MEM_55 0x00300DC
|
||||
#define CS35L56_DSP1_XMEM_PACKED_0 0x2000000
|
||||
#define CS35L56_DSP1_XMEM_PACKED_6143 0x2005FFC
|
||||
#define CS35L56_DSP1_XMEM_UNPACKED32_0 0x2400000
|
||||
@@ -435,6 +435,7 @@ ssize_t cs35l56_cal_data_debugfs_read(struct cs35l56_base *cs35l56_base,
|
||||
ssize_t cs35l56_cal_data_debugfs_write(struct cs35l56_base *cs35l56_base,
|
||||
const char __user *from, size_t count,
|
||||
loff_t *ppos);
|
||||
int cs35l56_factory_calibrate(struct cs35l56_base *cs35l56_base);
|
||||
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);
|
||||
|
||||
@@ -536,6 +536,7 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus,
|
||||
struct snd_gf1_dma_block * block,
|
||||
int atomic,
|
||||
int synth);
|
||||
void snd_gf1_dma_suspend(struct snd_gus_card *gus);
|
||||
|
||||
/* gus_volume.c */
|
||||
|
||||
@@ -552,6 +553,8 @@ struct snd_gus_voice *snd_gf1_alloc_voice(struct snd_gus_card * gus, int type, i
|
||||
void snd_gf1_free_voice(struct snd_gus_card * gus, struct snd_gus_voice *voice);
|
||||
int snd_gf1_start(struct snd_gus_card * gus);
|
||||
int snd_gf1_stop(struct snd_gus_card * gus);
|
||||
int snd_gf1_suspend(struct snd_gus_card *gus);
|
||||
int snd_gf1_resume(struct snd_gus_card *gus);
|
||||
|
||||
/* gus_mixer.c */
|
||||
|
||||
@@ -572,6 +575,8 @@ int snd_gus_create(struct snd_card *card,
|
||||
int effect,
|
||||
struct snd_gus_card ** rgus);
|
||||
int snd_gus_initialize(struct snd_gus_card * gus);
|
||||
int snd_gus_suspend(struct snd_gus_card *gus);
|
||||
int snd_gus_resume(struct snd_gus_card *gus);
|
||||
|
||||
/* gus_irq.c */
|
||||
|
||||
@@ -583,6 +588,8 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus);
|
||||
/* gus_uart.c */
|
||||
|
||||
int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device);
|
||||
void snd_gf1_uart_suspend(struct snd_gus_card *gus);
|
||||
void snd_gf1_uart_resume(struct snd_gus_card *gus);
|
||||
|
||||
/* gus_dram.c */
|
||||
int snd_gus_dram_write(struct snd_gus_card *gus, char __user *ptr,
|
||||
@@ -593,5 +600,6 @@ int snd_gus_dram_read(struct snd_gus_card *gus, char __user *ptr,
|
||||
/* gus_timer.c */
|
||||
void snd_gf1_timers_init(struct snd_gus_card *gus);
|
||||
void snd_gf1_timers_done(struct snd_gus_card *gus);
|
||||
void snd_gf1_timers_resume(struct snd_gus_card *gus);
|
||||
|
||||
#endif /* __SOUND_GUS_H */
|
||||
|
||||
@@ -336,6 +336,17 @@ snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
|
||||
return snd_hdac_codec_write(&codec->core, nid, flags, verb, parm);
|
||||
}
|
||||
|
||||
/* sync after write */
|
||||
static inline int
|
||||
snd_hda_codec_write_sync(struct hda_codec *codec, hda_nid_t nid, int flags,
|
||||
unsigned int verb, unsigned int parm)
|
||||
{
|
||||
/* use snd_hda_codec_read() for writing;
|
||||
* the returned value is usually discarded
|
||||
*/
|
||||
return snd_hdac_codec_read(&codec->core, nid, flags, verb, parm);
|
||||
}
|
||||
|
||||
#define snd_hda_param_read(codec, nid, param) \
|
||||
snd_hdac_read_parm(&(codec)->core, nid, param)
|
||||
#define snd_hda_get_sub_nodes(codec, nid, start_nid) \
|
||||
@@ -470,6 +481,10 @@ void snd_hda_unlock_devices(struct hda_bus *bus);
|
||||
void snd_hda_bus_reset(struct hda_bus *bus);
|
||||
void snd_hda_bus_reset_codecs(struct hda_bus *bus);
|
||||
|
||||
void snd_hda_codec_set_gpio(struct hda_codec *codec, unsigned int mask,
|
||||
unsigned int dir, unsigned int data,
|
||||
unsigned int delay);
|
||||
|
||||
int snd_hda_codec_set_name(struct hda_codec *codec, const char *name);
|
||||
|
||||
/*
|
||||
|
||||
@@ -56,7 +56,12 @@ enum {
|
||||
#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d
|
||||
#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */
|
||||
#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f
|
||||
/* f10-f1a: GPIO */
|
||||
/* f10-f1a: GPI/GPO/GPIO */
|
||||
#define AC_VERB_GET_GPI_DATA 0x0f10
|
||||
#define AC_VERB_GET_GPI_WAKE_MASK 0x0f11
|
||||
#define AC_VERB_GET_GPI_UNSOLICITED_RSP_MASK 0x0f12
|
||||
#define AC_VERB_GET_GPI_STICKY_MASK 0x0f13
|
||||
#define AC_VERB_GET_GPO_DATA 0x0f14
|
||||
#define AC_VERB_GET_GPIO_DATA 0x0f15
|
||||
#define AC_VERB_GET_GPIO_MASK 0x0f16
|
||||
#define AC_VERB_GET_GPIO_DIRECTION 0x0f17
|
||||
@@ -99,6 +104,11 @@ enum {
|
||||
#define AC_VERB_SET_DIGI_CONVERT_2 0x70e
|
||||
#define AC_VERB_SET_DIGI_CONVERT_3 0x73e
|
||||
#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f
|
||||
#define AC_VERB_SET_GPI_DATA 0x710
|
||||
#define AC_VERB_SET_GPI_WAKE_MASK 0x711
|
||||
#define AC_VERB_SET_SPI_UNSOLICITED_RSP_MASK 0x712
|
||||
#define AC_VERB_SET_GPI_STICKY_MASK 0x713
|
||||
#define AC_VERB_SET_GPO_DATA 0x714
|
||||
#define AC_VERB_SET_GPIO_DATA 0x715
|
||||
#define AC_VERB_SET_GPIO_MASK 0x716
|
||||
#define AC_VERB_SET_GPIO_DIRECTION 0x717
|
||||
|
||||
@@ -729,6 +729,10 @@ static inline void __snd_pcm_set_state(struct snd_pcm_runtime *runtime,
|
||||
runtime->status->state = state; /* copy for mmap */
|
||||
}
|
||||
|
||||
void snd_pcm_set_state(struct snd_pcm_substream *substream,
|
||||
snd_pcm_state_t state);
|
||||
snd_pcm_state_t snd_pcm_get_state(struct snd_pcm_substream *substream);
|
||||
|
||||
/**
|
||||
* bytes_to_samples - Unit conversion of the size from bytes to samples
|
||||
* @runtime: PCM runtime instance
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
struct device;
|
||||
struct regmap;
|
||||
struct sdca_function_data;
|
||||
struct snd_ctl_elem_value;
|
||||
struct snd_kcontrol;
|
||||
struct snd_kcontrol_new;
|
||||
struct snd_pcm_hw_params;
|
||||
struct snd_pcm_substream;
|
||||
@@ -23,6 +25,42 @@ struct snd_soc_dai_ops;
|
||||
struct snd_soc_dapm_route;
|
||||
struct snd_soc_dapm_widget;
|
||||
|
||||
/* convenient macro to handle the mono volume in 7.8 fixed format representation */
|
||||
#define SDCA_SINGLE_Q78_TLV(xname, xreg, xmin, xmax, xstep, tlv_array) \
|
||||
{ \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||
.name = (xname), \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE, \
|
||||
.tlv.p = (tlv_array), \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = sdca_asoc_q78_get_volsw, \
|
||||
.put = sdca_asoc_q78_put_volsw, \
|
||||
.private_value = (unsigned long)&(struct soc_mixer_control) { \
|
||||
.reg = (xreg), .rreg = (xreg), \
|
||||
.min = (xmin), .max = (xmax), \
|
||||
.shift = (xstep), .rshift = (xstep), \
|
||||
.sign_bit = 15 \
|
||||
} \
|
||||
}
|
||||
|
||||
/* convenient macro for stereo volume in 7.8 fixed format with separate registers for L/R */
|
||||
#define SDCA_DOUBLE_Q78_TLV(xname, xreg_l, xreg_r, xmin, xmax, xstep, tlv_array) \
|
||||
{ \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||
.name = (xname), \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE, \
|
||||
.tlv.p = (tlv_array), \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = sdca_asoc_q78_get_volsw, \
|
||||
.put = sdca_asoc_q78_put_volsw, \
|
||||
.private_value = (unsigned long)&(struct soc_mixer_control) { \
|
||||
.reg = (xreg_l), .rreg = (xreg_r), \
|
||||
.min = (xmin), .max = (xmax), \
|
||||
.shift = (xstep), .rshift = (xstep), \
|
||||
.sign_bit = 15 \
|
||||
} \
|
||||
}
|
||||
|
||||
int sdca_asoc_count_component(struct device *dev, struct sdca_function_data *function,
|
||||
int *num_widgets, int *num_routes, int *num_controls,
|
||||
int *num_dais);
|
||||
@@ -57,5 +95,8 @@ int sdca_asoc_hw_params(struct device *dev, struct regmap *regmap,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai);
|
||||
|
||||
int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
#endif // __SDCA_ASOC_H__
|
||||
|
||||
@@ -54,6 +54,11 @@ struct prop_nums {
|
||||
int platforms;
|
||||
};
|
||||
|
||||
enum simple_util_sysclk_order {
|
||||
SIMPLE_SYSCLK_ORDER_CODEC_FIRST = 0,
|
||||
SIMPLE_SYSCLK_ORDER_CPU_FIRST,
|
||||
};
|
||||
|
||||
struct simple_util_priv {
|
||||
struct snd_soc_card snd_card;
|
||||
struct simple_dai_props {
|
||||
@@ -63,6 +68,7 @@ struct simple_util_priv {
|
||||
struct snd_soc_codec_conf *codec_conf;
|
||||
struct prop_nums num;
|
||||
unsigned int mclk_fs;
|
||||
enum simple_util_sysclk_order sysclk_order;
|
||||
} *dai_props;
|
||||
struct simple_util_jack hp_jack;
|
||||
struct simple_util_jack mic_jack;
|
||||
|
||||
@@ -86,10 +86,10 @@ struct snd_soc_component_driver {
|
||||
unsigned int reg, unsigned int val);
|
||||
|
||||
/* pcm creation and destruction */
|
||||
int (*pcm_construct)(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd);
|
||||
void (*pcm_destruct)(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm);
|
||||
int (*pcm_new)(struct snd_soc_component *component,
|
||||
struct snd_soc_pcm_runtime *rtd);
|
||||
void (*pcm_free)(struct snd_soc_component *component,
|
||||
struct snd_pcm *pcm);
|
||||
|
||||
/* component wide operations */
|
||||
int (*set_sysclk)(struct snd_soc_component *component,
|
||||
@@ -224,7 +224,6 @@ struct snd_soc_component {
|
||||
int num_dai;
|
||||
|
||||
struct regmap *regmap;
|
||||
int val_bytes;
|
||||
|
||||
struct mutex io_mutex;
|
||||
|
||||
@@ -327,7 +326,7 @@ int snd_soc_component_stream_event(struct snd_soc_component *component,
|
||||
int snd_soc_component_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
void snd_soc_component_setup_regmap(struct snd_soc_component *component);
|
||||
int snd_soc_component_regmap_val_bytes(struct snd_soc_component *component);
|
||||
#ifdef CONFIG_REGMAP
|
||||
void snd_soc_component_init_regmap(struct snd_soc_component *component,
|
||||
struct regmap *regmap);
|
||||
|
||||
@@ -52,6 +52,21 @@ struct snd_compr_stream;
|
||||
#define SND_SOC_POSSIBLE_DAIFMT_AC97 (1 << SND_SOC_DAI_FORMAT_AC97)
|
||||
#define SND_SOC_POSSIBLE_DAIFMT_PDM (1 << SND_SOC_DAI_FORMAT_PDM)
|
||||
|
||||
/*
|
||||
* DAI TDM slot idle modes
|
||||
*
|
||||
* Describes a CODEC/CPU's behaviour when not actively receiving or
|
||||
* transmitting on a given TDM slot. NONE is undefined behaviour.
|
||||
* Add new modes to the end.
|
||||
*/
|
||||
#define SND_SOC_DAI_TDM_IDLE_NONE 0
|
||||
#define SND_SOC_DAI_TDM_IDLE_OFF 1
|
||||
#define SND_SOC_DAI_TDM_IDLE_ZERO 2
|
||||
#define SND_SOC_DAI_TDM_IDLE_PULLDOWN 3
|
||||
#define SND_SOC_DAI_TDM_IDLE_HIZ 4
|
||||
#define SND_SOC_DAI_TDM_IDLE_PULLUP 5
|
||||
#define SND_SOC_DAI_TDM_IDLE_DRIVE_HIGH 6
|
||||
|
||||
/*
|
||||
* DAI Clock gating.
|
||||
*
|
||||
@@ -181,6 +196,10 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
|
||||
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
|
||||
|
||||
int snd_soc_dai_set_tdm_idle(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask,
|
||||
int tx_mode, int rx_mode);
|
||||
|
||||
int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
|
||||
unsigned int tx_num, const unsigned int *tx_slot,
|
||||
unsigned int rx_num, const unsigned int *rx_slot);
|
||||
@@ -297,6 +316,9 @@ struct snd_soc_dai_ops {
|
||||
int (*set_tdm_slot)(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask,
|
||||
int slots, int slot_width);
|
||||
int (*set_tdm_idle)(struct snd_soc_dai *dai,
|
||||
unsigned int tx_mask, unsigned int rx_mask,
|
||||
int tx_mode, int rx_mode);
|
||||
int (*set_channel_map)(struct snd_soc_dai *dai,
|
||||
unsigned int tx_num, const unsigned int *tx_slot,
|
||||
unsigned int rx_num, const unsigned int *rx_slot);
|
||||
|
||||
@@ -424,6 +424,7 @@ enum snd_soc_dapm_type {
|
||||
snd_soc_dapm_input = 0, /* input pin */
|
||||
snd_soc_dapm_output, /* output pin */
|
||||
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
|
||||
snd_soc_dapm_mux_named_ctl, /* mux with named controls */
|
||||
snd_soc_dapm_demux, /* connects the input to one of multiple outputs */
|
||||
snd_soc_dapm_mixer, /* mixes several analog signals together */
|
||||
snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
|
||||
|
||||
@@ -311,6 +311,12 @@ struct platform_device;
|
||||
.info = snd_soc_info_bool_ext, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = xdata }
|
||||
#define SOC_SINGLE_BOOL_EXT_ACC(xname, xdata, xhandler_get, xhandler_put, xaccess) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.access = xaccess, \
|
||||
.info = snd_soc_info_bool_ext, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = xdata }
|
||||
#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
@@ -422,11 +428,6 @@ struct snd_soc_jack_pin;
|
||||
#include <sound/soc-dpcm.h>
|
||||
#include <sound/soc-topology.h>
|
||||
|
||||
enum snd_soc_pcm_subclass {
|
||||
SND_SOC_PCM_CLASS_PCM = 0,
|
||||
SND_SOC_PCM_CLASS_BE = 1,
|
||||
};
|
||||
|
||||
int snd_soc_register_card(struct snd_soc_card *card);
|
||||
void snd_soc_unregister_card(struct snd_soc_card *card);
|
||||
int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card);
|
||||
@@ -465,6 +466,7 @@ struct snd_soc_component *snd_soc_lookup_component_nolocked(struct device *dev,
|
||||
const char *driver_name);
|
||||
struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
|
||||
const char *driver_name);
|
||||
struct snd_soc_component *snd_soc_lookup_component_by_name(const char *component_name);
|
||||
|
||||
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd);
|
||||
#ifdef CONFIG_SND_SOC_COMPRESS
|
||||
@@ -999,7 +1001,6 @@ struct snd_soc_card {
|
||||
|
||||
/* Mutex for PCM operations */
|
||||
struct mutex pcm_mutex;
|
||||
enum snd_soc_pcm_subclass pcm_subclass;
|
||||
|
||||
int (*probe)(struct snd_soc_card *card);
|
||||
int (*late_probe)(struct snd_soc_card *card);
|
||||
@@ -1026,8 +1027,6 @@ struct snd_soc_card {
|
||||
void (*remove_dai_link)(struct snd_soc_card *,
|
||||
struct snd_soc_dai_link *link);
|
||||
|
||||
long pmdown_time;
|
||||
|
||||
/* CPU <--> Codec DAI links */
|
||||
struct snd_soc_dai_link *dai_link; /* predefined links only */
|
||||
int num_links; /* predefined links only */
|
||||
@@ -1072,9 +1071,6 @@ struct snd_soc_card {
|
||||
struct list_head dapm_list;
|
||||
struct list_head dapm_dirty;
|
||||
|
||||
/* attached dynamic objects */
|
||||
struct list_head dobj_list;
|
||||
|
||||
/* Generic DAPM context for the card */
|
||||
struct snd_soc_dapm_context *dapm;
|
||||
struct snd_soc_dapm_stats dapm_stats;
|
||||
@@ -1239,7 +1235,6 @@ struct soc_mixer_control {
|
||||
unsigned int sign_bit;
|
||||
unsigned int invert:1;
|
||||
unsigned int autodisable:1;
|
||||
unsigned int sdca_q78:1;
|
||||
#ifdef CONFIG_SND_SOC_TOPOLOGY
|
||||
struct snd_soc_dobj dobj;
|
||||
#endif
|
||||
@@ -1340,15 +1335,6 @@ void snd_soc_of_parse_node_prefix(struct device_node *np,
|
||||
struct snd_soc_codec_conf *codec_conf,
|
||||
struct device_node *of_node,
|
||||
const char *propname);
|
||||
static inline
|
||||
void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
|
||||
struct snd_soc_codec_conf *codec_conf,
|
||||
struct device_node *of_node,
|
||||
const char *propname)
|
||||
{
|
||||
snd_soc_of_parse_node_prefix(card->dev->of_node,
|
||||
codec_conf, of_node, propname);
|
||||
}
|
||||
|
||||
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
|
||||
const char *propname);
|
||||
@@ -1412,6 +1398,9 @@ struct snd_soc_dai *snd_soc_find_dai(
|
||||
struct snd_soc_dai *snd_soc_find_dai_with_mutex(
|
||||
const struct snd_soc_dai_link_component *dlc);
|
||||
|
||||
void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_hw_params *params);
|
||||
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
static inline
|
||||
@@ -1517,7 +1506,7 @@ static inline void _snd_soc_dapm_mutex_assert_held_d(struct snd_soc_dapm_context
|
||||
*/
|
||||
static inline void _snd_soc_dpcm_mutex_lock_c(struct snd_soc_card *card)
|
||||
{
|
||||
mutex_lock_nested(&card->pcm_mutex, card->pcm_subclass);
|
||||
mutex_lock(&card->pcm_mutex);
|
||||
}
|
||||
|
||||
static inline void _snd_soc_dpcm_mutex_unlock_c(struct snd_soc_card *card)
|
||||
|
||||
@@ -71,6 +71,7 @@ struct asoc_sdw_aux_info {
|
||||
};
|
||||
|
||||
struct asoc_sdw_codec_info {
|
||||
const int vendor_id;
|
||||
const int part_id;
|
||||
const int version_id;
|
||||
const char *name_prefix;
|
||||
@@ -82,6 +83,8 @@ struct asoc_sdw_codec_info {
|
||||
const int dai_num;
|
||||
struct asoc_sdw_aux_info auxs[SOC_SDW_MAX_AUX_NUM];
|
||||
const int aux_num;
|
||||
/* Force AMP-style name_prefix handling (append AMP index) even if MIC/Jack DAIs exist */
|
||||
const bool is_amp;
|
||||
|
||||
int (*codec_card_late_probe)(struct snd_soc_card *card);
|
||||
|
||||
@@ -259,6 +262,8 @@ int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_so
|
||||
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_cs47l47_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_cs47l47_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
|
||||
/* TI */
|
||||
|
||||
@@ -12,5 +12,6 @@
|
||||
int snd_tea6330t_detect(struct snd_i2c_bus *bus, int equalizer);
|
||||
int snd_tea6330t_update_mixer(struct snd_card *card, struct snd_i2c_bus *bus,
|
||||
int equalizer, int fader);
|
||||
int snd_tea6330t_restore_mixer(struct snd_i2c_bus *bus);
|
||||
|
||||
#endif /* __SOUND_TEA6330T_H */
|
||||
|
||||
@@ -102,6 +102,7 @@ struct snd_timer_instance {
|
||||
unsigned int slave_id;
|
||||
struct list_head open_list;
|
||||
struct list_head active_list;
|
||||
struct list_head master_list;
|
||||
struct list_head ack_list;
|
||||
struct list_head slave_list_head;
|
||||
struct list_head slave_active_head;
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* UDA1380 ALSA SoC Codec driver
|
||||
*
|
||||
* Copyright 2009 Philipp Zabel
|
||||
*/
|
||||
|
||||
#ifndef __UDA1380_H
|
||||
#define __UDA1380_H
|
||||
|
||||
struct uda1380_platform_data {
|
||||
int gpio_power;
|
||||
int gpio_reset;
|
||||
int dac_clk;
|
||||
#define UDA1380_DAC_CLK_SYSCLK 0
|
||||
#define UDA1380_DAC_CLK_WSPLL 1
|
||||
};
|
||||
|
||||
#endif /* __UDA1380_H */
|
||||
@@ -48,7 +48,7 @@ struct aoa_codec {
|
||||
u32 connected;
|
||||
|
||||
/* data the fabric can associate with this structure */
|
||||
void *fabric_data;
|
||||
const void *fabric_data;
|
||||
|
||||
/* private! */
|
||||
struct list_head list;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/asoundef.h>
|
||||
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");
|
||||
@@ -514,8 +515,36 @@ static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int onyx_set_spdif_pcm_rate(struct onyx *onyx, unsigned int rate)
|
||||
{
|
||||
u8 dig_info3, fs;
|
||||
|
||||
switch (rate) {
|
||||
case 32000:
|
||||
fs = IEC958_AES3_CON_FS_32000;
|
||||
break;
|
||||
case 44100:
|
||||
fs = IEC958_AES3_CON_FS_44100;
|
||||
break;
|
||||
case 48000:
|
||||
fs = IEC958_AES3_CON_FS_48000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &dig_info3))
|
||||
return -EBUSY;
|
||||
dig_info3 = (dig_info3 & ~IEC958_AES3_CON_FS) | fs;
|
||||
if (onyx_write_register(onyx, ONYX_REG_DIG_INFO3, dig_info3))
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new onyx_spdif_ctrl = {
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_VOLATILE,
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
|
||||
.info = onyx_spdif_info,
|
||||
@@ -695,9 +724,9 @@ static int onyx_prepare(struct codec_info_item *cii,
|
||||
case 32000:
|
||||
case 44100:
|
||||
case 48000:
|
||||
/* these rates are ok for all outputs */
|
||||
/* FIXME: program spdif channel control bits here so that
|
||||
* userspace doesn't have to if it only plays pcm! */
|
||||
if (onyx->codec.connected & 2)
|
||||
return onyx_set_spdif_pcm_rate(onyx,
|
||||
substream->runtime->rate);
|
||||
return 0;
|
||||
default:
|
||||
/* got some rate that the digital output can't do,
|
||||
@@ -980,10 +1009,12 @@ static int onyx_i2c_probe(struct i2c_client *client)
|
||||
onyx->codec.node = of_node_get(node);
|
||||
|
||||
if (aoa_codec_register(&onyx->codec)) {
|
||||
goto fail;
|
||||
goto fail_put;
|
||||
}
|
||||
printk(KERN_DEBUG PFX "created and attached onyx instance\n");
|
||||
return 0;
|
||||
fail_put:
|
||||
of_node_put(onyx->codec.node);
|
||||
fail:
|
||||
kfree(onyx);
|
||||
return -ENODEV;
|
||||
|
||||
@@ -872,6 +872,7 @@ static int tas_i2c_probe(struct i2c_client *client)
|
||||
return 0;
|
||||
fail:
|
||||
mutex_destroy(&tas->mtx);
|
||||
of_node_put(tas->codec.node);
|
||||
kfree(tas);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ struct codec_connection {
|
||||
|
||||
struct codec_connect_info {
|
||||
char *name;
|
||||
struct codec_connection *connections;
|
||||
const struct codec_connection *connections;
|
||||
};
|
||||
|
||||
#define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0)
|
||||
@@ -116,7 +116,7 @@ MODULE_ALIAS("aoa-device-id-35");
|
||||
MODULE_ALIAS("aoa-device-id-44");
|
||||
|
||||
/* onyx with all but microphone connected */
|
||||
static struct codec_connection onyx_connections_nomic[] = {
|
||||
static const struct codec_connection onyx_connections_nomic[] = {
|
||||
{
|
||||
.connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
|
||||
.codec_bit = 0,
|
||||
@@ -133,7 +133,7 @@ static struct codec_connection onyx_connections_nomic[] = {
|
||||
};
|
||||
|
||||
/* onyx on machines without headphone */
|
||||
static struct codec_connection onyx_connections_noheadphones[] = {
|
||||
static const struct codec_connection onyx_connections_noheadphones[] = {
|
||||
{
|
||||
.connected = CC_SPEAKERS | CC_LINEOUT |
|
||||
CC_LINEOUT_LABELLED_HEADPHONE,
|
||||
@@ -157,7 +157,7 @@ static struct codec_connection onyx_connections_noheadphones[] = {
|
||||
};
|
||||
|
||||
/* onyx on machines with real line-out */
|
||||
static struct codec_connection onyx_connections_reallineout[] = {
|
||||
static const struct codec_connection onyx_connections_reallineout[] = {
|
||||
{
|
||||
.connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE,
|
||||
.codec_bit = 0,
|
||||
@@ -174,7 +174,7 @@ static struct codec_connection onyx_connections_reallineout[] = {
|
||||
};
|
||||
|
||||
/* tas on machines without line out */
|
||||
static struct codec_connection tas_connections_nolineout[] = {
|
||||
static const struct codec_connection tas_connections_nolineout[] = {
|
||||
{
|
||||
.connected = CC_SPEAKERS | CC_HEADPHONE,
|
||||
.codec_bit = 0,
|
||||
@@ -191,7 +191,7 @@ static struct codec_connection tas_connections_nolineout[] = {
|
||||
};
|
||||
|
||||
/* tas on machines with neither line out nor line in */
|
||||
static struct codec_connection tas_connections_noline[] = {
|
||||
static const struct codec_connection tas_connections_noline[] = {
|
||||
{
|
||||
.connected = CC_SPEAKERS | CC_HEADPHONE,
|
||||
.codec_bit = 0,
|
||||
@@ -204,7 +204,7 @@ static struct codec_connection tas_connections_noline[] = {
|
||||
};
|
||||
|
||||
/* tas on machines without microphone */
|
||||
static struct codec_connection tas_connections_nomic[] = {
|
||||
static const struct codec_connection tas_connections_nomic[] = {
|
||||
{
|
||||
.connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
|
||||
.codec_bit = 0,
|
||||
@@ -217,7 +217,7 @@ static struct codec_connection tas_connections_nomic[] = {
|
||||
};
|
||||
|
||||
/* tas on machines with everything connected */
|
||||
static struct codec_connection tas_connections_all[] = {
|
||||
static const struct codec_connection tas_connections_all[] = {
|
||||
{
|
||||
.connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
|
||||
.codec_bit = 0,
|
||||
@@ -233,7 +233,7 @@ static struct codec_connection tas_connections_all[] = {
|
||||
{} /* terminate array by .connected == 0 */
|
||||
};
|
||||
|
||||
static struct codec_connection toonie_connections[] = {
|
||||
static const struct codec_connection toonie_connections[] = {
|
||||
{
|
||||
.connected = CC_SPEAKERS | CC_HEADPHONE,
|
||||
.codec_bit = 0,
|
||||
@@ -241,7 +241,7 @@ static struct codec_connection toonie_connections[] = {
|
||||
{} /* terminate array by .connected == 0 */
|
||||
};
|
||||
|
||||
static struct codec_connection topaz_input[] = {
|
||||
static const struct codec_connection topaz_input[] = {
|
||||
{
|
||||
.connected = CC_DIGITALIN,
|
||||
.codec_bit = 0,
|
||||
@@ -249,7 +249,7 @@ static struct codec_connection topaz_input[] = {
|
||||
{} /* terminate array by .connected == 0 */
|
||||
};
|
||||
|
||||
static struct codec_connection topaz_output[] = {
|
||||
static const struct codec_connection topaz_output[] = {
|
||||
{
|
||||
.connected = CC_DIGITALOUT,
|
||||
.codec_bit = 1,
|
||||
@@ -257,7 +257,7 @@ static struct codec_connection topaz_output[] = {
|
||||
{} /* terminate array by .connected == 0 */
|
||||
};
|
||||
|
||||
static struct codec_connection topaz_inout[] = {
|
||||
static const struct codec_connection topaz_inout[] = {
|
||||
{
|
||||
.connected = CC_DIGITALIN,
|
||||
.codec_bit = 0,
|
||||
@@ -772,7 +772,7 @@ static int check_codec(struct aoa_codec *codec,
|
||||
{
|
||||
const u32 *ref;
|
||||
char propname[32];
|
||||
struct codec_connection *cc;
|
||||
const struct codec_connection *cc;
|
||||
|
||||
/* if the codec has a 'codec' node, we require a reference */
|
||||
if (of_node_name_eq(codec->node, "codec")) {
|
||||
@@ -895,7 +895,7 @@ static void layout_notify(void *data)
|
||||
|
||||
static void layout_attached_codec(struct aoa_codec *codec)
|
||||
{
|
||||
struct codec_connection *cc;
|
||||
const struct codec_connection *cc;
|
||||
struct snd_kcontrol *ctl;
|
||||
int headphones, lineout;
|
||||
struct layout_dev *ldev = layout_device;
|
||||
|
||||
@@ -84,6 +84,7 @@ static void i2sbus_release_dev(struct device *dev)
|
||||
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
|
||||
free_irq(i2sdev->interrupts[i], i2sdev);
|
||||
i2sbus_control_remove_dev(i2sdev->control, i2sdev);
|
||||
of_node_put(i2sdev->sound.ofdev.dev.of_node);
|
||||
mutex_destroy(&i2sdev->lock);
|
||||
kfree(i2sdev);
|
||||
}
|
||||
@@ -147,7 +148,6 @@ static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
|
||||
}
|
||||
|
||||
/* Returns 1 if added, 0 for otherwise; don't return a negative value! */
|
||||
/* FIXME: look at device node refcounting */
|
||||
static int i2sbus_add_dev(struct macio_dev *macio,
|
||||
struct i2sbus_control *control,
|
||||
struct device_node *np)
|
||||
@@ -178,8 +178,9 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
||||
i = 0;
|
||||
for_each_child_of_node(np, child) {
|
||||
if (of_node_name_eq(child, "sound")) {
|
||||
of_node_put(sound);
|
||||
i++;
|
||||
sound = child;
|
||||
sound = of_node_get(child);
|
||||
}
|
||||
}
|
||||
if (i == 1) {
|
||||
@@ -205,6 +206,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
||||
}
|
||||
}
|
||||
}
|
||||
of_node_put(sound);
|
||||
/* for the time being, until we can handle non-layout-id
|
||||
* things in some fabric, refuse to attach if there is no
|
||||
* layout-id property or we haven't been forced to attach.
|
||||
@@ -219,7 +221,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
||||
mutex_init(&dev->lock);
|
||||
spin_lock_init(&dev->low_lock);
|
||||
dev->sound.ofdev.archdata.dma_mask = macio->ofdev.archdata.dma_mask;
|
||||
dev->sound.ofdev.dev.of_node = np;
|
||||
dev->sound.ofdev.dev.of_node = of_node_get(np);
|
||||
dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.archdata.dma_mask;
|
||||
dev->sound.ofdev.dev.parent = &macio->ofdev.dev;
|
||||
dev->sound.ofdev.dev.release = i2sbus_release_dev;
|
||||
@@ -327,6 +329,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
||||
for (i=0;i<3;i++)
|
||||
release_and_free_resource(dev->allocated_resource[i]);
|
||||
mutex_destroy(&dev->lock);
|
||||
of_node_put(dev->sound.ofdev.dev.of_node);
|
||||
kfree(dev);
|
||||
return 0;
|
||||
}
|
||||
@@ -405,6 +408,9 @@ static int i2sbus_resume(struct macio_dev* dev)
|
||||
int err, ret = 0;
|
||||
|
||||
list_for_each_entry(i2sdev, &control->list, item) {
|
||||
if (list_empty(&i2sdev->sound.codec_list))
|
||||
continue;
|
||||
|
||||
/* reset i2s bus format etc. */
|
||||
i2sbus_pcm_prepare_both(i2sdev);
|
||||
|
||||
|
||||
@@ -165,17 +165,16 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
|
||||
* currently in use (if any). */
|
||||
hw->rate_min = 5512;
|
||||
hw->rate_max = 192000;
|
||||
/* if the other stream is active, then we can only
|
||||
* support what it is currently using.
|
||||
* FIXME: I lied. This comment is wrong. We can support
|
||||
* anything that works with the same serial format, ie.
|
||||
* when recording 24 bit sound we can well play 16 bit
|
||||
* sound at the same time iff using the same transfer mode.
|
||||
/* If the other stream is already prepared, keep this stream
|
||||
* on the same duplex format and rate.
|
||||
*
|
||||
* i2sbus_pcm_prepare() still programs one shared transport
|
||||
* configuration for both directions, so mixed duplex formats
|
||||
* are not supported here.
|
||||
*/
|
||||
if (other->active) {
|
||||
/* FIXME: is this guaranteed by the alsa api? */
|
||||
hw->formats &= pcm_format_to_bits(i2sdev->format);
|
||||
/* see above, restrict rates to the one we already have */
|
||||
/* Restrict rates to the one already in use. */
|
||||
hw->rate_min = i2sdev->rate;
|
||||
hw->rate_max = i2sdev->rate;
|
||||
}
|
||||
@@ -283,6 +282,23 @@ void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void i2sbus_pcm_clear_active(struct i2sbus_dev *i2sdev, int in)
|
||||
{
|
||||
struct pcm_info *pi;
|
||||
|
||||
guard(mutex)(&i2sdev->lock);
|
||||
|
||||
get_pcm_info(i2sdev, in, &pi, NULL);
|
||||
pi->active = 0;
|
||||
}
|
||||
|
||||
static inline int i2sbus_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, int in)
|
||||
{
|
||||
i2sbus_pcm_clear_active(snd_pcm_substream_chip(substream), in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
|
||||
{
|
||||
struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream);
|
||||
@@ -291,14 +307,27 @@ static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in)
|
||||
get_pcm_info(i2sdev, in, &pi, NULL);
|
||||
if (pi->dbdma_ring.stopping)
|
||||
i2sbus_wait_for_stop(i2sdev, pi);
|
||||
i2sbus_pcm_clear_active(i2sdev, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2sbus_playback_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
return i2sbus_hw_params(substream, params, 0);
|
||||
}
|
||||
|
||||
static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return i2sbus_hw_free(substream, 0);
|
||||
}
|
||||
|
||||
static int i2sbus_record_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
return i2sbus_hw_params(substream, params, 1);
|
||||
}
|
||||
|
||||
static int i2sbus_record_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return i2sbus_hw_free(substream, 1);
|
||||
@@ -335,7 +364,6 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
||||
return -EINVAL;
|
||||
|
||||
runtime = pi->substream->runtime;
|
||||
pi->active = 1;
|
||||
if (other->active &&
|
||||
((i2sdev->format != runtime->format)
|
||||
|| (i2sdev->rate != runtime->rate)))
|
||||
@@ -383,6 +411,9 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
||||
/* set stop command */
|
||||
command->command = cpu_to_le16(DBDMA_STOP);
|
||||
|
||||
cii = list_first_entry(&i2sdev->sound.codec_list,
|
||||
struct codec_info_item, list);
|
||||
|
||||
/* ok, let's set the serial format and stuff */
|
||||
switch (runtime->format) {
|
||||
/* 16 bit formats */
|
||||
@@ -390,13 +421,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
||||
case SNDRV_PCM_FORMAT_U16_BE:
|
||||
/* FIXME: if we add different bus factors we need to
|
||||
* do more here!! */
|
||||
bi.bus_factor = 0;
|
||||
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
|
||||
bi.bus_factor = cii->codec->bus_factor;
|
||||
break;
|
||||
}
|
||||
if (!bi.bus_factor)
|
||||
return -ENODEV;
|
||||
bi.bus_factor = cii->codec->bus_factor;
|
||||
input_16bit = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_BE:
|
||||
@@ -410,10 +435,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
||||
return -EINVAL;
|
||||
}
|
||||
/* we assume all sysclocks are the same! */
|
||||
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
|
||||
bi.sysclock_factor = cii->codec->sysclock_factor;
|
||||
break;
|
||||
}
|
||||
bi.sysclock_factor = cii->codec->sysclock_factor;
|
||||
|
||||
if (clock_and_divisors(bi.sysclock_factor,
|
||||
bi.bus_factor,
|
||||
@@ -450,9 +472,11 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
||||
|
||||
/* early exit if already programmed correctly */
|
||||
/* not locking these is fine since we touch them only in this function */
|
||||
if (in_le32(&i2sdev->intfregs->serial_format) == sfr
|
||||
&& in_le32(&i2sdev->intfregs->data_word_sizes) == dws)
|
||||
if (in_le32(&i2sdev->intfregs->serial_format) == sfr &&
|
||||
in_le32(&i2sdev->intfregs->data_word_sizes) == dws) {
|
||||
pi->active = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* let's notify the codecs about clocks going away.
|
||||
* For now we only do mastering on the i2s cell... */
|
||||
@@ -490,6 +514,7 @@ static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in)
|
||||
if (cii->codec->switch_clock)
|
||||
cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE);
|
||||
|
||||
pi->active = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -734,6 +759,7 @@ static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream
|
||||
static const struct snd_pcm_ops i2sbus_playback_ops = {
|
||||
.open = i2sbus_playback_open,
|
||||
.close = i2sbus_playback_close,
|
||||
.hw_params = i2sbus_playback_hw_params,
|
||||
.hw_free = i2sbus_playback_hw_free,
|
||||
.prepare = i2sbus_playback_prepare,
|
||||
.trigger = i2sbus_playback_trigger,
|
||||
@@ -802,6 +828,7 @@ static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream
|
||||
static const struct snd_pcm_ops i2sbus_record_ops = {
|
||||
.open = i2sbus_record_open,
|
||||
.close = i2sbus_record_close,
|
||||
.hw_params = i2sbus_record_hw_params,
|
||||
.hw_free = i2sbus_record_hw_free,
|
||||
.prepare = i2sbus_record_prepare,
|
||||
.trigger = i2sbus_record_trigger,
|
||||
|
||||
@@ -23,6 +23,7 @@ snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o
|
||||
# for trace-points
|
||||
CFLAGS_pcm_lib.o := -I$(src)
|
||||
CFLAGS_pcm_native.o := -I$(src)
|
||||
CFLAGS_control.o := -I$(src)
|
||||
|
||||
snd-pcm-dmaengine-y := pcm_dmaengine.o
|
||||
|
||||
|
||||
@@ -41,13 +41,6 @@
|
||||
#define COMPR_CODEC_CAPS_OVERFLOW
|
||||
#endif
|
||||
|
||||
/* TODO:
|
||||
* - add substream support for multiple devices in case of
|
||||
* SND_DYNAMIC_MINORS is not used
|
||||
* - Multiple node representation
|
||||
* driver should be able to register multiple nodes
|
||||
*/
|
||||
|
||||
struct snd_compr_file {
|
||||
unsigned long caps;
|
||||
struct snd_compr_stream stream;
|
||||
@@ -190,9 +183,21 @@ snd_compr_tstamp32_from_64(struct snd_compr_tstamp *tstamp32,
|
||||
static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
|
||||
struct snd_compr_tstamp64 *tstamp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!stream->ops->pointer)
|
||||
return -ENOTSUPP;
|
||||
stream->ops->pointer(stream, tstamp);
|
||||
|
||||
switch (stream->runtime->state) {
|
||||
case SNDRV_PCM_STATE_OPEN:
|
||||
return -EBADFD;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = stream->ops->pointer(stream, tstamp);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
pr_debug("dsp consumed till %u total %llu bytes\n", tstamp->byte_offset,
|
||||
tstamp->copied_total);
|
||||
if (stream->direction == SND_COMPRESS_PLAYBACK)
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
#include <sound/info.h>
|
||||
#include <sound/control.h>
|
||||
|
||||
#ifdef CONFIG_SND_CTL_DEBUG
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "control_trace.h"
|
||||
#else
|
||||
#define trace_snd_ctl_put(card, kctl, iname, expected, actual)
|
||||
#endif
|
||||
|
||||
// Max allocation size for user controls.
|
||||
static int max_user_ctl_alloc_size = 8 * 1024 * 1024;
|
||||
module_param_named(max_user_ctl_alloc_size, max_user_ctl_alloc_size, int, 0444);
|
||||
@@ -1264,6 +1271,72 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
|
||||
return result;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_CTL_DEBUG)
|
||||
|
||||
static const char *const snd_ctl_elem_iface_names[] = {
|
||||
[SNDRV_CTL_ELEM_IFACE_CARD] = "CARD",
|
||||
[SNDRV_CTL_ELEM_IFACE_HWDEP] = "HWDEP",
|
||||
[SNDRV_CTL_ELEM_IFACE_MIXER] = "MIXER",
|
||||
[SNDRV_CTL_ELEM_IFACE_PCM] = "PCM",
|
||||
[SNDRV_CTL_ELEM_IFACE_RAWMIDI] = "RAWMIDI",
|
||||
[SNDRV_CTL_ELEM_IFACE_TIMER] = "TIMER",
|
||||
[SNDRV_CTL_ELEM_IFACE_SEQUENCER] = "SEQUENCER",
|
||||
};
|
||||
|
||||
static int snd_ctl_put_verify(struct snd_card *card, struct snd_kcontrol *kctl,
|
||||
struct snd_ctl_elem_value *control)
|
||||
{
|
||||
struct snd_ctl_elem_value *original = card->value_buf;
|
||||
struct snd_ctl_elem_info info;
|
||||
const char *iname;
|
||||
int ret, retcmp;
|
||||
|
||||
memset(original, 0, sizeof(*original));
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
ret = kctl->info(kctl, &info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kctl->get(kctl, original);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kctl->put(kctl, control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Sanitize the new value (control->value) before comparing. */
|
||||
fill_remaining_elem_value(control, &info, 0);
|
||||
|
||||
/* With known state for both new and original, do the comparison. */
|
||||
retcmp = memcmp(&original->value, &control->value, sizeof(original->value));
|
||||
if (retcmp)
|
||||
retcmp = 1;
|
||||
|
||||
iname = snd_ctl_elem_iface_names[kctl->id.iface];
|
||||
trace_snd_ctl_put(&kctl->id, iname, card->number, ret, retcmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int snd_ctl_put(struct snd_card *card, struct snd_kcontrol *kctl,
|
||||
struct snd_ctl_elem_value *control, unsigned int access)
|
||||
{
|
||||
if ((access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK) ||
|
||||
(access & SNDRV_CTL_ELEM_ACCESS_VOLATILE))
|
||||
return kctl->put(kctl, control);
|
||||
|
||||
return snd_ctl_put_verify(card, kctl, control);
|
||||
}
|
||||
#else
|
||||
static inline int snd_ctl_put(struct snd_card *card, struct snd_kcontrol *kctl,
|
||||
struct snd_ctl_elem_value *control, unsigned int access)
|
||||
{
|
||||
return kctl->put(kctl, control);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
|
||||
struct snd_ctl_elem_value *control)
|
||||
{
|
||||
@@ -1300,7 +1373,8 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
|
||||
false);
|
||||
}
|
||||
if (!result)
|
||||
result = kctl->put(kctl, control);
|
||||
result = snd_ctl_put(card, kctl, control, vd->access);
|
||||
|
||||
if (result < 0) {
|
||||
up_write(&card->controls_rwsem);
|
||||
return result;
|
||||
@@ -1574,6 +1648,10 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue)
|
||||
/* check that there are enough valid names */
|
||||
p = names;
|
||||
for (i = 0; i < ue->info.value.enumerated.items; ++i) {
|
||||
if (buf_len == 0) {
|
||||
kvfree(names);
|
||||
return -EINVAL;
|
||||
}
|
||||
name_len = strnlen(p, buf_len);
|
||||
if (name_len == 0 || name_len >= 64 || name_len == buf_len) {
|
||||
kvfree(names);
|
||||
|
||||
55
sound/core/control_trace.h
Normal file
55
sound/core/control_trace.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM snd_ctl
|
||||
|
||||
#if !defined(_TRACE_SND_CTL_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_SND_CTL_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
#include <uapi/sound/asound.h>
|
||||
|
||||
TRACE_EVENT(snd_ctl_put,
|
||||
|
||||
TP_PROTO(struct snd_ctl_elem_id *id, const char *iname, unsigned int card,
|
||||
int expected, int actual),
|
||||
|
||||
TP_ARGS(id, iname, card, expected, actual),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, numid)
|
||||
__string(iname, iname)
|
||||
__string(kname, id->name)
|
||||
__field(unsigned int, index)
|
||||
__field(unsigned int, device)
|
||||
__field(unsigned int, subdevice)
|
||||
__field(unsigned int, card)
|
||||
__field(int, expected)
|
||||
__field(int, actual)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->numid = id->numid;
|
||||
__assign_str(iname);
|
||||
__assign_str(kname);
|
||||
__entry->index = id->index;
|
||||
__entry->device = id->device;
|
||||
__entry->subdevice = id->subdevice;
|
||||
__entry->card = card;
|
||||
__entry->expected = expected;
|
||||
__entry->actual = actual;
|
||||
),
|
||||
|
||||
TP_printk("%s: expected=%d, actual=%d for ctl numid=%d, iface=%s, name='%s', index=%d, device=%d, subdevice=%d, card=%d\n",
|
||||
__entry->expected == __entry->actual ? "success" : "fail",
|
||||
__entry->expected, __entry->actual, __entry->numid,
|
||||
__get_str(iname), __get_str(kname), __entry->index,
|
||||
__entry->device, __entry->subdevice, __entry->card)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_SND_CTL_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#define TRACE_INCLUDE_FILE control_trace
|
||||
#include <trace/define_trace.h>
|
||||
@@ -362,6 +362,11 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
card->debugfs_root = debugfs_create_dir(dev_name(&card->card_dev),
|
||||
sound_debugfs_root);
|
||||
#endif
|
||||
#ifdef CONFIG_SND_CTL_DEBUG
|
||||
card->value_buf = kmalloc(sizeof(*card->value_buf), GFP_KERNEL);
|
||||
if (!card->value_buf)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
@@ -587,6 +592,9 @@ static int snd_card_do_free(struct snd_card *card)
|
||||
snd_device_free_all(card);
|
||||
if (card->private_free)
|
||||
card->private_free(card);
|
||||
#ifdef CONFIG_SND_CTL_DEBUG
|
||||
kfree(card->value_buf);
|
||||
#endif
|
||||
if (snd_info_card_free(card) < 0) {
|
||||
dev_warn(card->dev, "unable to free card info\n");
|
||||
/* Not fatal error */
|
||||
|
||||
@@ -1227,14 +1227,16 @@ static int snd_pcm_oss_capture_position_fixup(struct snd_pcm_substream *substrea
|
||||
snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
snd_pcm_state_t state;
|
||||
int ret;
|
||||
while (1) {
|
||||
if (runtime->state == SNDRV_PCM_STATE_XRUN ||
|
||||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
|
||||
state = snd_pcm_get_state(substream);
|
||||
if (state == SNDRV_PCM_STATE_XRUN ||
|
||||
state == SNDRV_PCM_STATE_SUSPENDED) {
|
||||
#ifdef OSS_DEBUG
|
||||
pcm_dbg(substream->pcm,
|
||||
"pcm_oss: write: recovering from %s\n",
|
||||
runtime->state == SNDRV_PCM_STATE_XRUN ?
|
||||
state == SNDRV_PCM_STATE_XRUN ?
|
||||
"XRUN" : "SUSPEND");
|
||||
#endif
|
||||
ret = snd_pcm_oss_prepare(substream);
|
||||
@@ -1249,7 +1251,7 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
|
||||
break;
|
||||
/* test, if we can't store new data, because the stream */
|
||||
/* has not been started */
|
||||
if (runtime->state == SNDRV_PCM_STATE_PREPARED)
|
||||
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_PREPARED)
|
||||
return -EAGAIN;
|
||||
}
|
||||
return ret;
|
||||
@@ -1259,20 +1261,22 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
snd_pcm_sframes_t delay;
|
||||
snd_pcm_state_t state;
|
||||
int ret;
|
||||
while (1) {
|
||||
if (runtime->state == SNDRV_PCM_STATE_XRUN ||
|
||||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
|
||||
state = snd_pcm_get_state(substream);
|
||||
if (state == SNDRV_PCM_STATE_XRUN ||
|
||||
state == SNDRV_PCM_STATE_SUSPENDED) {
|
||||
#ifdef OSS_DEBUG
|
||||
pcm_dbg(substream->pcm,
|
||||
"pcm_oss: read: recovering from %s\n",
|
||||
runtime->state == SNDRV_PCM_STATE_XRUN ?
|
||||
state == SNDRV_PCM_STATE_XRUN ?
|
||||
"XRUN" : "SUSPEND");
|
||||
#endif
|
||||
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
|
||||
if (ret < 0)
|
||||
break;
|
||||
} else if (runtime->state == SNDRV_PCM_STATE_SETUP) {
|
||||
} else if (state == SNDRV_PCM_STATE_SETUP) {
|
||||
ret = snd_pcm_oss_prepare(substream);
|
||||
if (ret < 0)
|
||||
break;
|
||||
@@ -1285,7 +1289,7 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
|
||||
frames, in_kernel);
|
||||
mutex_lock(&runtime->oss.params_lock);
|
||||
if (ret == -EPIPE) {
|
||||
if (runtime->state == SNDRV_PCM_STATE_DRAINING) {
|
||||
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_DRAINING) {
|
||||
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
|
||||
if (ret < 0)
|
||||
break;
|
||||
@@ -1301,15 +1305,16 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
|
||||
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
|
||||
snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
snd_pcm_state_t state;
|
||||
int ret;
|
||||
while (1) {
|
||||
if (runtime->state == SNDRV_PCM_STATE_XRUN ||
|
||||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
|
||||
state = snd_pcm_get_state(substream);
|
||||
if (state == SNDRV_PCM_STATE_XRUN ||
|
||||
state == SNDRV_PCM_STATE_SUSPENDED) {
|
||||
#ifdef OSS_DEBUG
|
||||
pcm_dbg(substream->pcm,
|
||||
"pcm_oss: writev: recovering from %s\n",
|
||||
runtime->state == SNDRV_PCM_STATE_XRUN ?
|
||||
state == SNDRV_PCM_STATE_XRUN ?
|
||||
"XRUN" : "SUSPEND");
|
||||
#endif
|
||||
ret = snd_pcm_oss_prepare(substream);
|
||||
@@ -1322,7 +1327,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
|
||||
|
||||
/* test, if we can't store new data, because the stream */
|
||||
/* has not been started */
|
||||
if (runtime->state == SNDRV_PCM_STATE_PREPARED)
|
||||
if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_PREPARED)
|
||||
return -EAGAIN;
|
||||
}
|
||||
return ret;
|
||||
@@ -1330,21 +1335,22 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
|
||||
|
||||
snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
snd_pcm_state_t state;
|
||||
int ret;
|
||||
while (1) {
|
||||
if (runtime->state == SNDRV_PCM_STATE_XRUN ||
|
||||
runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
|
||||
state = snd_pcm_get_state(substream);
|
||||
if (state == SNDRV_PCM_STATE_XRUN ||
|
||||
state == SNDRV_PCM_STATE_SUSPENDED) {
|
||||
#ifdef OSS_DEBUG
|
||||
pcm_dbg(substream->pcm,
|
||||
"pcm_oss: readv: recovering from %s\n",
|
||||
runtime->state == SNDRV_PCM_STATE_XRUN ?
|
||||
state == SNDRV_PCM_STATE_XRUN ?
|
||||
"XRUN" : "SUSPEND");
|
||||
#endif
|
||||
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
|
||||
if (ret < 0)
|
||||
break;
|
||||
} else if (runtime->state == SNDRV_PCM_STATE_SETUP) {
|
||||
} else if (state == SNDRV_PCM_STATE_SETUP) {
|
||||
ret = snd_pcm_oss_prepare(substream);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
@@ -430,11 +430,13 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
|
||||
if (!boundary)
|
||||
boundary = 0x7fffffff;
|
||||
scoped_guard(pcm_stream_lock_irq, substream) {
|
||||
/* FIXME: we should consider the boundary for the sync from app */
|
||||
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
|
||||
control->appl_ptr = scontrol.appl_ptr;
|
||||
else
|
||||
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
|
||||
err = pcm_lib_apply_appl_ptr(substream, scontrol.appl_ptr);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
scontrol.appl_ptr = control->appl_ptr % boundary;
|
||||
}
|
||||
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
|
||||
control->avail_min = scontrol.avail_min;
|
||||
else
|
||||
|
||||
@@ -618,13 +618,32 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
|
||||
return usecs;
|
||||
}
|
||||
|
||||
static void snd_pcm_set_state(struct snd_pcm_substream *substream,
|
||||
snd_pcm_state_t state)
|
||||
/**
|
||||
* snd_pcm_set_state - Set the PCM runtime state with stream lock
|
||||
* @substream: PCM substream
|
||||
* @state: state to set
|
||||
*/
|
||||
void snd_pcm_set_state(struct snd_pcm_substream *substream,
|
||||
snd_pcm_state_t state)
|
||||
{
|
||||
guard(pcm_stream_lock_irq)(substream);
|
||||
if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED)
|
||||
__snd_pcm_set_state(substream->runtime, state);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_pcm_set_state);
|
||||
|
||||
/**
|
||||
* snd_pcm_get_state - Read the PCM runtime state with stream lock
|
||||
* @substream: PCM substream
|
||||
*
|
||||
* Return: the current PCM state
|
||||
*/
|
||||
snd_pcm_state_t snd_pcm_get_state(struct snd_pcm_substream *substream)
|
||||
{
|
||||
guard(pcm_stream_lock_irqsave)(substream);
|
||||
return substream->runtime->state;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_pcm_get_state);
|
||||
|
||||
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
|
||||
int event)
|
||||
@@ -1761,6 +1780,9 @@ static int snd_pcm_suspend(struct snd_pcm_substream *substream)
|
||||
* snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm
|
||||
* @pcm: the PCM instance
|
||||
*
|
||||
* Takes and releases pcm->open_mutex to serialize against
|
||||
* concurrent open/close while walking the substreams.
|
||||
*
|
||||
* After this call, all streams are changed to SUSPENDED state.
|
||||
*
|
||||
* Return: Zero if successful (or @pcm is %NULL), or a negative error code.
|
||||
@@ -1773,8 +1795,9 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)
|
||||
if (! pcm)
|
||||
return 0;
|
||||
|
||||
guard(mutex)(&pcm->open_mutex);
|
||||
|
||||
for_each_pcm_substream(pcm, stream, substream) {
|
||||
/* FIXME: the open/close code should lock this as well */
|
||||
if (!substream->runtime)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -101,9 +101,9 @@ snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count,
|
||||
break;
|
||||
}
|
||||
fmt = (*(unsigned short *)rec.c) & 0xffff;
|
||||
/* FIXME the return value isn't correct */
|
||||
return snd_seq_oss_synth_load_patch(dp, rec.s.dev,
|
||||
fmt, buf, 0, count);
|
||||
err = snd_seq_oss_synth_load_patch(dp, rec.s.dev,
|
||||
fmt, buf, 0, count);
|
||||
return err < 0 ? err : count;
|
||||
}
|
||||
if (ev_is_long(&rec)) {
|
||||
/* extended code */
|
||||
|
||||
@@ -841,7 +841,7 @@ static int cc_ev_to_ump_midi2(const struct snd_seq_event *event,
|
||||
unsigned char index = event->data.control.param & 0x7f;
|
||||
unsigned char val = event->data.control.value & 0x7f;
|
||||
struct ump_cvt_to_ump_bank *cc = &dest_port->midi2_bank[channel];
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/* process special CC's (bank/rpn/nrpn) */
|
||||
switch (index) {
|
||||
@@ -851,47 +851,54 @@ static int cc_ev_to_ump_midi2(const struct snd_seq_event *event,
|
||||
cc->cc_rpn_msb = val;
|
||||
if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
|
||||
reset_rpn(cc);
|
||||
return ret;
|
||||
break;
|
||||
case UMP_CC_RPN_LSB:
|
||||
ret = fill_rpn(cc, data, channel, true);
|
||||
cc->rpn_set = 1;
|
||||
cc->cc_rpn_lsb = val;
|
||||
if (cc->cc_rpn_msb == 0x7f && cc->cc_rpn_lsb == 0x7f)
|
||||
reset_rpn(cc);
|
||||
return ret;
|
||||
break;
|
||||
case UMP_CC_NRPN_MSB:
|
||||
ret = fill_rpn(cc, data, channel, true);
|
||||
cc->nrpn_set = 1;
|
||||
cc->cc_nrpn_msb = val;
|
||||
return ret;
|
||||
break;
|
||||
case UMP_CC_NRPN_LSB:
|
||||
ret = fill_rpn(cc, data, channel, true);
|
||||
cc->nrpn_set = 1;
|
||||
cc->cc_nrpn_lsb = val;
|
||||
return ret;
|
||||
break;
|
||||
case UMP_CC_DATA:
|
||||
cc->cc_data_msb_set = 1;
|
||||
cc->cc_data_msb = val;
|
||||
return fill_rpn(cc, data, channel, false);
|
||||
ret = fill_rpn(cc, data, channel, false);
|
||||
break;
|
||||
case UMP_CC_BANK_SELECT:
|
||||
cc->bank_set = 1;
|
||||
cc->cc_bank_msb = val;
|
||||
return 0; // skip
|
||||
ret = 0; // skip
|
||||
break;
|
||||
case UMP_CC_BANK_SELECT_LSB:
|
||||
cc->bank_set = 1;
|
||||
cc->cc_bank_lsb = val;
|
||||
return 0; // skip
|
||||
ret = 0; // skip
|
||||
break;
|
||||
case UMP_CC_DATA_LSB:
|
||||
cc->cc_data_lsb_set = 1;
|
||||
cc->cc_data_lsb = val;
|
||||
return fill_rpn(cc, data, channel, false);
|
||||
ret = fill_rpn(cc, data, channel, false);
|
||||
break;
|
||||
default:
|
||||
data->cc.status = status;
|
||||
data->cc.channel = channel;
|
||||
data->cc.index = index;
|
||||
data->cc.data = upscale_7_to_32bit(event->data.control.value & 0x7f);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
data->cc.status = status;
|
||||
data->cc.channel = channel;
|
||||
data->cc.index = index;
|
||||
data->cc.data = upscale_7_to_32bit(event->data.control.value & 0x7f);
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* convert one-parameter control event to MIDI 2.0 UMP */
|
||||
|
||||
@@ -216,9 +216,16 @@ static int snd_find_free_minor(int type, struct snd_card *card, int dev)
|
||||
case SNDRV_DEVICE_TYPE_RAWMIDI:
|
||||
case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
|
||||
case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
|
||||
if (snd_BUG_ON(!card))
|
||||
return -EINVAL;
|
||||
minor = SNDRV_MINOR(card->number, type + dev);
|
||||
break;
|
||||
case SNDRV_DEVICE_TYPE_COMPRESS:
|
||||
if (snd_BUG_ON(!card))
|
||||
return -EINVAL;
|
||||
if (dev < 0 ||
|
||||
dev >= SNDRV_MINOR_HWDEP - SNDRV_MINOR_COMPRESS)
|
||||
return -EINVAL;
|
||||
minor = SNDRV_MINOR(card->number, type + dev);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -129,6 +129,9 @@ static LIST_HEAD(snd_timer_list);
|
||||
/* list of slave instances */
|
||||
static LIST_HEAD(snd_timer_slave_list);
|
||||
|
||||
/* list of open master instances that can accept slave links */
|
||||
static LIST_HEAD(snd_timer_master_list);
|
||||
|
||||
/* lock for slave active lists */
|
||||
static DEFINE_SPINLOCK(slave_active_lock);
|
||||
|
||||
@@ -161,6 +164,7 @@ struct snd_timer_instance *snd_timer_instance_new(const char *owner)
|
||||
}
|
||||
INIT_LIST_HEAD(&timeri->open_list);
|
||||
INIT_LIST_HEAD(&timeri->active_list);
|
||||
INIT_LIST_HEAD(&timeri->master_list);
|
||||
INIT_LIST_HEAD(&timeri->ack_list);
|
||||
INIT_LIST_HEAD(&timeri->slave_list_head);
|
||||
INIT_LIST_HEAD(&timeri->slave_active_head);
|
||||
@@ -245,6 +249,12 @@ static int check_matching_master_slave(struct snd_timer_instance *master,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool snd_timer_has_slave_key(const struct snd_timer_instance *timeri)
|
||||
{
|
||||
return !(timeri->flags & SNDRV_TIMER_IFLG_SLAVE) &&
|
||||
timeri->slave_class > SNDRV_TIMER_SCLASS_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* look for a master instance matching with the slave id of the given slave.
|
||||
* when found, relink the open_link of the slave.
|
||||
@@ -253,19 +263,15 @@ static int check_matching_master_slave(struct snd_timer_instance *master,
|
||||
*/
|
||||
static int snd_timer_check_slave(struct snd_timer_instance *slave)
|
||||
{
|
||||
struct snd_timer *timer;
|
||||
struct snd_timer_instance *master;
|
||||
int err = 0;
|
||||
|
||||
/* FIXME: it's really dumb to look up all entries.. */
|
||||
list_for_each_entry(timer, &snd_timer_list, device_list) {
|
||||
list_for_each_entry(master, &timer->open_list_head, open_list) {
|
||||
err = check_matching_master_slave(master, slave);
|
||||
if (err != 0) /* match found or error */
|
||||
goto out;
|
||||
}
|
||||
list_for_each_entry(master, &snd_timer_master_list, master_list) {
|
||||
err = check_matching_master_slave(master, slave);
|
||||
if (err != 0) /* match found or error */
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
out:
|
||||
return err < 0 ? err : 0;
|
||||
}
|
||||
|
||||
@@ -377,6 +383,8 @@ int snd_timer_open(struct snd_timer_instance *timeri,
|
||||
timeri->slave_id = slave_id;
|
||||
|
||||
list_add_tail(&timeri->open_list, &timer->open_list_head);
|
||||
if (snd_timer_has_slave_key(timeri))
|
||||
list_add_tail(&timeri->master_list, &snd_timer_master_list);
|
||||
timer->num_instances++;
|
||||
err = snd_timer_check_master(timeri);
|
||||
list_added:
|
||||
@@ -431,6 +439,9 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
|
||||
num_slaves--;
|
||||
}
|
||||
|
||||
if (!list_empty(&timeri->master_list))
|
||||
list_del_init(&timeri->master_list);
|
||||
|
||||
/* force to stop the timer */
|
||||
snd_timer_stop(timeri);
|
||||
|
||||
|
||||
@@ -151,10 +151,13 @@ efw_transaction(struct snd_efw *efw, unsigned int category,
|
||||
(be32_to_cpu(header->category) != category) ||
|
||||
(be32_to_cpu(header->command) != command) ||
|
||||
(be32_to_cpu(header->status) != EFR_STATUS_OK)) {
|
||||
u32 st = be32_to_cpu(header->status);
|
||||
|
||||
dev_err(&efw->unit->device, "EFW command failed [%u/%u]: %s\n",
|
||||
be32_to_cpu(header->category),
|
||||
be32_to_cpu(header->command),
|
||||
efr_status_names[be32_to_cpu(header->status)]);
|
||||
st < ARRAY_SIZE(efr_status_names) ?
|
||||
efr_status_names[st] : "unknown");
|
||||
err = -EIO;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ struct ad198x_spec {
|
||||
|
||||
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
|
||||
int num_smux_conns;
|
||||
|
||||
unsigned int gpio_data;
|
||||
};
|
||||
|
||||
|
||||
@@ -934,9 +936,9 @@ static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
|
||||
|
||||
if (spec->eapd_nid)
|
||||
ad_vmaster_eapd_hook(private_data, enabled);
|
||||
snd_hda_codec_write_cache(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DATA,
|
||||
enabled ? 0x00 : 0x02);
|
||||
spec->gpio_data = enabled ? 0x00 : 0x02;
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DATA, spec->gpio_data);
|
||||
}
|
||||
|
||||
static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
|
||||
@@ -948,12 +950,7 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
|
||||
case HDA_FIXUP_ACT_PRE_PROBE:
|
||||
spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
|
||||
spec->gen.own_eapd_ctl = 1;
|
||||
snd_hda_codec_write_cache(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_MASK, 0x02);
|
||||
snd_hda_codec_write_cache(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DIRECTION, 0x02);
|
||||
snd_hda_codec_write_cache(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DATA, 0x02);
|
||||
spec->gpio_data = 0x02;
|
||||
break;
|
||||
case HDA_FIXUP_ACT_PROBE:
|
||||
if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
|
||||
@@ -961,6 +958,9 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
|
||||
else
|
||||
spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
|
||||
break;
|
||||
case HDA_FIXUP_ACT_INIT:
|
||||
snd_hda_codec_set_gpio(codec, 0x02, 0x02, spec->gpio_data, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3755,22 +3755,12 @@ static void ca0132_gpio_setup(struct hda_codec *codec)
|
||||
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DIRECTION, 0x07);
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_MASK, 0x07);
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DATA, 0x04);
|
||||
snd_hda_codec_set_gpio(codec, 0x07, 0x07, 0x04, 0);
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DATA, 0x06);
|
||||
break;
|
||||
case QUIRK_R3DI:
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DIRECTION, 0x1E);
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_MASK, 0x1F);
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DATA, 0x0C);
|
||||
snd_hda_codec_set_gpio(codec, 0x1F, 0x1E, 0x0C, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -264,14 +264,9 @@ static int cs_init(struct hda_codec *codec)
|
||||
|
||||
snd_hda_gen_init(codec);
|
||||
|
||||
if (spec->gpio_mask) {
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
|
||||
spec->gpio_mask);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
|
||||
spec->gpio_dir);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
|
||||
spec->gpio_data);
|
||||
}
|
||||
if (spec->gpio_mask)
|
||||
snd_hda_codec_set_gpio(codec, spec->gpio_mask, spec->gpio_dir,
|
||||
spec->gpio_data, 0);
|
||||
|
||||
if (spec->vendor_nid == CS420X_VENDOR_NID) {
|
||||
init_input_coef(codec);
|
||||
|
||||
@@ -442,14 +442,9 @@ static int cs421x_init(struct hda_codec *codec)
|
||||
|
||||
snd_hda_gen_init(codec);
|
||||
|
||||
if (spec->gpio_mask) {
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
|
||||
spec->gpio_mask);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
|
||||
spec->gpio_dir);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
|
||||
spec->gpio_data);
|
||||
}
|
||||
if (spec->gpio_mask)
|
||||
snd_hda_codec_set_gpio(codec, spec->gpio_mask, spec->gpio_dir,
|
||||
spec->gpio_data, 0);
|
||||
|
||||
cs4210_spdif_automute(codec, NULL);
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ static int cs8409_i2c_bulk_read(struct sub_codec *scodec, struct cs8409_i2c_para
|
||||
return 0;
|
||||
|
||||
error:
|
||||
codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr);
|
||||
codec_err(codec, "I2C Bulk Read Failed 0x%02x\n", scodec->addr);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -1042,14 +1042,9 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
|
||||
struct cs8409_spec *spec = codec->spec;
|
||||
struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
|
||||
|
||||
if (spec->gpio_mask) {
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_MASK,
|
||||
spec->gpio_mask);
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DIRECTION,
|
||||
spec->gpio_dir);
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA,
|
||||
spec->gpio_data);
|
||||
}
|
||||
if (spec->gpio_mask)
|
||||
snd_hda_codec_set_gpio(codec, spec->gpio_mask, spec->gpio_dir,
|
||||
spec->gpio_data, 0);
|
||||
|
||||
for (; seq->nid; seq++)
|
||||
cs8409_vendor_coef_set(codec, seq->cir, seq->coeff);
|
||||
@@ -1442,14 +1437,9 @@ static void dolphin_hw_init(struct hda_codec *codec)
|
||||
struct sub_codec *cs42l42;
|
||||
int i;
|
||||
|
||||
if (spec->gpio_mask) {
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_MASK,
|
||||
spec->gpio_mask);
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DIRECTION,
|
||||
spec->gpio_dir);
|
||||
snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA,
|
||||
spec->gpio_data);
|
||||
}
|
||||
if (spec->gpio_mask)
|
||||
snd_hda_codec_set_gpio(codec, spec->gpio_mask, spec->gpio_dir,
|
||||
spec->gpio_data, 0);
|
||||
|
||||
for (; seq->nid; seq++)
|
||||
cs8409_vendor_coef_set(codec, seq->cir, seq->coeff);
|
||||
|
||||
@@ -39,13 +39,6 @@ static int cmedia_probe(struct hda_codec *codec, const struct hda_device_id *id)
|
||||
spec->out_vol_mask = (1ULL << 0x10);
|
||||
}
|
||||
|
||||
err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
err = snd_hda_gen_parse_auto_config(codec, cfg);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
@@ -154,14 +154,8 @@ static void cxt_init_gpio_led(struct hda_codec *codec)
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
|
||||
|
||||
if (mask) {
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
|
||||
mask);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
|
||||
mask);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
|
||||
spec->gpio_led);
|
||||
}
|
||||
if (mask)
|
||||
snd_hda_codec_set_gpio(codec, mask, mask, spec->gpio_led, 0);
|
||||
}
|
||||
|
||||
static void cx_fixup_headset_recog(struct hda_codec *codec)
|
||||
@@ -775,9 +769,7 @@ static void cxt_setup_gpio_unmute(struct hda_codec *codec,
|
||||
{
|
||||
if (gpio_mute_mask) {
|
||||
// set gpio data to 0.
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, gpio_mute_mask);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, gpio_mute_mask);
|
||||
snd_hda_codec_set_gpio(codec, gpio_mute_mask, gpio_mute_mask, 0, 0);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_STICKY_MASK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,7 +863,7 @@ static void sync_power_state_change(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
if (nid) {
|
||||
msleep(10);
|
||||
snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
|
||||
snd_hda_codec_write_sync(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
|
||||
}
|
||||
}
|
||||
|
||||
snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
|
||||
snd_hda_codec_write_sync(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
|
||||
snd_hda_codec_set_power_to_all(codec, fg, power_state);
|
||||
}
|
||||
|
||||
|
||||
@@ -1004,13 +1004,6 @@ static int alc269_resume(struct hda_codec *codec)
|
||||
snd_hda_regmap_sync(codec);
|
||||
hda_call_check_power_status(codec, 0x01);
|
||||
|
||||
/* on some machine, the BIOS will clear the codec gpio data when enter
|
||||
* suspend, and won't restore the data after resume, so we restore it
|
||||
* in the driver.
|
||||
*/
|
||||
if (spec->gpio_data)
|
||||
alc_write_gpio_data(codec);
|
||||
|
||||
if (spec->has_alc5505_dsp)
|
||||
alc5505_dsp_resume(codec);
|
||||
|
||||
@@ -2296,9 +2289,9 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec,
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
|
||||
alc255_set_default_jack_type(codec);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
alc_fixup_headset_mode(codec, fix, action);
|
||||
}
|
||||
}
|
||||
|
||||
static void alc288_update_headset_jack_cb(struct hda_codec *codec,
|
||||
@@ -3661,22 +3654,11 @@ static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo,
|
||||
struct snd_pcm_substream *substream,
|
||||
int action)
|
||||
{
|
||||
static const struct coef_fw dis_coefs[] = {
|
||||
WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203),
|
||||
WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023),
|
||||
}; /* Disable AMP silence detection */
|
||||
static const struct coef_fw en_coefs[] = {
|
||||
WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203),
|
||||
WRITE_COEF(0x28, 0x0084), WRITE_COEF(0x29, 0xb023),
|
||||
}; /* Enable AMP silence detection */
|
||||
|
||||
switch (action) {
|
||||
case HDA_GEN_PCM_ACT_OPEN:
|
||||
alc_process_coef_fw(codec, dis_coefs);
|
||||
alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */
|
||||
break;
|
||||
case HDA_GEN_PCM_ACT_CLOSE:
|
||||
alc_process_coef_fw(codec, en_coefs);
|
||||
alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
|
||||
break;
|
||||
}
|
||||
@@ -3699,10 +3681,15 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
|
||||
WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC301),
|
||||
WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023),
|
||||
};
|
||||
static const struct coef_fw dis_coefs[] = {
|
||||
WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC203),
|
||||
WRITE_COEF(0x28, 0x0004), WRITE_COEF(0x29, 0xb023),
|
||||
}; /* Disable AMP silence detection */
|
||||
|
||||
if (action != HDA_FIXUP_ACT_PRE_PROBE)
|
||||
return;
|
||||
alc_update_coef_idx(codec, 0x10, 1<<11, 1<<11);
|
||||
alc_process_coef_fw(codec, dis_coefs);
|
||||
alc_process_coef_fw(codec, coefs);
|
||||
spec->power_hook = alc287_s4_power_gpio3_default;
|
||||
spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
|
||||
@@ -6639,10 +6626,10 @@ static const struct hda_fixup alc269_fixups[] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc288_fixup_surface_swap_dacs,
|
||||
},
|
||||
[ALC233_FIXUP_LENOVO_GPIO2_MIC_HOTKEY] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc233_fixup_lenovo_gpio2_mic_hotkey,
|
||||
},
|
||||
[ALC233_FIXUP_LENOVO_GPIO2_MIC_HOTKEY] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc233_fixup_lenovo_gpio2_mic_hotkey,
|
||||
},
|
||||
[ALC245_FIXUP_BASS_HP_DAC] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
/* Borrow the DAC routing selected for those Thinkpads */
|
||||
@@ -6718,6 +6705,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1025, 0x1539, "Acer Nitro 5 AN515-57", ALC2XX_FIXUP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
|
||||
SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED),
|
||||
SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED),
|
||||
@@ -6954,6 +6942,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
|
||||
HDA_CODEC_QUIRK(0x103c, 0x885b, "HP Spectre x360 14-ea", ALC245_FIXUP_HP_X360_AMP),
|
||||
SND_PCI_QUIRK(0x103c, 0x8862, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x103c, 0x8863, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x103c, 0x886d, "HP ZBook Fury 17.3 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
@@ -7198,6 +7187,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x8e60, "HP OmniBook 7 Laptop 16-bh0xxx", ALC245_FIXUP_CS35L41_I2C_2_MUTE_LED),
|
||||
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, 0x8e75, "HP Trekker G7JC", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8e8a, "HP NexusX", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8e9c, "HP 16 Clipper OmniBook X X360", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8e9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
@@ -7219,8 +7209,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x8ee4, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||
SND_PCI_QUIRK(0x103c, 0x8ee5, "HP Bantie A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||
SND_PCI_QUIRK(0x103c, 0x8ee7, "HP Abe A6U", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f07, "HP Agusta G7KX", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
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, 0x8f2d, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8f2e, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
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),
|
||||
@@ -7365,6 +7358,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1043, 0x31e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x3391, "ASUS PM3606CKA", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x3601, "ASUS PM5406CGA", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x3611, "ASUS PM5606CGA", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x3701, "ASUS P5406CCA", ALC245_FIXUP_CS35L41_SPI_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x3711, "ASUS P5606CCA", ALC245_FIXUP_CS35L41_SPI_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
|
||||
SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
|
||||
SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
|
||||
@@ -7605,6 +7602,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
|
||||
HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3811, "Legion S7 15IMH05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS),
|
||||
|
||||
@@ -255,6 +255,17 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
|
||||
alc_fixup_headset_mode(codec, fix, action);
|
||||
}
|
||||
|
||||
static void alc662_fixup_csl_amp(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
if (action == HDA_FIXUP_ACT_INIT) {
|
||||
/* need to toggle GPIO to enable the amp */
|
||||
snd_hda_codec_set_gpio(codec, 0x03, 0x03, 0x03, 0);
|
||||
msleep(100);
|
||||
snd_hda_codec_set_gpio(codec, 0x03, 0x03, 0x00, 0);
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
ALC662_FIXUP_ASPIRE,
|
||||
ALC662_FIXUP_LED_GPIO1,
|
||||
@@ -313,6 +324,7 @@ enum {
|
||||
ALC897_FIXUP_HEADSET_MIC_PIN2,
|
||||
ALC897_FIXUP_UNIS_H3C_X500S,
|
||||
ALC897_FIXUP_HEADSET_MIC_PIN3,
|
||||
ALC662_FIXUP_CSL_GPIO,
|
||||
};
|
||||
|
||||
static const struct hda_fixup alc662_fixups[] = {
|
||||
@@ -766,11 +778,16 @@ static const struct hda_fixup alc662_fixups[] = {
|
||||
{ }
|
||||
},
|
||||
},
|
||||
[ALC662_FIXUP_CSL_GPIO] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc662_fixup_csl_amp,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hda_quirk alc662_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
|
||||
SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3),
|
||||
SND_PCI_QUIRK(0x1022, 0xc950, "CSL Unity BF24B", ALC662_FIXUP_CSL_GPIO),
|
||||
SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
|
||||
|
||||
@@ -99,15 +99,6 @@ void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(alc_setup_gpio, "SND_HDA_CODEC_REALTEK");
|
||||
|
||||
void alc_write_gpio_data(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
|
||||
spec->gpio_data);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(alc_write_gpio_data, "SND_HDA_CODEC_REALTEK");
|
||||
|
||||
void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
|
||||
bool on)
|
||||
{
|
||||
@@ -119,26 +110,22 @@ void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
|
||||
else
|
||||
spec->gpio_data &= ~mask;
|
||||
if (oldval != spec->gpio_data)
|
||||
alc_write_gpio_data(codec);
|
||||
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
|
||||
spec->gpio_data);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(alc_update_gpio_data, "SND_HDA_CODEC_REALTEK");
|
||||
|
||||
void alc_write_gpio(struct hda_codec *codec)
|
||||
static void alc_write_gpio(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
if (!spec->gpio_mask)
|
||||
return;
|
||||
|
||||
snd_hda_codec_write(codec, codec->core.afg, 0,
|
||||
AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
|
||||
snd_hda_codec_write(codec, codec->core.afg, 0,
|
||||
AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
|
||||
if (spec->gpio_write_delay)
|
||||
msleep(1);
|
||||
alc_write_gpio_data(codec);
|
||||
snd_hda_codec_set_gpio(codec, spec->gpio_mask, spec->gpio_dir,
|
||||
spec->gpio_data,
|
||||
spec->gpio_write_delay ? 1 : 0);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(alc_write_gpio, "SND_HDA_CODEC_REALTEK");
|
||||
|
||||
void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask)
|
||||
{
|
||||
@@ -411,9 +398,8 @@ void alc_headset_mic_no_shutup(struct hda_codec *codec)
|
||||
return;
|
||||
|
||||
snd_array_for_each(&codec->init_pins, i, pin) {
|
||||
/* use read here for syncing after issuing each verb */
|
||||
if (pin->nid != mic_pin)
|
||||
snd_hda_codec_read(codec, pin->nid, 0,
|
||||
snd_hda_codec_write_sync(codec, pin->nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
|
||||
}
|
||||
|
||||
@@ -2164,8 +2150,7 @@ void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
|
||||
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
|
||||
struct alc_spec *spec = codec->spec;
|
||||
spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
|
||||
}
|
||||
else
|
||||
} else
|
||||
alc_fixup_headset_mode(codec, fix, action);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(alc_fixup_headset_mode_no_hp_mic, "SND_HDA_CODEC_REALTEK");
|
||||
|
||||
@@ -168,10 +168,8 @@ void alc_process_coef_fw(struct hda_codec *codec, const struct coef_fw *fw);
|
||||
* GPIO helpers
|
||||
*/
|
||||
void alc_setup_gpio(struct hda_codec *codec, unsigned int mask);
|
||||
void alc_write_gpio_data(struct hda_codec *codec);
|
||||
void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
|
||||
bool on);
|
||||
void alc_write_gpio(struct hda_codec *codec);
|
||||
|
||||
/* common GPIO fixups */
|
||||
void alc_fixup_gpio(struct hda_codec *codec, int action, unsigned int mask);
|
||||
|
||||
@@ -36,6 +36,32 @@ struct senary_spec {
|
||||
unsigned int gpio_mic_led_mask;
|
||||
};
|
||||
|
||||
enum {
|
||||
SENARY_FIXUP_PINCFG_DEFAULT,
|
||||
};
|
||||
|
||||
static const struct hda_pintbl senary_pincfg_default[] = {
|
||||
{ 0x16, 0x02211020 }, /* Headphone */
|
||||
{ 0x17, 0x40f001f0 }, /* Not used */
|
||||
{ 0x18, 0x05a1904d }, /* Mic */
|
||||
{ 0x19, 0x02a1104e }, /* Headset Mic */
|
||||
{ 0x1a, 0x01819030 }, /* Line-in */
|
||||
{ 0x1d, 0x01014010 }, /* Line-out */
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct hda_fixup senary_fixups[] = {
|
||||
[SENARY_FIXUP_PINCFG_DEFAULT] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = senary_pincfg_default,
|
||||
},
|
||||
};
|
||||
|
||||
/* Quirk table for specific machines can be added here */
|
||||
static const struct hda_quirk sn6186_fixups[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SND_HDA_INPUT_BEEP
|
||||
/* additional beep mixers; private_value will be overwritten */
|
||||
static const struct snd_kcontrol_new senary_beep_mixer[] = {
|
||||
@@ -50,7 +76,6 @@ static int set_beep_amp(struct senary_spec *spec, hda_nid_t nid,
|
||||
unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
|
||||
int i;
|
||||
|
||||
spec->gen.beep_nid = nid;
|
||||
for (i = 0; i < ARRAY_SIZE(senary_beep_mixer); i++) {
|
||||
knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
|
||||
&senary_beep_mixer[i]);
|
||||
@@ -58,6 +83,8 @@ static int set_beep_amp(struct senary_spec *spec, hda_nid_t nid,
|
||||
return -ENOMEM;
|
||||
knew->private_value = beep_amp;
|
||||
}
|
||||
|
||||
spec->gen.beep_nid = nid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -93,16 +120,28 @@ static void senary_auto_parse_eapd(struct hda_codec *codec)
|
||||
}
|
||||
}
|
||||
|
||||
/* Hardware specific initialization verbs */
|
||||
static void senary_init_verb(struct hda_codec *codec)
|
||||
{
|
||||
/* Vendor specific init sequence */
|
||||
snd_hda_codec_write(codec, 0x1b, 0x0, 0x05a, 0xaa);
|
||||
snd_hda_codec_write(codec, 0x1b, 0x0, 0x059, 0x48);
|
||||
snd_hda_codec_write(codec, 0x1b, 0x0, 0x01b, 0x00);
|
||||
snd_hda_codec_write(codec, 0x1b, 0x0, 0x01c, 0x00);
|
||||
|
||||
/* Override pin caps for headset mic */
|
||||
snd_hda_override_pin_caps(codec, 0x19, 0x2124);
|
||||
}
|
||||
|
||||
static void senary_auto_turn_eapd(struct hda_codec *codec, int num_pins,
|
||||
const hda_nid_t *pins, bool on)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
|
||||
snd_hda_codec_write(codec, pins[i], 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE,
|
||||
on ? 0x02 : 0);
|
||||
snd_hda_codec_write(codec, pins[i], 0,
|
||||
AC_VERB_SET_EAPD_BTLENABLE,
|
||||
on ? 0x02 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,14 +159,8 @@ static void senary_init_gpio_led(struct hda_codec *codec)
|
||||
struct senary_spec *spec = codec->spec;
|
||||
unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
|
||||
|
||||
if (mask) {
|
||||
snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_MASK,
|
||||
mask);
|
||||
snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DIRECTION,
|
||||
mask);
|
||||
snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA,
|
||||
spec->gpio_led);
|
||||
}
|
||||
if (mask)
|
||||
snd_hda_codec_set_gpio(codec, mask, mask, spec->gpio_led, 0);
|
||||
}
|
||||
|
||||
static int senary_init(struct hda_codec *codec)
|
||||
@@ -136,6 +169,7 @@ static int senary_init(struct hda_codec *codec)
|
||||
|
||||
snd_hda_gen_init(codec);
|
||||
senary_init_gpio_led(codec);
|
||||
senary_init_verb(codec);
|
||||
if (!spec->dynamic_eapd)
|
||||
senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
|
||||
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
|
||||
@@ -181,11 +215,30 @@ static int senary_probe(struct hda_codec *codec, const struct hda_device_id *id)
|
||||
senary_auto_parse_eapd(codec);
|
||||
spec->gen.own_eapd_ctl = 1;
|
||||
|
||||
if (!spec->gen.vmaster_mute.hook)
|
||||
spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook;
|
||||
/* Setup fixups based on codec vendor ID */
|
||||
switch (codec->core.vendor_id) {
|
||||
case 0x1fa86186:
|
||||
codec->pin_amp_workaround = 1;
|
||||
spec->gen.mixer_nid = 0x15;
|
||||
snd_hda_pick_fixup(codec, NULL, sn6186_fixups, senary_fixups);
|
||||
|
||||
/* If no specific quirk found, apply the default pin configuration */
|
||||
if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET)
|
||||
codec->fixup_id = SENARY_FIXUP_PINCFG_DEFAULT;
|
||||
break;
|
||||
default:
|
||||
snd_hda_pick_fixup(codec, NULL, sn6186_fixups, senary_fixups);
|
||||
break;
|
||||
}
|
||||
|
||||
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
|
||||
|
||||
/* Run hardware init verbs once during probe */
|
||||
senary_init_verb(codec);
|
||||
|
||||
if (!spec->gen.vmaster_mute.hook)
|
||||
spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook;
|
||||
|
||||
err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
|
||||
spec->parse_flags);
|
||||
if (err < 0)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config SND_HDA_CIRRUS_SCODEC
|
||||
tristate
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@ static const struct cs35l41_config cs35l41_config_table[] = {
|
||||
{ "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
|
||||
{ "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
|
||||
{ "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 },
|
||||
/*
|
||||
* Device 103C8B63 has _DSD with valid reset-gpios and cs-gpios, however the
|
||||
* boost type is incorrectly set to Internal. Override to External Boost.
|
||||
*/
|
||||
{ "103C8B63", 4, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, -1, -1, -1, 0, 0, 0 },
|
||||
{ "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
|
||||
{ "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
|
||||
{ "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
|
||||
@@ -475,6 +480,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
|
||||
{ "CSC3551", "103C8A30", generic_dsd_config },
|
||||
{ "CSC3551", "103C8A31", generic_dsd_config },
|
||||
{ "CSC3551", "103C8A6E", generic_dsd_config },
|
||||
{ "CSC3551", "103C8B63", generic_dsd_config },
|
||||
{ "CSC3551", "103C8BB3", generic_dsd_config },
|
||||
{ "CSC3551", "103C8BB4", generic_dsd_config },
|
||||
{ "CSC3551", "103C8BDD", generic_dsd_config },
|
||||
|
||||
@@ -309,15 +309,7 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
|
||||
/* Configure GPIOx as CMOS */
|
||||
snd_hda_codec_write(codec, fg, 0, 0x7e7, 0);
|
||||
|
||||
snd_hda_codec_write(codec, fg, 0,
|
||||
AC_VERB_SET_GPIO_MASK, gpiomask);
|
||||
snd_hda_codec_read(codec, fg, 0,
|
||||
AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
|
||||
|
||||
msleep(1);
|
||||
|
||||
snd_hda_codec_read(codec, fg, 0,
|
||||
AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
|
||||
snd_hda_codec_set_gpio(codec, gpiomask, gpiodir, gpiostate, 1);
|
||||
}
|
||||
|
||||
/* hook for controlling mic-mute LED GPIO */
|
||||
|
||||
@@ -606,9 +606,8 @@ void snd_hda_shutup_pins(struct hda_codec *codec)
|
||||
if (codec->bus->shutdown)
|
||||
return;
|
||||
snd_array_for_each(&codec->init_pins, i, pin) {
|
||||
/* use read here for syncing after issuing each verb */
|
||||
snd_hda_codec_read(codec, pin->nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
|
||||
snd_hda_codec_write_sync(codec, pin->nid, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
|
||||
}
|
||||
codec->pins_shutup = 1;
|
||||
}
|
||||
@@ -2529,7 +2528,10 @@ EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_assign);
|
||||
static int spdif_share_sw_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct hda_multi_out *mout = (void *)kcontrol->private_value;
|
||||
|
||||
guard(mutex)(&codec->spdif_mutex);
|
||||
ucontrol->value.integer.value[0] = mout->share_spdif;
|
||||
return 0;
|
||||
}
|
||||
@@ -2537,9 +2539,15 @@ static int spdif_share_sw_get(struct snd_kcontrol *kcontrol,
|
||||
static int spdif_share_sw_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
|
||||
mout->share_spdif = !!ucontrol->value.integer.value[0];
|
||||
return 0;
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct hda_multi_out *mout = (void *)kcontrol->private_value;
|
||||
bool val = !!ucontrol->value.integer.value[0];
|
||||
int change;
|
||||
|
||||
guard(mutex)(&codec->spdif_mutex);
|
||||
change = mout->share_spdif != val;
|
||||
mout->share_spdif = val;
|
||||
return change;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new spdif_share_sw = {
|
||||
@@ -2550,6 +2558,14 @@ static const struct snd_kcontrol_new spdif_share_sw = {
|
||||
.put = spdif_share_sw_put,
|
||||
};
|
||||
|
||||
static void notify_spdif_share_sw(struct hda_codec *codec,
|
||||
struct hda_multi_out *mout)
|
||||
{
|
||||
if (mout->share_spdif_kctl)
|
||||
snd_ctl_notify_one(codec->card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
mout->share_spdif_kctl, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_create_spdif_share_sw - create Default PCM switch
|
||||
* @codec: the HDA codec
|
||||
@@ -2559,15 +2575,24 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
|
||||
struct hda_multi_out *mout)
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
int err;
|
||||
|
||||
if (!mout->dig_out_nid)
|
||||
return 0;
|
||||
|
||||
kctl = snd_ctl_new1(&spdif_share_sw, mout);
|
||||
kctl = snd_ctl_new1(&spdif_share_sw, codec);
|
||||
if (!kctl)
|
||||
return -ENOMEM;
|
||||
/* ATTENTION: here mout is passed as private_data, instead of codec */
|
||||
return snd_hda_ctl_add(codec, mout->dig_out_nid, kctl);
|
||||
/* snd_ctl_new1() stores @codec in private_data; stash @mout in
|
||||
* private_value for the share-switch callbacks and cache the
|
||||
* assigned control for forced-disable notifications.
|
||||
*/
|
||||
kctl->private_value = (unsigned long)mout;
|
||||
err = snd_hda_ctl_add(codec, mout->dig_out_nid, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
mout->share_spdif_kctl = kctl;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw);
|
||||
|
||||
@@ -2768,9 +2793,9 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
|
||||
if (codec->power_filter)
|
||||
state = codec->power_filter(codec, fg, state);
|
||||
if (state == power_state || power_state != AC_PWRST_D3)
|
||||
snd_hda_codec_read(codec, fg, flags,
|
||||
AC_VERB_SET_POWER_STATE,
|
||||
state);
|
||||
snd_hda_codec_write_sync(codec, fg, flags,
|
||||
AC_VERB_SET_POWER_STATE,
|
||||
state);
|
||||
snd_hda_codec_set_power_to_all(codec, fg, power_state);
|
||||
}
|
||||
state = snd_hda_sync_power_state(codec, fg, power_state);
|
||||
@@ -3701,6 +3726,8 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
|
||||
struct hda_pcm_stream *hinfo)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
bool notify_share_sw = false;
|
||||
|
||||
runtime->hw.channels_max = mout->max_channels;
|
||||
if (mout->dig_out_nid) {
|
||||
if (!mout->analog_rates) {
|
||||
@@ -3729,10 +3756,12 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
|
||||
hinfo->maxbps = mout->spdif_maxbps;
|
||||
} else {
|
||||
mout->share_spdif = 0;
|
||||
/* FIXME: need notify? */
|
||||
notify_share_sw = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (notify_share_sw)
|
||||
notify_spdif_share_sw(codec, mout);
|
||||
return snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
|
||||
}
|
||||
@@ -4023,6 +4052,35 @@ void snd_hda_bus_reset_codecs(struct hda_bus *bus)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_codec_set_gpio - Set up GPIO bits for AFG
|
||||
* @codec: the HDA codec
|
||||
* @mask: GPIO bitmask
|
||||
* @dir: GPIO direction bits
|
||||
* @data: GPIO data bits
|
||||
* @delay: the delay in msec before writing GPIO data bits
|
||||
*/
|
||||
void snd_hda_codec_set_gpio(struct hda_codec *codec, unsigned int mask,
|
||||
unsigned int dir, unsigned int data,
|
||||
unsigned int delay)
|
||||
{
|
||||
snd_hda_codec_write(codec, codec->core.afg, 0,
|
||||
AC_VERB_SET_GPIO_MASK, mask);
|
||||
if (delay) {
|
||||
snd_hda_codec_write_sync(codec, codec->core.afg, 0,
|
||||
AC_VERB_SET_GPIO_DIRECTION, dir);
|
||||
msleep(delay);
|
||||
snd_hda_codec_write_sync(codec, codec->core.afg, 0,
|
||||
AC_VERB_SET_GPIO_DATA, data);
|
||||
} else {
|
||||
snd_hda_codec_write(codec, codec->core.afg, 0,
|
||||
AC_VERB_SET_GPIO_DIRECTION, dir);
|
||||
snd_hda_codec_write(codec, codec->core.afg, 0,
|
||||
AC_VERB_SET_GPIO_DATA, data);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_codec_set_gpio);
|
||||
|
||||
/**
|
||||
* snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer
|
||||
* @pcm: PCM caps bits
|
||||
|
||||
@@ -221,6 +221,7 @@ struct hda_multi_out {
|
||||
unsigned int spdif_rates;
|
||||
unsigned int spdif_maxbps;
|
||||
u64 spdif_formats;
|
||||
struct snd_kcontrol *share_spdif_kctl; /* cached shared SPDIF switch */
|
||||
};
|
||||
|
||||
int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
|
||||
|
||||
@@ -640,41 +640,78 @@ static void print_gpio(struct snd_info_buffer *buffer,
|
||||
{
|
||||
unsigned int gpio =
|
||||
param_read(codec, codec->core.afg, AC_PAR_GPIO_CAP);
|
||||
unsigned int enable, direction, wake, unsol, sticky, data;
|
||||
int i, max;
|
||||
int i, gpio_max, gpo_max, gpi_max;
|
||||
|
||||
gpio_max = gpio & AC_GPIO_IO_COUNT;
|
||||
gpo_max = (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT;
|
||||
gpi_max = (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT;
|
||||
|
||||
snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, "
|
||||
"unsolicited=%d, wake=%d\n",
|
||||
gpio & AC_GPIO_IO_COUNT,
|
||||
(gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT,
|
||||
(gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT,
|
||||
gpio_max, gpo_max, gpi_max,
|
||||
(gpio & AC_GPIO_UNSOLICITED) ? 1 : 0,
|
||||
(gpio & AC_GPIO_WAKE) ? 1 : 0);
|
||||
max = gpio & AC_GPIO_IO_COUNT;
|
||||
if (!max || max > 8)
|
||||
return;
|
||||
enable = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_MASK, 0);
|
||||
direction = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_DIRECTION, 0);
|
||||
wake = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_WAKE_MASK, 0);
|
||||
unsol = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK, 0);
|
||||
sticky = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_STICKY_MASK, 0);
|
||||
data = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_DATA, 0);
|
||||
for (i = 0; i < max; ++i)
|
||||
snd_iprintf(buffer,
|
||||
" IO[%d]: enable=%d, dir=%d, wake=%d, "
|
||||
"sticky=%d, data=%d, unsol=%d\n", i,
|
||||
(enable & (1<<i)) ? 1 : 0,
|
||||
(direction & (1<<i)) ? 1 : 0,
|
||||
(wake & (1<<i)) ? 1 : 0,
|
||||
(sticky & (1<<i)) ? 1 : 0,
|
||||
(data & (1<<i)) ? 1 : 0,
|
||||
(unsol & (1<<i)) ? 1 : 0);
|
||||
/* FIXME: add GPO and GPI pin information */
|
||||
|
||||
if (gpio_max && gpio_max <= 8) {
|
||||
unsigned int enable, direction, wake, unsol, sticky, data;
|
||||
|
||||
enable = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_MASK, 0);
|
||||
direction = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_DIRECTION, 0);
|
||||
wake = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_WAKE_MASK, 0);
|
||||
unsol = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK,
|
||||
0);
|
||||
sticky = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_STICKY_MASK, 0);
|
||||
data = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPIO_DATA, 0);
|
||||
for (i = 0; i < gpio_max; ++i) {
|
||||
snd_iprintf(buffer,
|
||||
" IO[%d]: enable=%d, dir=%d, wake=%d, ",
|
||||
i, (enable & (1 << i)) ? 1 : 0,
|
||||
(direction & (1 << i)) ? 1 : 0,
|
||||
(wake & (1 << i)) ? 1 : 0);
|
||||
snd_iprintf(buffer,
|
||||
"sticky=%d, data=%d, unsol=%d\n",
|
||||
(sticky & (1 << i)) ? 1 : 0,
|
||||
(data & (1 << i)) ? 1 : 0,
|
||||
(unsol & (1 << i)) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (gpo_max && gpo_max <= 8) {
|
||||
unsigned int gpo_data;
|
||||
|
||||
gpo_data = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPO_DATA, 0);
|
||||
for (i = 0; i < gpo_max; ++i)
|
||||
snd_iprintf(buffer, " GPO[%d]: data=%d\n", i,
|
||||
(gpo_data & (1 << i)) ? 1 : 0);
|
||||
}
|
||||
|
||||
if (gpi_max && gpi_max <= 8) {
|
||||
unsigned int wake, unsol, sticky, data;
|
||||
|
||||
wake = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPI_WAKE_MASK, 0);
|
||||
unsol = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPI_UNSOLICITED_RSP_MASK,
|
||||
0);
|
||||
sticky = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPI_STICKY_MASK, 0);
|
||||
data = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_GPI_DATA, 0);
|
||||
for (i = 0; i < gpi_max; ++i)
|
||||
snd_iprintf(buffer, " GPI[%d]: wake=%d, sticky=%d, data=%d, unsol=%d\n",
|
||||
i, (wake & (1 << i)) ? 1 : 0,
|
||||
(sticky & (1 << i)) ? 1 : 0,
|
||||
(data & (1 << i)) ? 1 : 0,
|
||||
(unsol & (1 << i)) ? 1 : 0);
|
||||
}
|
||||
|
||||
print_nid_array(buffer, codec, nid, &codec->mixers);
|
||||
print_nid_array(buffer, codec, nid, &codec->nids);
|
||||
}
|
||||
@@ -940,4 +977,3 @@ int snd_hda_codec_proc_new(struct hda_codec *codec)
|
||||
snprintf(name, sizeof(name), "codec#%d", codec->core.addr);
|
||||
return snd_card_ro_proc_new(codec->card, name, codec, print_codec_info);
|
||||
}
|
||||
|
||||
|
||||
@@ -2436,20 +2436,7 @@ static void azx_remove(struct pci_dev *pci)
|
||||
/* cancel the pending probing work */
|
||||
chip = card->private_data;
|
||||
hda = container_of(chip, struct hda_intel, chip);
|
||||
/* FIXME: below is an ugly workaround.
|
||||
* Both device_release_driver() and driver_probe_device()
|
||||
* take *both* the device's and its parent's lock before
|
||||
* calling the remove() and probe() callbacks. The codec
|
||||
* probe takes the locks of both the codec itself and its
|
||||
* parent, i.e. the PCI controller dev. Meanwhile, when
|
||||
* the PCI controller is unbound, it takes its lock, too
|
||||
* ==> ouch, a deadlock!
|
||||
* As a workaround, we unlock temporarily here the controller
|
||||
* device during cancel_work_sync() call.
|
||||
*/
|
||||
device_unlock(&pci->dev);
|
||||
cancel_delayed_work_sync(&hda->probe_work);
|
||||
device_lock(&pci->dev);
|
||||
|
||||
clear_bit(chip->dev_index, probed_devs);
|
||||
pci_set_drvdata(pci, NULL);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user