sound updates for 4.21
There are no intensive changes in both ALSA and ASoC core parts while rather most of changes are a bunch of driver fixes and updates. A large diff pattern appears in ASoC TI part which now merges both OMAP and DaVinci stuff, but the rest spreads allover the places. Note that this pull request includes also some updates for LED trigger and platform drivers for mute LEDs, appearing in the diffstat as well. Some highlights: ASoC: - Preparatory work for merging the audio-graph and audio-graph-scu cards - A merge of TI OMAP and DaVinci directories, as both product lines get merged together. Also including a few architecture changes as well. - Major cleanups of the Maxim MAX9867 driver - Small fixes for tablets & co with Intel BYT/CHT chips - Lots of rsnd updates as usual - Support for Asahi Kaesi AKM4118, AMD ACP3x, Intel platforms with RT5660, Meson AXG S/PDIF inputs, several Qualcomm IPs and Xilinx I2S controllers HD-audio: - Introduce audio-mute LED trigger for replacing the former hackish dynamic binding - Huawei WMI hotkey and mute LED support - Refactoring of PM code and display power controls - Headset button support in the generic jack code - A few updates for Tegra - Fixups for HP EliteBook and ASUS UX391UA - Lots of updates for Intel ASoC HD-audio, including the improved DSP detection and the fallback binding from ASoC SST to legacy HD-audio controller drivers Others: - Updates for FireWire TASCAM and Fireface devices, some other fixes - A few potential Spectre v1 fixes that are all trivial -----BEGIN PGP SIGNATURE----- iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAlwbbCIOHHRpd2FpQHN1 c2UuZGUACgkQLtJE4w1nLE+RoQ//TNKliUP3bOv4BdnSmUHcCSAP3st96Ror5lC+ RZ103UyjlCsfa7hSPfH7/4WHAjk7wXYdazjA3m2swsxsbcjPMW4uBIBJlegQNM/9 PmNt4y60UgdgMCT/uu10BlEO8GsqBkRpxFYHtUJ3Lq6h9ECa+VDLazNjK9jABItK BVG668/LZp0le94cnJsLICmZ7fwKpAvi58hOsgOJLrPP4gzSGTj1gJXw/yyZ99QC MPLVj1PruXq1l8zfxM+MUuOa7hayafx64bCbftlITPonWfEr7OvBCQ7Vf9HqzJIJ OzEXAclVSc89R7RQT2omPiRKC7AyL85M9PCkpTtXh2D7DGXw9CFj5IDL6eIC4Ip4 sycArLOo6LA8ZYu45zCiY3rfh9Hx0Zn2qHz3qJeQtBrv5XYULuf6ZNwq6xJDEUz/ jxS558wSGHYWAyjv/IaPha1+JD6Us7zkSQgum+/qqnYYnYlDyxXnBatj4HzWZP/M Khuhj+k+Y8UXK1MbRiekVCGIwCHGf3cUv4H7tq+qpEzvJZwTFnOBh7/twVL8gN96 x4ozZogaiaenZwlEZlkzowAMBBYMYb537Y+Y5suxzWGz3HN/Z8raaL8GTkIIB/BO bNprJtPR8GJLfdu8NE++dUR2VuHfMnWat+frXk0eAsWutoviRyB4JLCRppfpgrA/ vDhIreU= =SG61 -----END PGP SIGNATURE----- Merge tag 'sound-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound updates from Takashi Iwai: "There are no intensive changes in both ALSA and ASoC core parts while rather most of changes are a bunch of driver fixes and updates. A large diff pattern appears in ASoC TI part which now merges both OMAP and DaVinci stuff, but the rest spreads allover the places. Note that this pull request includes also some updates for LED trigger and platform drivers for mute LEDs, appearing in the diffstat as well. Some highlights: ASoC: - Preparatory work for merging the audio-graph and audio-graph-scu cards - A merge of TI OMAP and DaVinci directories, as both product lines get merged together. Also including a few architecture changes as well. - Major cleanups of the Maxim MAX9867 driver - Small fixes for tablets & co with Intel BYT/CHT chips - Lots of rsnd updates as usual - Support for Asahi Kaesi AKM4118, AMD ACP3x, Intel platforms with RT5660, Meson AXG S/PDIF inputs, several Qualcomm IPs and Xilinx I2S controllers HD-audio: - Introduce audio-mute LED trigger for replacing the former hackish dynamic binding - Huawei WMI hotkey and mute LED support - Refactoring of PM code and display power controls - Headset button support in the generic jack code - A few updates for Tegra - Fixups for HP EliteBook and ASUS UX391UA - Lots of updates for Intel ASoC HD-audio, including the improved DSP detection and the fallback binding from ASoC SST to legacy HD-audio controller drivers Others: - Updates for FireWire TASCAM and Fireface devices, some other fixes - A few potential Spectre v1 fixes that are all trivial" * tag 'sound-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (280 commits) ALSA: HD-Audio: SKL+: force HDaudio legacy or SKL+ driver selection ALSA: HD-Audio: SKL+: abort probe if DSP is present and Skylake driver selected ALSA: HDA: export process_unsol_events() ALSA: hda/realtek: Enable audio jacks of ASUS UX391UA with ALC294 ALSA: bebob: fix model-id of unit for Apogee Ensemble ALSA: emu10k1: Fix potential Spectre v1 vulnerabilities ALSA: rme9652: Fix potential Spectre v1 vulnerability ASoC: ti: Kconfig: Remove the deprecated options ARM: davinci_all_defconfig: Update the audio options ARM: omap1_defconfig: Do not select ASoC by default ARM: omap2plus_defconfig: Update the audio options ARM: davinci: dm365-evm: Update for the new ASoC Kcofnig options ARM: OMAP2: Update for new MCBSP Kconfig option ARM: OMAP1: Makefile: Update for new MCBSP Kconfig option MAINTAINERS: Add entry for sound/soc/ti and update the OMAP audio support ASoC: ti: Merge davinci and omap directories ALSA: hda: add mute LED support for HP EliteBook 840 G4 ALSA: fireface: code refactoring to handle model-specific registers ALSA: fireface: add support for packet streaming on Fireface 800 ALSA: fireface: allocate isochronous resources in mode-specific implementation ...
This commit is contained in:
commit
8e61e7b5c4
|
@ -12,8 +12,8 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpio : a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the device starts.
|
||||
- reset-gpios : a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the device starts.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
AK4118 S/PDIF transceiver
|
||||
|
||||
This device supports I2C mode.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "asahi-kasei,ak4118"
|
||||
- reg : The I2C address of the device for I2C
|
||||
- reset-gpios: A GPIO specifier for the reset pin
|
||||
- irq-gpios: A GPIO specifier for the IRQ pin
|
||||
|
||||
Example:
|
||||
|
||||
&i2c {
|
||||
ak4118: ak4118@13 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "asahi-kasei,ak4118";
|
||||
reg = <0x13>;
|
||||
reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>
|
||||
irq-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
* Amlogic Audio SPDIF Input
|
||||
|
||||
Required properties:
|
||||
- compatible: 'amlogic,axg-spdifin'
|
||||
- interrupts: interrupt specifier for the spdif input.
|
||||
- clocks: list of clock phandle, one for each entry clock-names.
|
||||
- clock-names: should contain the following:
|
||||
* "pclk" : peripheral clock.
|
||||
* "refclk" : spdif input reference clock
|
||||
- #sound-dai-cells: must be 0.
|
||||
|
||||
Example on the A113 SoC:
|
||||
|
||||
spdifin: audio-controller@400 {
|
||||
compatible = "amlogic,axg-spdifin";
|
||||
reg = <0x0 0x400 0x0 0x30>;
|
||||
#sound-dai-cells = <0>;
|
||||
interrupts = <GIC_SPI 87 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clkc_audio AUD_CLKID_SPDIFIN>,
|
||||
<&clkc_audio AUD_CLKID_SPDIFIN_CLK>;
|
||||
clock-names = "pclk", "refclk";
|
||||
};
|
|
@ -32,7 +32,9 @@ Required properties:
|
|||
Optional properties:
|
||||
- pa-gpios: GPIO used to control external amplifier.
|
||||
|
||||
-----------------------
|
||||
Example: Single DAI case
|
||||
-----------------------
|
||||
|
||||
sound_card {
|
||||
compatible = "audio-graph-card";
|
||||
|
@ -61,7 +63,9 @@ Example: Single DAI case
|
|||
};
|
||||
};
|
||||
|
||||
-----------------------
|
||||
Example: Multi DAI case
|
||||
-----------------------
|
||||
|
||||
sound-card {
|
||||
compatible = "audio-graph-card";
|
||||
|
@ -130,3 +134,204 @@ Example: Multi DAI case
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
-----------------------
|
||||
Example: Sampling Rate Conversion
|
||||
-----------------------
|
||||
|
||||
sound_card {
|
||||
compatible = "audio-graph-card";
|
||||
|
||||
label = "sound-card";
|
||||
prefix = "codec";
|
||||
routing = "codec Playback", "DAI0 Playback",
|
||||
"DAI0 Capture", "codec Capture";
|
||||
convert-rate = <48000>;
|
||||
|
||||
dais = <&cpu_port>;
|
||||
};
|
||||
|
||||
audio-codec {
|
||||
...
|
||||
port {
|
||||
codec_endpoint: endpoint {
|
||||
remote-endpoint = <&cpu_endpoint>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dai-controller {
|
||||
...
|
||||
cpu_port: port {
|
||||
cpu_endpoint: endpoint {
|
||||
remote-endpoint = <&codec_endpoint>;
|
||||
|
||||
dai-format = "left_j";
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
-----------------------
|
||||
Example: 2 CPU 1 Codec (Mixing)
|
||||
-----------------------
|
||||
|
||||
sound_card {
|
||||
compatible = "audio-graph-card";
|
||||
|
||||
label = "sound-card";
|
||||
routing = "codec Playback", "DAI0 Playback",
|
||||
"codec Playback", "DAI1 Playback",
|
||||
"DAI0 Capture", "codec Capture";
|
||||
|
||||
dais = <&cpu_port>;
|
||||
};
|
||||
|
||||
audio-codec {
|
||||
...
|
||||
|
||||
audio-graph-card,prefix = "codec";
|
||||
audio-graph-card,convert-rate = <48000>;
|
||||
port {
|
||||
reg = <0>;
|
||||
codec_endpoint0: endpoint@0 {
|
||||
remote-endpoint = <&cpu_endpoint0>;
|
||||
};
|
||||
codec_endpoint1: endpoint@1 {
|
||||
remote-endpoint = <&cpu_endpoint1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dai-controller {
|
||||
...
|
||||
cpu_port: port {
|
||||
cpu_endpoint0: endpoint@0 {
|
||||
remote-endpoint = <&codec_endpoint0>;
|
||||
|
||||
dai-format = "left_j";
|
||||
...
|
||||
};
|
||||
cpu_endpoint1: endpoint@1 {
|
||||
remote-endpoint = <&codec_endpoint1>;
|
||||
|
||||
dai-format = "left_j";
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
-----------------------
|
||||
Example: Multi DAI with DPCM
|
||||
-----------------------
|
||||
|
||||
CPU0 ------ ak4613
|
||||
CPU1 ------ HDMI
|
||||
CPU2 ------ PCM3168A-p /* DPCM 1ch/2ch */
|
||||
CPU3 --/ /* DPCM 3ch/4ch */
|
||||
CPU4 --/ /* DPCM 5ch/6ch */
|
||||
CPU5 --/ /* DPCM 7ch/8ch */
|
||||
CPU6 ------ PCM3168A-c
|
||||
|
||||
sound_card: sound {
|
||||
compatible = "audio-graph-card";
|
||||
|
||||
label = "sound-card";
|
||||
|
||||
routing = "pcm3168a Playback", "DAI2 Playback",
|
||||
"pcm3168a Playback", "DAI3 Playback",
|
||||
"pcm3168a Playback", "DAI4 Playback",
|
||||
"pcm3168a Playback", "DAI5 Playback";
|
||||
|
||||
dais = <&snd_port0 /* ak4613 */
|
||||
&snd_port1 /* HDMI0 */
|
||||
&snd_port2 /* pcm3168a playback */
|
||||
&snd_port3 /* pcm3168a capture */
|
||||
>;
|
||||
};
|
||||
|
||||
ak4613: codec@10 {
|
||||
...
|
||||
port {
|
||||
ak4613_endpoint: endpoint {
|
||||
remote-endpoint = <&rsnd_endpoint0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pcm3168a: audio-codec@44 {
|
||||
...
|
||||
audio-graph-card,prefix = "pcm3168a";
|
||||
audio-graph-card,convert-channels = <8>; /* TDM Split */
|
||||
ports {
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
pcm3168a_endpoint_p1: endpoint@1 {
|
||||
remote-endpoint = <&rsnd_endpoint2>;
|
||||
...
|
||||
};
|
||||
pcm3168a_endpoint_p2: endpoint@2 {
|
||||
remote-endpoint = <&rsnd_endpoint3>;
|
||||
...
|
||||
};
|
||||
pcm3168a_endpoint_p3: endpoint@3 {
|
||||
remote-endpoint = <&rsnd_endpoint4>;
|
||||
...
|
||||
};
|
||||
pcm3168a_endpoint_p4: endpoint@4 {
|
||||
remote-endpoint = <&rsnd_endpoint5>;
|
||||
...
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
pcm3168a_endpoint_c: endpoint {
|
||||
remote-endpoint = <&rsnd_endpoint6>;
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&sound {
|
||||
ports {
|
||||
snd_port0: port@0 {
|
||||
rsnd_endpoint0: endpoint {
|
||||
remote-endpoint = <&ak4613_endpoint>;
|
||||
...
|
||||
};
|
||||
};
|
||||
snd_port1: port@1 {
|
||||
rsnd_endpoint1: endpoint {
|
||||
remote-endpoint = <&dw_hdmi0_snd_in>;
|
||||
...
|
||||
};
|
||||
};
|
||||
snd_port2: port@2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
rsnd_endpoint2: endpoint@2 {
|
||||
remote-endpoint = <&pcm3168a_endpoint_p1>;
|
||||
...
|
||||
};
|
||||
rsnd_endpoint3: endpoint@3 {
|
||||
remote-endpoint = <&pcm3168a_endpoint_p2>;
|
||||
...
|
||||
};
|
||||
rsnd_endpoint4: endpoint@4 {
|
||||
remote-endpoint = <&pcm3168a_endpoint_p3>;
|
||||
...
|
||||
};
|
||||
rsnd_endpoint5: endpoint@5 {
|
||||
remote-endpoint = <&pcm3168a_endpoint_p4>;
|
||||
...
|
||||
};
|
||||
};
|
||||
snd_port3: port@6 {
|
||||
rsnd_endpoint6: endpoint {
|
||||
remote-endpoint = <&pcm3168a_endpoint_c>;
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -77,11 +77,9 @@ Example 2. 2 CPU 1 Codec (Mixing)
|
|||
compatible = "audio-graph-scu-card";
|
||||
|
||||
label = "sound-card";
|
||||
prefix = "codec";
|
||||
routing = "codec Playback", "DAI0 Playback",
|
||||
"codec Playback", "DAI1 Playback",
|
||||
"DAI0 Capture", "codec Capture";
|
||||
convert-rate = <48000>;
|
||||
|
||||
dais = <&cpu_port0
|
||||
&cpu_port1>;
|
||||
|
@ -90,6 +88,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
|
|||
audio-codec {
|
||||
...
|
||||
|
||||
audio-graph-card,prefix = "codec";
|
||||
audio-graph-card,convert-rate = <48000>;
|
||||
port {
|
||||
codec_endpoint0: endpoint {
|
||||
remote-endpoint = <&cpu_endpoint0>;
|
||||
|
|
|
@ -10,8 +10,8 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpio : a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the codec starts.
|
||||
- reset-gpios : a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the codec starts.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -30,6 +30,11 @@ Optional properties:
|
|||
- ti,hwmods : Must be "mcasp<n>", n is controller instance starting 0
|
||||
- tx-num-evt : FIFO levels.
|
||||
- rx-num-evt : FIFO levels.
|
||||
- dismod : Specify the drive on TX pin during inactive slots
|
||||
0 : 3-state
|
||||
2 : logic low
|
||||
3 : logic high
|
||||
Defaults to 'logic low' when the property is not present
|
||||
- sram-size-playback : size of sram to be allocated during playback
|
||||
- sram-size-capture : size of sram to be allocated during capture
|
||||
- interrupts : Interrupt numbers for McASP
|
||||
|
|
|
@ -9,6 +9,7 @@ Optional properties:
|
|||
- dmicen-gpios: GPIO specifier for dmic to control start and stop
|
||||
- num-channels: Number of microphones on this DAI
|
||||
- wakeup-delay-ms: Delay (in ms) after enabling the DMIC
|
||||
- modeswitch-delay-ms: Delay (in ms) to complete DMIC mode switch
|
||||
|
||||
Example node:
|
||||
|
||||
|
@ -17,4 +18,5 @@ Example node:
|
|||
dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
|
||||
num-channels = <1>;
|
||||
wakeup-delay-ms <50>;
|
||||
modeswitch-delay-ms <35>;
|
||||
};
|
||||
|
|
|
@ -35,13 +35,13 @@ Required properties:
|
|||
|
||||
- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
|
||||
that SAI will work in the synchronous mode (sync Tx
|
||||
with Rx) which means both the transimitter and the
|
||||
with Rx) which means both the transmitter and the
|
||||
receiver will send and receive data by following
|
||||
receiver's bit clocks and frame sync clocks.
|
||||
|
||||
- fsl,sai-asynchronous: This is a boolean property. If present, indicating
|
||||
that SAI will work in the asynchronous mode, which
|
||||
means both transimitter and receiver will send and
|
||||
means both transmitter and receiver will send and
|
||||
receive data by following their own bit clocks and
|
||||
frame sync clocks separately.
|
||||
|
||||
|
@ -58,8 +58,8 @@ Optional properties (for mx6ul):
|
|||
Note:
|
||||
- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
|
||||
default synchronous mode (sync Rx with Tx) will be used, which means both
|
||||
transimitter and receiver will send and receive data by following clocks
|
||||
of transimitter.
|
||||
transmitter and receiver will send and receive data by following clocks
|
||||
of transmitter.
|
||||
- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive.
|
||||
|
||||
Example:
|
||||
|
|
|
@ -7,6 +7,8 @@ Required properties:
|
|||
<L3 interconnect address, size>;
|
||||
- interrupts: Interrupt number for McPDM
|
||||
- ti,hwmods: Name of the hwmod associated to the McPDM
|
||||
- clocks: phandle for the pdmclk provider, likely <&twl6040>
|
||||
- clock-names: Must be "pdmclk"
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -18,3 +20,11 @@ mcpdm: mcpdm@40132000 {
|
|||
interrupt-parent = <&gic>;
|
||||
ti,hwmods = "mcpdm";
|
||||
};
|
||||
|
||||
In board DTS file the pdmclk needs to be added:
|
||||
|
||||
&mcpdm {
|
||||
clocks = <&twl6040>;
|
||||
clock-names = "pdmclk";
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -9,9 +9,15 @@ Required properties:
|
|||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- ti,out-single-ended: "true" if output is single-ended;
|
||||
"false" or not specified if output is differential.
|
||||
|
||||
Examples:
|
||||
|
||||
pcm3060: pcm3060@46 {
|
||||
compatible = "ti,pcm3060";
|
||||
reg = <0x46>;
|
||||
ti,out-single-ended = "true";
|
||||
};
|
||||
|
|
|
@ -27,6 +27,28 @@ used by the apr service device.
|
|||
Value type: <u32>
|
||||
Definition: Must be 1
|
||||
|
||||
== ASM DAI is subnode of "dais" and represent a dai, it includes board specific
|
||||
configuration of each dai. Must contain the following properties.
|
||||
|
||||
- reg
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: Must be dai id
|
||||
|
||||
- direction:
|
||||
Usage: Required for Compress offload dais
|
||||
Value type: <u32>
|
||||
Definition: Specifies the direction of the dai stream
|
||||
0 for both tx and rx
|
||||
1 for only tx (Capture/Encode)
|
||||
2 for only rx (Playback/Decode)
|
||||
|
||||
- is-compress-dai:
|
||||
Usage: Required for Compress offload dais
|
||||
Value type: <boolean>
|
||||
Definition: present for Compress offload dais
|
||||
|
||||
|
||||
= EXAMPLE
|
||||
|
||||
q6asm@7 {
|
||||
|
@ -35,5 +57,10 @@ q6asm@7 {
|
|||
q6asmdai: dais {
|
||||
compatible = "qcom,q6asm-dais";
|
||||
#sound-dai-cells = <1>;
|
||||
mm@0 {
|
||||
reg = <0>;
|
||||
direction = <2>;
|
||||
is-compress-dai;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -39,15 +39,7 @@ This is example of
|
|||
Playback: [MEM] -> [SRC2] -> [DVC0] -> [SSIU0/SSI0] -> [codec]
|
||||
Capture: [MEM] <- [DVC1] <- [SRC3] <- [SSIU1/SSI1] <- [codec]
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
rcar_sound,dai {
|
||||
dai0 {
|
||||
playback = <&ssi0 &src2 &dvc0>;
|
||||
capture = <&ssi1 &src3 &dvc1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
see "Example: simple sound card"
|
||||
|
||||
You can use below.
|
||||
${LINUX}/arch/arm/boot/dts/r8a7790.dts can be good example.
|
||||
|
@ -83,29 +75,8 @@ SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
|
|||
** Asynchronous mode
|
||||
------------------
|
||||
|
||||
You need to use "simple-scu-audio-card" sound card for it.
|
||||
example)
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
/*
|
||||
* SRC Asynchronous mode setting
|
||||
* Playback:
|
||||
* All input data will be converted to 48kHz
|
||||
* Capture:
|
||||
* Inputed 48kHz data will be converted to
|
||||
* system specified Hz
|
||||
*/
|
||||
simple-audio-card,convert-rate = <48000>;
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
|
||||
see "Example: simple sound card for Asynchronous mode"
|
||||
|
||||
------------------
|
||||
** Synchronous mode
|
||||
|
@ -141,26 +112,8 @@ For more detail information, see below
|
|||
${LINUX}/sound/soc/sh/rcar/ctu.c
|
||||
- comment of header
|
||||
|
||||
You need to use "simple-scu-audio-card" sound card for it.
|
||||
example)
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
/*
|
||||
* CTU setting
|
||||
* All input data will be converted to 2ch
|
||||
* as output data
|
||||
*/
|
||||
simple-audio-card,convert-channels = <2>;
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
|
||||
see "Example: simple sound card for channel convert"
|
||||
|
||||
Ex) Exchange output channel
|
||||
Input -> Output
|
||||
|
@ -190,42 +143,13 @@ and these sounds will be merged by MIX.
|
|||
aplay -D plughw:0,0 xxxx.wav &
|
||||
aplay -D plughw:0,1 yyyy.wav
|
||||
|
||||
You need to use "simple-scu-audio-card" sound card for it.
|
||||
You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
|
||||
Ex)
|
||||
[MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
|
||||
|
|
||||
[MEM] -> [SRC2] -> [CTU03] -+
|
||||
|
||||
sound {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
simple-audio-card,cpu@0 {
|
||||
reg = <0>;
|
||||
sound-dai = <&rcar_sound 0>;
|
||||
};
|
||||
simple-audio-card,cpu@1 {
|
||||
reg = <1>;
|
||||
sound-dai = <&rcar_sound 1>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
rcar_sound,dai {
|
||||
dai0 {
|
||||
playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
|
||||
};
|
||||
dai1 {
|
||||
playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
see "Example: simple sound card for MIXer"
|
||||
|
||||
=============================================
|
||||
* DVC (Digital Volume and Mute Function)
|
||||
|
@ -257,15 +181,31 @@ Volume Ramp
|
|||
* SSIU (Serial Sound Interface Unit)
|
||||
=============================================
|
||||
|
||||
There is no DT settings for SSIU, because SSIU will be automatically
|
||||
selected via SSI.
|
||||
SSIU can avoid some under/over run error, because it has some buffer.
|
||||
But you can't use it if SSI was PIO mode.
|
||||
In DMA mode, you can select not to use SSIU by using "no-busif" on DT.
|
||||
In DMA mode, you can select not to use SSIU by using "no-busif" via SSI.
|
||||
|
||||
&ssi0 {
|
||||
no-busif;
|
||||
};
|
||||
SSIU handles BUSIF which will be used for TDM Split mode.
|
||||
This driver is assuming that audio-graph card will be used.
|
||||
|
||||
TDM Split mode merges 4 sounds. You can see 4 sound interface on system,
|
||||
and these sounds will be merged SSIU/SSI.
|
||||
|
||||
aplay -D plughw:0,0 xxxx.wav &
|
||||
aplay -D plughw:0,1 xxxx.wav &
|
||||
aplay -D plughw:0,2 xxxx.wav &
|
||||
aplay -D plughw:0,3 xxxx.wav
|
||||
|
||||
2ch 8ch
|
||||
[MEM] -> [SSIU 30] -+-> [SSIU 3] --> [Codec]
|
||||
2ch |
|
||||
[MEM] -> [SSIU 31] -+
|
||||
2ch |
|
||||
[MEM] -> [SSIU 32] -+
|
||||
2ch |
|
||||
[MEM] -> [SSIU 33] -+
|
||||
|
||||
see "Example: simple sound card for TDM Split"
|
||||
|
||||
=============================================
|
||||
* SSI (Serial Sound Interface)
|
||||
|
@ -304,14 +244,7 @@ This is example if SSI1 want to share WS pin with SSI0
|
|||
You can use Multi-SSI.
|
||||
This is example of SSI0/SSI1/SSI2 (= for 6ch)
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
rcar_sound,dai {
|
||||
dai0 {
|
||||
playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
see "Example: simple sound card for Multi channel"
|
||||
|
||||
** TDM-SSI
|
||||
|
||||
|
@ -319,19 +252,7 @@ You can use TDM with SSI.
|
|||
This is example of TDM 6ch.
|
||||
Driver can automatically switches TDM <-> stereo mode in this case.
|
||||
|
||||
rsnd_tdm: sound {
|
||||
compatible = "simple-audio-card";
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
/* system can use TDM 6ch */
|
||||
dai-tdm-slot-num = <6>;
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
see "Example: simple sound card for TDM"
|
||||
|
||||
=============================================
|
||||
Required properties:
|
||||
|
@ -346,6 +267,7 @@ Required properties:
|
|||
- "renesas,rcar_sound-r8a7744" (RZ/G1N)
|
||||
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
|
||||
- "renesas,rcar_sound-r8a774a1" (RZ/G2M)
|
||||
- "renesas,rcar_sound-r8a774c0" (RZ/G2E)
|
||||
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
||||
- "renesas,rcar_sound-r8a7779" (R-Car H1)
|
||||
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
||||
|
@ -356,6 +278,7 @@ Required properties:
|
|||
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
|
||||
- "renesas,rcar_sound-r8a77965" (R-Car M3-N)
|
||||
- "renesas,rcar_sound-r8a77990" (R-Car E3)
|
||||
- "renesas,rcar_sound-r8a77995" (R-Car D3)
|
||||
- reg : Should contain the register physical address.
|
||||
required register is
|
||||
SRU/ADG/SSI if generation1
|
||||
|
@ -363,6 +286,9 @@ Required properties:
|
|||
- rcar_sound,ssi : Should contain SSI feature.
|
||||
The number of SSI subnode should be same as HW.
|
||||
see below for detail.
|
||||
- rcar_sound,ssiu : Should contain SSIU feature.
|
||||
The number of SSIU subnode should be same as HW.
|
||||
see below for detail.
|
||||
- rcar_sound,src : Should contain SRC feature.
|
||||
The number of SRC subnode should be same as HW.
|
||||
see below for detail.
|
||||
|
@ -402,8 +328,13 @@ SSI subnode properties:
|
|||
- no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case
|
||||
- dma : Should contain Audio DMAC entry
|
||||
- dma-names : SSI case "rx" (=playback), "tx" (=capture)
|
||||
Deprecated: see SSIU subnode properties
|
||||
SSIU case "rxu" (=playback), "txu" (=capture)
|
||||
|
||||
SSIU subnode properties:
|
||||
- dma : Should contain Audio DMAC entry
|
||||
- dma-names : "rx" (=playback), "tx" (=capture)
|
||||
|
||||
SRC subnode properties:
|
||||
- dma : Should contain Audio DMAC entry
|
||||
- dma-names : "rx" (=playback), "tx" (=capture)
|
||||
|
@ -532,56 +463,55 @@ rcar_sound: sound@ec500000 {
|
|||
};
|
||||
};
|
||||
|
||||
rcar_sound,ssiu {
|
||||
ssiu00: ssiu-0 {
|
||||
dmas = <&audma0 0x15>, <&audma1 0x16>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssiu01: ssiu-1 {
|
||||
dmas = <&audma0 0x35>, <&audma1 0x36>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
ssiu95: ssiu-49 {
|
||||
dmas = <&audma0 0xA5>, <&audma1 0xA6>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssiu96: ssiu-50 {
|
||||
dmas = <&audma0 0xA7>, <&audma1 0xA8>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssiu97: ssiu-51 {
|
||||
dmas = <&audma0 0xA9>, <&audma1 0xAA>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
};
|
||||
|
||||
rcar_sound,ssi {
|
||||
ssi0: ssi-0 {
|
||||
interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
dmas = <&audma0 0x01>, <&audma1 0x02>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssi1: ssi-1 {
|
||||
interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi2: ssi-2 {
|
||||
interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi3: ssi-3 {
|
||||
interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi4: ssi-4 {
|
||||
interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi5: ssi-5 {
|
||||
interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi6: ssi-6 {
|
||||
interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi7: ssi-7 {
|
||||
interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
dmas = <&audma0 0x03>, <&audma1 0x04>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
ssi8: ssi-8 {
|
||||
interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
dmas = <&audma0 0x11>, <&audma1 0x12>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssi9: ssi-9 {
|
||||
interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
dmas = <&audma0 0x13>, <&audma1 0x14>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -646,26 +576,175 @@ Example: simple sound card
|
|||
shared-pin;
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for Asynchronous mode
|
||||
=============================================
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
/*
|
||||
* SRC Asynchronous mode setting
|
||||
* Playback:
|
||||
* All input data will be converted to 48kHz
|
||||
* Capture:
|
||||
* Inputed 48kHz data will be converted to
|
||||
* system specified Hz
|
||||
*/
|
||||
simple-audio-card,convert-rate = <48000>;
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for channel convert
|
||||
=============================================
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
/*
|
||||
* CTU setting
|
||||
* All input data will be converted to 2ch
|
||||
* as output data
|
||||
*/
|
||||
simple-audio-card,convert-channels = <2>;
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for MIXer
|
||||
=============================================
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
simple-audio-card,cpu@0 {
|
||||
sound-dai = <&rcar_sound 0>;
|
||||
};
|
||||
simple-audio-card,cpu@1 {
|
||||
sound-dai = <&rcar_sound 1>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
rcar_sound,dai {
|
||||
dai0 {
|
||||
playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
|
||||
};
|
||||
dai1 {
|
||||
playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for TDM
|
||||
=============================================
|
||||
|
||||
rsnd_tdm: sound {
|
||||
compatible = "simple-audio-card";
|
||||
rsnd_tdm: sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&sndcodec>;
|
||||
simple-audio-card,frame-master = <&sndcodec>;
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&sndcodec>;
|
||||
simple-audio-card,frame-master = <&sndcodec>;
|
||||
|
||||
sndcpu: simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
dai-tdm-slot-num = <6>;
|
||||
sndcpu: simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
dai-tdm-slot-num = <6>;
|
||||
};
|
||||
|
||||
sndcodec: simple-audio-card,codec {
|
||||
sound-dai = <&xxx>;
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for TDM Split
|
||||
=============================================
|
||||
|
||||
sound_card: sound {
|
||||
compatible = "audio-graph-scu-card";
|
||||
prefix = "xxxx";
|
||||
routing = "xxxx Playback", "DAI0 Playback",
|
||||
"xxxx Playback", "DAI1 Playback",
|
||||
"xxxx Playback", "DAI2 Playback",
|
||||
"xxxx Playback", "DAI3 Playback";
|
||||
convert-channels = <8>; /* TDM Split */
|
||||
|
||||
dais = <&rsnd_port0 /* playback ch1/ch2 */
|
||||
&rsnd_port1 /* playback ch3/ch4 */
|
||||
&rsnd_port2 /* playback ch5/ch6 */
|
||||
&rsnd_port3 /* playback ch7/ch8 */
|
||||
>;
|
||||
};
|
||||
|
||||
audio-codec {
|
||||
...
|
||||
port {
|
||||
codec_0: endpoint@1 {
|
||||
remote-endpoint = <&rsnd_ep0>;
|
||||
};
|
||||
|
||||
sndcodec: simple-audio-card,codec {
|
||||
sound-dai = <&xxx>;
|
||||
codec_1: endpoint@2 {
|
||||
remote-endpoint = <&rsnd_ep1>;
|
||||
};
|
||||
codec_2: endpoint@3 {
|
||||
remote-endpoint = <&rsnd_ep2>;
|
||||
};
|
||||
codec_3: endpoint@4 {
|
||||
remote-endpoint = <&rsnd_ep3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
ports {
|
||||
rsnd_port0: port@0 {
|
||||
rsnd_ep0: endpoint {
|
||||
remote-endpoint = <&codec_0>;
|
||||
...
|
||||
playback = <&ssiu30 &ssi3>;
|
||||
};
|
||||
};
|
||||
rsnd_port1: port@1 {
|
||||
rsnd_ep1: endpoint {
|
||||
remote-endpoint = <&codec_1>;
|
||||
...
|
||||
playback = <&ssiu31 &ssi3>;
|
||||
};
|
||||
};
|
||||
rsnd_port2: port@2 {
|
||||
rsnd_ep2: endpoint {
|
||||
remote-endpoint = <&codec_2>;
|
||||
...
|
||||
playback = <&ssiu32 &ssi3>;
|
||||
};
|
||||
};
|
||||
rsnd_port3: port@3 {
|
||||
rsnd_ep3: endpoint {
|
||||
remote-endpoint = <&codec_3>;
|
||||
...
|
||||
playback = <&ssiu33 &ssi3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for Multi channel
|
||||
|
|
|
@ -35,14 +35,14 @@ Pins on the device (for linking into audio routes):
|
|||
|
||||
Example:
|
||||
|
||||
alc5631: alc5631@1a {
|
||||
alc5631: audio-codec@1a {
|
||||
compatible = "realtek,alc5631";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
||||
or
|
||||
|
||||
rt5631: rt5631@1a {
|
||||
rt5631: audio-codec@1a {
|
||||
compatible = "realtek,rt5631";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
|
|
@ -10,6 +10,10 @@ Required properties:
|
|||
|
||||
- interrupts : The CODEC's interrupt output.
|
||||
|
||||
- avdd-supply: Power supply for AVDD, providing 1.8V.
|
||||
|
||||
- cpvdd-supply: Power supply for CPVDD, providing 3.5V.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- "realtek,dc_offset_l_manual"
|
||||
|
@ -51,4 +55,6 @@ rt5663: codec@12 {
|
|||
compatible = "realtek,rt5663";
|
||||
reg = <0x12>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
|
||||
avdd-supply = <&pp1800_a_alc5662>;
|
||||
cpvdd-supply = <&pp3500_a_alc5662>;
|
||||
};
|
||||
|
|
|
@ -4,9 +4,14 @@ Required properties:
|
|||
- compatible : "dioo,dio2125" or "simple-audio-amplifier"
|
||||
- enable-gpios : the gpio connected to the enable pin of the simple amplifier
|
||||
|
||||
Optional properties:
|
||||
- VCC-supply : power supply for the device, as covered
|
||||
in Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
Example:
|
||||
|
||||
amp: analog-amplifier {
|
||||
compatible = "simple-audio-amplifier";
|
||||
VCC-supply = <®ulator>;
|
||||
enable-gpios = <&gpio GPIOH_3 0>;
|
||||
};
|
||||
|
|
|
@ -95,7 +95,9 @@ Optional CPU/CODEC subnodes properties:
|
|||
initialization. It is useful for some aCPUs with
|
||||
fixed clocks.
|
||||
|
||||
-------------------------------------------
|
||||
Example 1 - single DAI link:
|
||||
-------------------------------------------
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
@ -138,7 +140,9 @@ sh_fsi2: sh_fsi2@ec230000 {
|
|||
interrupts = <0 146 0x4>;
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 2 - many DAI links:
|
||||
-------------------------------------------
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
@ -176,8 +180,10 @@ sound {
|
|||
};
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 3 - route audio from IMX6 SSI2 through TLV320DAC3100 codec
|
||||
through TPA6130A2 amplifier to headphones:
|
||||
-------------------------------------------
|
||||
|
||||
&i2c0 {
|
||||
codec: tlv320dac3100@18 {
|
||||
|
@ -210,3 +216,134 @@ sound {
|
|||
clocks = ...
|
||||
};
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 4. Sampling Rate Conversion
|
||||
-------------------------------------------
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
||||
simple-audio-card,name = "rsnd-ak4643";
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&sndcodec>;
|
||||
simple-audio-card,frame-master = <&sndcodec>;
|
||||
|
||||
simple-audio-card,convert-rate = <48000>;
|
||||
|
||||
simple-audio-card,prefix = "ak4642";
|
||||
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
|
||||
"DAI0 Capture", "ak4642 Capture";
|
||||
|
||||
sndcpu: simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
|
||||
sndcodec: simple-audio-card,codec {
|
||||
sound-dai = <&ak4643>;
|
||||
system-clock-frequency = <11289600>;
|
||||
};
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 5. 2 CPU 1 Codec (Mixing)
|
||||
-------------------------------------------
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
||||
simple-audio-card,name = "rsnd-ak4643";
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&dpcmcpu>;
|
||||
simple-audio-card,frame-master = <&dpcmcpu>;
|
||||
|
||||
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
|
||||
"ak4642 Playback", "DAI1 Playback";
|
||||
|
||||
dpcmcpu: cpu@0 {
|
||||
sound-dai = <&rcar_sound 0>;
|
||||
};
|
||||
|
||||
cpu@1 {
|
||||
sound-dai = <&rcar_sound 1>;
|
||||
};
|
||||
|
||||
codec {
|
||||
prefix = "ak4642";
|
||||
sound-dai = <&ak4643>;
|
||||
clocks = <&audio_clock>;
|
||||
};
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 6 - many DAI links with DPCM:
|
||||
-------------------------------------------
|
||||
|
||||
CPU0 ------ ak4613
|
||||
CPU1 ------ PCM3168A-p /* DPCM 1ch/2ch */
|
||||
CPU2 --/ /* DPCM 3ch/4ch */
|
||||
CPU3 --/ /* DPCM 5ch/6ch */
|
||||
CPU4 --/ /* DPCM 7ch/8ch */
|
||||
CPU5 ------ PCM3168A-c
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
||||
simple-audio-card,routing =
|
||||
"pcm3168a Playback", "DAI1 Playback",
|
||||
"pcm3168a Playback", "DAI2 Playback",
|
||||
"pcm3168a Playback", "DAI3 Playback",
|
||||
"pcm3168a Playback", "DAI4 Playback";
|
||||
|
||||
simple-audio-card,dai-link@0 {
|
||||
format = "left_j";
|
||||
bitclock-master = <&sndcpu0>;
|
||||
frame-master = <&sndcpu0>;
|
||||
|
||||
sndcpu0: cpu {
|
||||
sound-dai = <&rcar_sound 0>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&ak4613>;
|
||||
};
|
||||
};
|
||||
simple-audio-card,dai-link@1 {
|
||||
format = "i2s";
|
||||
bitclock-master = <&sndcpu1>;
|
||||
frame-master = <&sndcpu1>;
|
||||
|
||||
convert-channels = <8>; /* TDM Split */
|
||||
|
||||
sndcpu1: cpu@0 {
|
||||
sound-dai = <&rcar_sound 1>;
|
||||
};
|
||||
cpu@1 {
|
||||
sound-dai = <&rcar_sound 2>;
|
||||
};
|
||||
cpu@2 {
|
||||
sound-dai = <&rcar_sound 3>;
|
||||
};
|
||||
cpu@3 {
|
||||
sound-dai = <&rcar_sound 4>;
|
||||
};
|
||||
codec {
|
||||
mclk-fs = <512>;
|
||||
prefix = "pcm3168a";
|
||||
dai-tdm-slot-num = <8>;
|
||||
sound-dai = <&pcm3168a 0>;
|
||||
};
|
||||
};
|
||||
simple-audio-card,dai-link@2 {
|
||||
format = "i2s";
|
||||
bitclock-master = <&sndcpu2>;
|
||||
frame-master = <&sndcpu2>;
|
||||
|
||||
sndcpu2: cpu {
|
||||
sound-dai = <&rcar_sound 5>;
|
||||
};
|
||||
codec {
|
||||
mclk-fs = <512>;
|
||||
prefix = "pcm3168a";
|
||||
sound-dai = <&pcm3168a 1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -75,7 +75,6 @@ sound {
|
|||
simple-audio-card,bitclock-master = <&dpcmcpu>;
|
||||
simple-audio-card,frame-master = <&dpcmcpu>;
|
||||
|
||||
simple-audio-card,prefix = "ak4642";
|
||||
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
|
||||
"ak4642 Playback", "DAI1 Playback";
|
||||
|
||||
|
@ -88,6 +87,7 @@ sound {
|
|||
};
|
||||
|
||||
codec {
|
||||
prefix = "ak4642";
|
||||
sound-dai = <&ak4643>;
|
||||
clocks = <&audio_clock>;
|
||||
};
|
||||
|
|
|
@ -4,9 +4,11 @@ Required properties:
|
|||
- compatible: must be one of the following compatibles:
|
||||
- "allwinner,sun50i-a64-codec-analog"
|
||||
- reg: must contain the registers location and length
|
||||
- cpvdd-supply: Regulator supply for the headphone amplifier
|
||||
|
||||
Example:
|
||||
codec_analog: codec-analog@1f015c0 {
|
||||
compatible = "allwinner,sun50i-a64-codec-analog";
|
||||
reg = <0x01f015c0 0x4>;
|
||||
cpvdd-supply = <®_eldo1>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
Device-Tree bindings for Xilinx I2S PL block
|
||||
|
||||
The IP supports I2S based playback/capture audio
|
||||
|
||||
Required property:
|
||||
- compatible: "xlnx,i2s-transmitter-1.0" for playback and
|
||||
"xlnx,i2s-receiver-1.0" for capture
|
||||
|
||||
Required property common to both I2S playback and capture:
|
||||
- reg: Base address and size of the IP core instance.
|
||||
- xlnx,dwidth: sample data width. Can be any of 16, 24.
|
||||
- xlnx,num-channels: Number of I2S streams. Can be any of 1, 2, 3, 4.
|
||||
supported channels = 2 * xlnx,num-channels
|
||||
|
||||
Example:
|
||||
|
||||
i2s_receiver@a0080000 {
|
||||
compatible = "xlnx,i2s-receiver-1.0";
|
||||
reg = <0x0 0xa0080000 0x0 0x10000>;
|
||||
xlnx,dwidth = <0x18>;
|
||||
xlnx,num-channels = <1>;
|
||||
};
|
||||
i2s_transmitter@a0090000 {
|
||||
compatible = "xlnx,i2s-transmitter-1.0";
|
||||
reg = <0x0 0xa0090000 0x0 0x10000>;
|
||||
xlnx,dwidth = <0x18>;
|
||||
xlnx,num-channels = <1>;
|
||||
};
|
18
MAINTAINERS
18
MAINTAINERS
|
@ -1310,6 +1310,13 @@ F: drivers/pinctrl/meson/
|
|||
F: drivers/mmc/host/meson*
|
||||
N: meson
|
||||
|
||||
ARM/Amlogic Meson SoC Sound Drivers
|
||||
M: Jerome Brunet <jbrunet@baylibre.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: sound/soc/meson/
|
||||
F: Documentation/devicetree/bindings/sound/amlogic*
|
||||
|
||||
ARM/Annapurna Labs ALPINE ARCHITECTURE
|
||||
M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
|
||||
M: Antoine Tenart <antoine.tenart@bootlin.com>
|
||||
|
@ -10862,7 +10869,10 @@ M: Jarkko Nikula <jarkko.nikula@bitmer.com>
|
|||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
L: linux-omap@vger.kernel.org
|
||||
S: Maintained
|
||||
F: sound/soc/omap/
|
||||
F: sound/soc/ti/omap*
|
||||
F: sound/soc/ti/rx51.c
|
||||
F: sound/soc/ti/n810.c
|
||||
F: sound/soc/ti/sdma-pcm.*
|
||||
|
||||
OMAP CLOCK FRAMEWORK SUPPORT
|
||||
M: Paul Walmsley <paul@pwsan.com>
|
||||
|
@ -14927,6 +14937,12 @@ F: Documentation/devicetree/bindings/clock/ti,sci-clk.txt
|
|||
F: drivers/clk/keystone/sci-clk.c
|
||||
F: drivers/reset/reset-ti-sci.c
|
||||
|
||||
Texas Instruments ASoC drivers
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: sound/soc/ti/
|
||||
|
||||
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
|
||||
M: Hans Verkuil <hverkuil@xs4all.nl>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
|
|
@ -167,8 +167,9 @@ CONFIG_SOUND=m
|
|||
CONFIG_SND=m
|
||||
CONFIG_SND_USB_AUDIO=m
|
||||
CONFIG_SND_SOC=m
|
||||
CONFIG_SND_EDMA_SOC=m
|
||||
CONFIG_SND_DA850_SOC_EVM=m
|
||||
CONFIG_SND_SOC_TLV320AIC3X=m
|
||||
CONFIG_SND_SOC_DAVINCI_MCASP=m
|
||||
CONFIG_SND_SOC_DAVINCI_EVM=m
|
||||
CONFIG_SND_SIMPLE_CARD=m
|
||||
CONFIG_HID=m
|
||||
CONFIG_HID_A4TECH=m
|
||||
|
|
|
@ -175,8 +175,6 @@ CONFIG_SND_PCM_OSS=y
|
|||
# CONFIG_SND_VERBOSE_PROCFS is not set
|
||||
CONFIG_SND_DUMMY=y
|
||||
CONFIG_SND_USB_AUDIO=y
|
||||
CONFIG_SND_SOC=y
|
||||
CONFIG_SND_OMAP_SOC=y
|
||||
# CONFIG_USB_HID is not set
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_PHY=y
|
||||
|
|
|
@ -381,13 +381,13 @@ CONFIG_SND_VERBOSE_PRINTK=y
|
|||
CONFIG_SND_DEBUG=y
|
||||
CONFIG_SND_USB_AUDIO=m
|
||||
CONFIG_SND_SOC=m
|
||||
CONFIG_SND_EDMA_SOC=m
|
||||
CONFIG_SND_AM33XX_SOC_EVM=m
|
||||
CONFIG_SND_OMAP_SOC=m
|
||||
CONFIG_SND_OMAP_SOC_HDMI_AUDIO=m
|
||||
CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m
|
||||
CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m
|
||||
CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
|
||||
CONFIG_SND_SOC_TLV320AIC3X=m
|
||||
CONFIG_SND_SOC_DAVINCI_MCASP=m
|
||||
CONFIG_SND_SOC_NOKIA_RX51=m
|
||||
CONFIG_SND_SOC_OMAP_HDMI=m
|
||||
CONFIG_SND_SOC_OMAP_ABE_TWL6040=m
|
||||
CONFIG_SND_SOC_OMAP3_PANDORA=m
|
||||
CONFIG_SND_SOC_OMAP3_TWL4030=m
|
||||
CONFIG_SND_SOC_CPCAP=m
|
||||
CONFIG_SND_SIMPLE_CARD=m
|
||||
CONFIG_SND_AUDIO_GRAPH_CARD=m
|
||||
|
|
|
@ -794,9 +794,9 @@ static __init void dm365_evm_init(void)
|
|||
/* maybe setup mmc1/etc ... _after_ mmc0 */
|
||||
evm_init_cpld();
|
||||
|
||||
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
|
||||
#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
|
||||
dm365_init_asp();
|
||||
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
|
||||
#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
|
||||
dm365_init_vc();
|
||||
#endif
|
||||
dm365_init_rtc();
|
||||
|
|
|
@ -8,7 +8,7 @@ obj-y := io.o id.o sram-init.o sram.o time.o irq.o mux.o flash.o \
|
|||
serial.o devices.o dma.o fb.o
|
||||
obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
|
||||
|
||||
ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
|
||||
ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
|
||||
obj-y += mcbsp.o
|
||||
endif
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ obj-$(CONFIG_SOC_OMAP5) += $(hwmod-common) $(secure-common)
|
|||
obj-$(CONFIG_SOC_AM43XX) += $(hwmod-common) $(secure-common)
|
||||
obj-$(CONFIG_SOC_DRA7XX) += $(hwmod-common) $(secure-common)
|
||||
|
||||
ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
|
||||
ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
|
||||
obj-y += mcbsp.o
|
||||
endif
|
||||
|
||||
|
|
|
@ -524,7 +524,7 @@ void omap_auxdata_legacy_init(struct device *dev)
|
|||
dev->platform_data = &twl_gpio_auxdata;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
|
||||
static struct omap_mcbsp_platform_data mcbsp_pdata;
|
||||
static void __init omap3_mcbsp_init(void)
|
||||
{
|
||||
|
@ -572,7 +572,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] = {
|
|||
OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
|
||||
&am35xx_emac_pdata),
|
||||
/* McBSP modules with sidetone core */
|
||||
#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
|
||||
OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49022000, "49022000.mcbsp", &mcbsp_pdata),
|
||||
OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49024000, "49024000.mcbsp", &mcbsp_pdata),
|
||||
#endif
|
||||
|
|
|
@ -136,4 +136,11 @@ config LEDS_TRIGGER_PATTERN
|
|||
which is a series of tuples, of brightness and duration (ms).
|
||||
If unsure, say N
|
||||
|
||||
config LEDS_TRIGGER_AUDIO
|
||||
tristate "Audio Mute LED Trigger"
|
||||
help
|
||||
This allows LEDs to be controlled by audio drivers for following
|
||||
the audio mute and mic-mute changes.
|
||||
If unsure, say N
|
||||
|
||||
endif # LEDS_TRIGGERS
|
||||
|
|
|
@ -14,3 +14,4 @@ obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
|
|||
obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_AUDIO) += ledtrig-audio.o
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Audio Mute LED trigger
|
||||
//
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static struct led_trigger *ledtrig_audio[NUM_AUDIO_LEDS];
|
||||
static enum led_brightness audio_state[NUM_AUDIO_LEDS];
|
||||
|
||||
enum led_brightness ledtrig_audio_get(enum led_audio type)
|
||||
{
|
||||
return audio_state[type];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ledtrig_audio_get);
|
||||
|
||||
void ledtrig_audio_set(enum led_audio type, enum led_brightness state)
|
||||
{
|
||||
audio_state[type] = state;
|
||||
led_trigger_event(ledtrig_audio[type], state);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ledtrig_audio_set);
|
||||
|
||||
static int __init ledtrig_audio_init(void)
|
||||
{
|
||||
led_trigger_register_simple("audio-mute",
|
||||
&ledtrig_audio[LED_AUDIO_MUTE]);
|
||||
led_trigger_register_simple("audio-micmute",
|
||||
&ledtrig_audio[LED_AUDIO_MICMUTE]);
|
||||
return 0;
|
||||
}
|
||||
module_init(ledtrig_audio_init);
|
||||
|
||||
static void __exit ledtrig_audio_exit(void)
|
||||
{
|
||||
led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MUTE]);
|
||||
led_trigger_unregister_simple(ledtrig_audio[LED_AUDIO_MICMUTE]);
|
||||
}
|
||||
module_exit(ledtrig_audio_exit);
|
||||
|
||||
MODULE_DESCRIPTION("LED trigger for audio mute control");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -177,6 +177,8 @@ config DELL_LAPTOP
|
|||
select POWER_SUPPLY
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
select LEDS_TRIGGERS
|
||||
select LEDS_TRIGGER_AUDIO
|
||||
---help---
|
||||
This driver adds support for rfkill and backlight control to Dell
|
||||
laptops (except for some models covered by the Compal driver).
|
||||
|
@ -493,6 +495,8 @@ config THINKPAD_ACPI
|
|||
select NVRAM
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
select LEDS_TRIGGERS
|
||||
select LEDS_TRIGGER_AUDIO
|
||||
---help---
|
||||
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
|
||||
support for Fn-Fx key combinations, Bluetooth control, video
|
||||
|
@ -1288,6 +1292,23 @@ config INTEL_ATOMISP2_PM
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called intel_atomisp2_pm.
|
||||
|
||||
config HUAWEI_WMI
|
||||
tristate "Huawei WMI hotkeys driver"
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
select INPUT_SPARSEKMAP
|
||||
select LEDS_CLASS
|
||||
select LEDS_TRIGGERS
|
||||
select LEDS_TRIGGER_AUDIO
|
||||
select NEW_LEDS
|
||||
help
|
||||
This driver provides support for Huawei WMI hotkeys.
|
||||
It enables the missing keys and adds support to the micmute
|
||||
LED found on some of these laptops.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called huawei-wmi.
|
||||
|
||||
endif # X86_PLATFORM_DEVICES
|
||||
|
||||
config PMC_ATOM
|
||||
|
|
|
@ -32,6 +32,7 @@ obj-$(CONFIG_ACERHDF) += acerhdf.o
|
|||
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
|
||||
obj-$(CONFIG_HP_WIRELESS) += hp-wireless.o
|
||||
obj-$(CONFIG_HP_WMI) += hp-wmi.o
|
||||
obj-$(CONFIG_HUAWEI_WMI) += huawei-wmi.o
|
||||
obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o
|
||||
obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o
|
||||
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/i8042.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dell-led.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <acpi/video.h>
|
||||
#include "dell-rbtn.h"
|
||||
|
@ -2111,17 +2110,17 @@ static struct notifier_block dell_laptop_notifier = {
|
|||
.notifier_call = dell_laptop_notifier_call,
|
||||
};
|
||||
|
||||
int dell_micmute_led_set(int state)
|
||||
static int micmute_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
struct calling_interface_token *token;
|
||||
int state = brightness != LED_OFF;
|
||||
|
||||
if (state == 0)
|
||||
token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
|
||||
else if (state == 1)
|
||||
token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
|
||||
else
|
||||
return -EINVAL;
|
||||
token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
|
||||
|
||||
if (!token)
|
||||
return -ENODEV;
|
||||
|
@ -2129,9 +2128,15 @@ int dell_micmute_led_set(int state)
|
|||
dell_fill_request(&buffer, token->location, token->value, 0, 0);
|
||||
dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
|
||||
|
||||
return state;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dell_micmute_led_set);
|
||||
|
||||
static struct led_classdev micmute_led_cdev = {
|
||||
.name = "platform::micmute",
|
||||
.max_brightness = 1,
|
||||
.brightness_set_blocking = micmute_led_set,
|
||||
.default_trigger = "audio-micmute",
|
||||
};
|
||||
|
||||
static int __init dell_init(void)
|
||||
{
|
||||
|
@ -2177,6 +2182,11 @@ static int __init dell_init(void)
|
|||
|
||||
dell_laptop_register_notifier(&dell_laptop_notifier);
|
||||
|
||||
micmute_led_cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
|
||||
ret = led_classdev_register(&platform_device->dev, &micmute_led_cdev);
|
||||
if (ret < 0)
|
||||
goto fail_led;
|
||||
|
||||
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
|
||||
return 0;
|
||||
|
||||
|
@ -2222,6 +2232,8 @@ static int __init dell_init(void)
|
|||
fail_get_brightness:
|
||||
backlight_device_unregister(dell_backlight_device);
|
||||
fail_backlight:
|
||||
led_classdev_unregister(&micmute_led_cdev);
|
||||
fail_led:
|
||||
dell_cleanup_rfkill();
|
||||
fail_rfkill:
|
||||
platform_device_del(platform_device);
|
||||
|
@ -2241,6 +2253,7 @@ static void __exit dell_exit(void)
|
|||
touchpad_led_exit();
|
||||
kbd_led_exit();
|
||||
backlight_device_unregister(dell_backlight_device);
|
||||
led_classdev_unregister(&micmute_led_cdev);
|
||||
dell_cleanup_rfkill();
|
||||
if (platform_device) {
|
||||
platform_device_unregister(platform_device);
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Huawei WMI hotkeys
|
||||
*
|
||||
* Copyright (C) 2018 Ayman Bagabas <ayman.bagabas@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
/*
|
||||
* Huawei WMI GUIDs
|
||||
*/
|
||||
#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
|
||||
#define AMW0_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
|
||||
|
||||
#define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
|
||||
|
||||
struct huawei_wmi_priv {
|
||||
struct input_dev *idev;
|
||||
struct led_classdev cdev;
|
||||
acpi_handle handle;
|
||||
char *acpi_method;
|
||||
};
|
||||
|
||||
static const struct key_entry huawei_wmi_keymap[] = {
|
||||
{ KE_KEY, 0x281, { KEY_BRIGHTNESSDOWN } },
|
||||
{ KE_KEY, 0x282, { KEY_BRIGHTNESSUP } },
|
||||
{ KE_KEY, 0x284, { KEY_MUTE } },
|
||||
{ KE_KEY, 0x285, { KEY_VOLUMEDOWN } },
|
||||
{ KE_KEY, 0x286, { KEY_VOLUMEUP } },
|
||||
{ KE_KEY, 0x287, { KEY_MICMUTE } },
|
||||
{ KE_KEY, 0x289, { KEY_WLAN } },
|
||||
// Huawei |M| key
|
||||
{ KE_KEY, 0x28a, { KEY_CONFIG } },
|
||||
// Keyboard backlight
|
||||
{ KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } },
|
||||
{ KE_IGNORE, 0x294, { KEY_KBDILLUMUP } },
|
||||
{ KE_IGNORE, 0x295, { KEY_KBDILLUMUP } },
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct huawei_wmi_priv *priv = dev_get_drvdata(led_cdev->dev->parent);
|
||||
acpi_status status;
|
||||
union acpi_object args[3];
|
||||
struct acpi_object_list arg_list = {
|
||||
.pointer = args,
|
||||
.count = ARRAY_SIZE(args),
|
||||
};
|
||||
|
||||
args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
|
||||
args[1].integer.value = 0x04;
|
||||
|
||||
if (strcmp(priv->acpi_method, "SPIN") == 0) {
|
||||
args[0].integer.value = 0;
|
||||
args[2].integer.value = brightness ? 1 : 0;
|
||||
} else if (strcmp(priv->acpi_method, "WPIN") == 0) {
|
||||
args[0].integer.value = 1;
|
||||
args[2].integer.value = brightness ? 0 : 1;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = acpi_evaluate_object(priv->handle, priv->acpi_method, &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENXIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int huawei_wmi_leds_setup(struct wmi_device *wdev)
|
||||
{
|
||||
struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
|
||||
priv->handle = ec_get_handle();
|
||||
if (!priv->handle)
|
||||
return 0;
|
||||
|
||||
if (acpi_has_method(priv->handle, "SPIN"))
|
||||
priv->acpi_method = "SPIN";
|
||||
else if (acpi_has_method(priv->handle, "WPIN"))
|
||||
priv->acpi_method = "WPIN";
|
||||
else
|
||||
return 0;
|
||||
|
||||
priv->cdev.name = "platform::micmute";
|
||||
priv->cdev.max_brightness = 1;
|
||||
priv->cdev.brightness_set_blocking = huawei_wmi_micmute_led_set;
|
||||
priv->cdev.default_trigger = "audio-micmute";
|
||||
priv->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
|
||||
priv->cdev.dev = &wdev->dev;
|
||||
priv->cdev.flags = LED_CORE_SUSPENDRESUME;
|
||||
|
||||
return devm_led_classdev_register(&wdev->dev, &priv->cdev);
|
||||
}
|
||||
|
||||
static void huawei_wmi_process_key(struct wmi_device *wdev, int code)
|
||||
{
|
||||
struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
const struct key_entry *key;
|
||||
|
||||
/*
|
||||
* WMI0 uses code 0x80 to indicate a hotkey event.
|
||||
* The actual key is fetched from the method WQ00
|
||||
* using WMI0_EXPENSIVE_GUID.
|
||||
*/
|
||||
if (code == 0x80) {
|
||||
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
|
||||
status = wmi_query_block(WMI0_EXPENSIVE_GUID, 0, &response);
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
|
||||
obj = (union acpi_object *)response.pointer;
|
||||
if (obj && obj->type == ACPI_TYPE_INTEGER)
|
||||
code = obj->integer.value;
|
||||
|
||||
kfree(response.pointer);
|
||||
}
|
||||
|
||||
key = sparse_keymap_entry_from_scancode(priv->idev, code);
|
||||
if (!key) {
|
||||
dev_info(&wdev->dev, "Unknown key pressed, code: 0x%04x\n", code);
|
||||
return;
|
||||
}
|
||||
|
||||
sparse_keymap_report_entry(priv->idev, key, 1, true);
|
||||
}
|
||||
|
||||
static void huawei_wmi_notify(struct wmi_device *wdev,
|
||||
union acpi_object *obj)
|
||||
{
|
||||
if (obj->type == ACPI_TYPE_INTEGER)
|
||||
huawei_wmi_process_key(wdev, obj->integer.value);
|
||||
else
|
||||
dev_info(&wdev->dev, "Bad response type %d\n", obj->type);
|
||||
}
|
||||
|
||||
static int huawei_wmi_input_setup(struct wmi_device *wdev)
|
||||
{
|
||||
struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
|
||||
int err;
|
||||
|
||||
priv->idev = devm_input_allocate_device(&wdev->dev);
|
||||
if (!priv->idev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->idev->name = "Huawei WMI hotkeys";
|
||||
priv->idev->phys = "wmi/input0";
|
||||
priv->idev->id.bustype = BUS_HOST;
|
||||
priv->idev->dev.parent = &wdev->dev;
|
||||
|
||||
err = sparse_keymap_setup(priv->idev, huawei_wmi_keymap, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return input_register_device(priv->idev);
|
||||
}
|
||||
|
||||
static int huawei_wmi_probe(struct wmi_device *wdev)
|
||||
{
|
||||
struct huawei_wmi_priv *priv;
|
||||
int err;
|
||||
|
||||
priv = devm_kzalloc(&wdev->dev, sizeof(struct huawei_wmi_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&wdev->dev, priv);
|
||||
|
||||
err = huawei_wmi_input_setup(wdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return huawei_wmi_leds_setup(wdev);
|
||||
}
|
||||
|
||||
static const struct wmi_device_id huawei_wmi_id_table[] = {
|
||||
{ .guid_string = WMI0_EVENT_GUID },
|
||||
{ .guid_string = AMW0_EVENT_GUID },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct wmi_driver huawei_wmi_driver = {
|
||||
.driver = {
|
||||
.name = "huawei-wmi",
|
||||
},
|
||||
.id_table = huawei_wmi_id_table,
|
||||
.probe = huawei_wmi_probe,
|
||||
.notify = huawei_wmi_notify,
|
||||
};
|
||||
|
||||
module_wmi_driver(huawei_wmi_driver);
|
||||
|
||||
MODULE_ALIAS("wmi:"WMI0_EVENT_GUID);
|
||||
MODULE_ALIAS("wmi:"AMW0_EVENT_GUID);
|
||||
MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
|
||||
MODULE_DESCRIPTION("Huawei WMI hotkeys");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -81,7 +81,6 @@
|
|||
#include <linux/acpi.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/thinkpad_acpi.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/initval.h>
|
||||
|
@ -9131,6 +9130,7 @@ static struct ibm_struct fan_driver_data = {
|
|||
* Mute LED subdriver
|
||||
*/
|
||||
|
||||
#define TPACPI_LED_MAX 2
|
||||
|
||||
struct tp_led_table {
|
||||
acpi_string name;
|
||||
|
@ -9139,13 +9139,13 @@ struct tp_led_table {
|
|||
int state;
|
||||
};
|
||||
|
||||
static struct tp_led_table led_tables[] = {
|
||||
[TPACPI_LED_MUTE] = {
|
||||
static struct tp_led_table led_tables[TPACPI_LED_MAX] = {
|
||||
[LED_AUDIO_MUTE] = {
|
||||
.name = "SSMS",
|
||||
.on_value = 1,
|
||||
.off_value = 0,
|
||||
},
|
||||
[TPACPI_LED_MICMUTE] = {
|
||||
[LED_AUDIO_MICMUTE] = {
|
||||
.name = "MMTS",
|
||||
.on_value = 2,
|
||||
.off_value = 0,
|
||||
|
@ -9170,31 +9170,64 @@ static int mute_led_on_off(struct tp_led_table *t, bool state)
|
|||
return state;
|
||||
}
|
||||
|
||||
int tpacpi_led_set(int whichled, bool on)
|
||||
static int tpacpi_led_set(int whichled, bool on)
|
||||
{
|
||||
struct tp_led_table *t;
|
||||
|
||||
if (whichled < 0 || whichled >= TPACPI_LED_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
t = &led_tables[whichled];
|
||||
if (t->state < 0 || t->state == on)
|
||||
return t->state;
|
||||
return mute_led_on_off(t, on);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpacpi_led_set);
|
||||
|
||||
static int tpacpi_led_mute_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
return tpacpi_led_set(LED_AUDIO_MUTE, brightness != LED_OFF);
|
||||
}
|
||||
|
||||
static int tpacpi_led_micmute_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
return tpacpi_led_set(LED_AUDIO_MICMUTE, brightness != LED_OFF);
|
||||
}
|
||||
|
||||
static struct led_classdev mute_led_cdev[TPACPI_LED_MAX] = {
|
||||
[LED_AUDIO_MUTE] = {
|
||||
.name = "platform::mute",
|
||||
.max_brightness = 1,
|
||||
.brightness_set_blocking = tpacpi_led_mute_set,
|
||||
.default_trigger = "audio-mute",
|
||||
},
|
||||
[LED_AUDIO_MICMUTE] = {
|
||||
.name = "platform::micmute",
|
||||
.max_brightness = 1,
|
||||
.brightness_set_blocking = tpacpi_led_micmute_set,
|
||||
.default_trigger = "audio-micmute",
|
||||
},
|
||||
};
|
||||
|
||||
static int mute_led_init(struct ibm_init_struct *iibm)
|
||||
{
|
||||
acpi_handle temp;
|
||||
int i;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < TPACPI_LED_MAX; i++) {
|
||||
struct tp_led_table *t = &led_tables[i];
|
||||
if (ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp)))
|
||||
mute_led_on_off(t, false);
|
||||
else
|
||||
if (ACPI_FAILURE(acpi_get_handle(hkey_handle, t->name, &temp))) {
|
||||
t->state = -ENODEV;
|
||||
continue;
|
||||
}
|
||||
|
||||
mute_led_cdev[i].brightness = ledtrig_audio_get(i);
|
||||
err = led_classdev_register(&tpacpi_pdev->dev, &mute_led_cdev[i]);
|
||||
if (err < 0) {
|
||||
while (i--) {
|
||||
if (led_tables[i].state >= 0)
|
||||
led_classdev_unregister(&mute_led_cdev[i]);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -9203,8 +9236,12 @@ static void mute_led_exit(void)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TPACPI_LED_MAX; i++)
|
||||
tpacpi_led_set(i, false);
|
||||
for (i = 0; i < TPACPI_LED_MAX; i++) {
|
||||
if (led_tables[i].state >= 0) {
|
||||
led_classdev_unregister(&mute_led_cdev[i]);
|
||||
tpacpi_led_set(i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mute_led_resume(void)
|
||||
|
|
|
@ -106,6 +106,7 @@
|
|||
#define QUINARY_TDM_TX_6 101
|
||||
#define QUINARY_TDM_RX_7 102
|
||||
#define QUINARY_TDM_TX_7 103
|
||||
#define DISPLAY_PORT_RX 104
|
||||
|
||||
#endif /* __DT_BINDINGS_Q6_AFE_H__ */
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __DELL_LED_H__
|
||||
#define __DELL_LED_H__
|
||||
|
||||
int dell_micmute_led_set(int on);
|
||||
|
||||
#endif
|
|
@ -487,4 +487,24 @@ struct led_pattern {
|
|||
int brightness;
|
||||
};
|
||||
|
||||
enum led_audio {
|
||||
LED_AUDIO_MUTE, /* master mute LED */
|
||||
LED_AUDIO_MICMUTE, /* mic mute LED */
|
||||
NUM_AUDIO_LEDS
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_LEDS_TRIGGER_AUDIO)
|
||||
enum led_brightness ledtrig_audio_get(enum led_audio type);
|
||||
void ledtrig_audio_set(enum led_audio type, enum led_brightness state);
|
||||
#else
|
||||
static inline enum led_brightness ledtrig_audio_get(enum led_audio type)
|
||||
{
|
||||
return LED_OFF;
|
||||
}
|
||||
static inline void ledtrig_audio_set(enum led_audio type,
|
||||
enum led_brightness state)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_LEDS_H_INCLUDED */
|
||||
|
|
|
@ -79,6 +79,7 @@ struct davinci_mcasp_pdata {
|
|||
/* McASP specific fields */
|
||||
int tdm_slots;
|
||||
u8 op_mode;
|
||||
u8 dismod;
|
||||
u8 num_serializer;
|
||||
u8 *serial_dir;
|
||||
u8 version;
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __THINKPAD_ACPI_H__
|
||||
#define __THINKPAD_ACPI_H__
|
||||
|
||||
/* These two functions return 0 if success, or negative error code
|
||||
(e g -ENODEV if no led present) */
|
||||
|
||||
enum {
|
||||
TPACPI_LED_MUTE,
|
||||
TPACPI_LED_MICMUTE,
|
||||
TPACPI_LED_MAX,
|
||||
};
|
||||
|
||||
int tpacpi_led_set(int whichled, bool on);
|
||||
|
||||
#endif
|
|
@ -23,6 +23,7 @@ struct snd_compr_ops;
|
|||
* struct snd_compr_runtime: runtime stream description
|
||||
* @state: stream state
|
||||
* @ops: pointer to DSP callbacks
|
||||
* @dma_buffer_p: runtime dma buffer pointer
|
||||
* @buffer: pointer to kernel buffer, valid only when not in mmap mode or
|
||||
* DSP doesn't implement copy
|
||||
* @buffer_size: size of the above buffer
|
||||
|
@ -37,6 +38,7 @@ struct snd_compr_ops;
|
|||
struct snd_compr_runtime {
|
||||
snd_pcm_state_t state;
|
||||
struct snd_compr_ops *ops;
|
||||
struct snd_dma_buffer *dma_buffer_p;
|
||||
void *buffer;
|
||||
u64 buffer_size;
|
||||
u32 fragment_size;
|
||||
|
@ -175,6 +177,23 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
|
|||
wake_up(&stream->runtime->sleep);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_compr_set_runtime_buffer - Set the Compress runtime buffer
|
||||
* @substream: compress substream to set
|
||||
* @bufp: the buffer information, NULL to clear
|
||||
*
|
||||
* Copy the buffer information to runtime buffer when @bufp is non-NULL.
|
||||
* Otherwise it clears the current buffer information.
|
||||
*/
|
||||
static inline void snd_compr_set_runtime_buffer(
|
||||
struct snd_compr_stream *substream,
|
||||
struct snd_dma_buffer *bufp)
|
||||
{
|
||||
struct snd_compr_runtime *runtime = substream->runtime;
|
||||
|
||||
runtime->dma_buffer_p = bufp;
|
||||
}
|
||||
|
||||
int snd_compr_stop_error(struct snd_compr_stream *stream,
|
||||
snd_pcm_state_t state);
|
||||
|
||||
|
|
|
@ -236,6 +236,7 @@ struct hda_codec {
|
|||
/* misc flags */
|
||||
unsigned int in_freeing:1; /* being released */
|
||||
unsigned int registered:1; /* codec was registered */
|
||||
unsigned int display_power_control:1; /* needs display power */
|
||||
unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
|
||||
* status change
|
||||
* (e.g. Realtek codecs)
|
||||
|
|
|
@ -5,10 +5,15 @@
|
|||
#define __SOUND_HDA_COMPONENT_H
|
||||
|
||||
#include <drm/drm_audio_component.h>
|
||||
#include <sound/hdaudio.h>
|
||||
|
||||
/* virtual idx for controller */
|
||||
#define HDA_CODEC_IDX_CONTROLLER HDA_MAX_CODECS
|
||||
|
||||
#ifdef CONFIG_SND_HDA_COMPONENT
|
||||
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
|
||||
int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
|
||||
void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx,
|
||||
bool enable);
|
||||
int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
|
||||
int dev_id, int rate);
|
||||
int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
|
||||
|
@ -25,9 +30,9 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
|
||||
static inline void snd_hdac_display_power(struct hdac_bus *bus,
|
||||
unsigned int idx, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
|
||||
hda_nid_t nid, int dev_id, int rate)
|
||||
|
|
|
@ -79,7 +79,6 @@ struct hdac_device {
|
|||
|
||||
/* misc flags */
|
||||
atomic_t in_pm; /* suspend/resume being performed */
|
||||
bool link_power_control:1;
|
||||
|
||||
/* sysfs */
|
||||
struct hdac_widget_tree *widgets;
|
||||
|
@ -99,6 +98,12 @@ enum {
|
|||
HDA_DEV_ASOC,
|
||||
};
|
||||
|
||||
enum {
|
||||
SND_SKL_PCI_BIND_AUTO, /* automatic selection based on pci class */
|
||||
SND_SKL_PCI_BIND_LEGACY,/* bind only with legacy driver */
|
||||
SND_SKL_PCI_BIND_ASOC /* bind only with ASoC driver */
|
||||
};
|
||||
|
||||
/* direction */
|
||||
enum {
|
||||
HDA_INPUT, HDA_OUTPUT
|
||||
|
@ -237,8 +242,6 @@ struct hdac_bus_ops {
|
|||
/* get a response from the last command */
|
||||
int (*get_response)(struct hdac_bus *bus, unsigned int addr,
|
||||
unsigned int *res);
|
||||
/* control the link power */
|
||||
int (*link_power)(struct hdac_bus *bus, bool enable);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -363,7 +366,8 @@ struct hdac_bus {
|
|||
|
||||
/* DRM component interface */
|
||||
struct drm_audio_component *audio_component;
|
||||
int drm_power_refcount;
|
||||
long display_power_status;
|
||||
bool display_power_active;
|
||||
|
||||
/* parameters required for enhanced capabilities */
|
||||
int num_streams;
|
||||
|
@ -389,6 +393,7 @@ void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex);
|
|||
int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec);
|
||||
void snd_hdac_bus_remove_device(struct hdac_bus *bus,
|
||||
struct hdac_device *codec);
|
||||
void snd_hdac_bus_process_unsol_events(struct work_struct *work);
|
||||
|
||||
static inline void snd_hdac_codec_link_up(struct hdac_device *codec)
|
||||
{
|
||||
|
@ -404,7 +409,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
|
|||
int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
|
||||
unsigned int *res);
|
||||
int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus);
|
||||
int snd_hdac_link_power(struct hdac_device *codec, bool enable);
|
||||
|
||||
bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset);
|
||||
void snd_hdac_bus_stop_chip(struct hdac_bus *bus);
|
||||
|
|
|
@ -116,12 +116,12 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card);
|
|||
|
||||
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
|
||||
struct snd_pcm_hw_params *params);
|
||||
void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
|
||||
void asoc_simple_card_parse_convert(struct device *dev,
|
||||
struct device_node *np, char *prefix,
|
||||
struct asoc_simple_card_data *data);
|
||||
|
||||
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
|
||||
char *prefix,
|
||||
int optional);
|
||||
char *prefix);
|
||||
int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
|
||||
char *prefix);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[];
|
|||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[];
|
||||
|
||||
/*
|
||||
* generic table used for HDA codec-based platforms, possibly with
|
||||
|
|
|
@ -37,6 +37,20 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
|
|||
struct snd_soc_acpi_mach *
|
||||
snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines);
|
||||
|
||||
/**
|
||||
* snd_soc_acpi_mach_params: interface for machine driver configuration
|
||||
*
|
||||
* @acpi_ipc_irq_index: used for BYT-CR detection
|
||||
* @platform: string used for HDaudio codec support
|
||||
* @codec_mask: used for HDAudio support
|
||||
*/
|
||||
struct snd_soc_acpi_mach_params {
|
||||
u32 acpi_ipc_irq_index;
|
||||
const char *platform;
|
||||
u32 codec_mask;
|
||||
u32 dmic_num;
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are
|
||||
* related to the hardware, except for the firmware and topology file names.
|
||||
|
@ -68,6 +82,7 @@ struct snd_soc_acpi_mach {
|
|||
struct snd_soc_acpi_mach * (*machine_quirk)(void *arg);
|
||||
const void *quirk_data;
|
||||
void *pdata;
|
||||
struct snd_soc_acpi_mach_params mach_params;
|
||||
const char *sof_fw_filename;
|
||||
const char *sof_tplg_filename;
|
||||
const char *asoc_plat_name;
|
||||
|
|
|
@ -553,12 +553,12 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_SOC_AC97_BUS
|
||||
struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component);
|
||||
struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
|
||||
unsigned int id, unsigned int id_mask);
|
||||
void snd_soc_free_ac97_component(struct snd_ac97 *ac97);
|
||||
|
||||
#ifdef CONFIG_SND_SOC_AC97_BUS
|
||||
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
|
||||
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
|
||||
struct platform_device *pdev);
|
||||
|
@ -1477,10 +1477,20 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
|
|||
unsigned int *rx_mask,
|
||||
unsigned int *slots,
|
||||
unsigned int *slot_width);
|
||||
void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
|
||||
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);
|
||||
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e617475
|
||||
#define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c
|
||||
#define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479
|
||||
#define SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL 0x7473636d
|
||||
|
||||
struct snd_firewire_event_common {
|
||||
unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
|
||||
|
@ -53,12 +54,24 @@ struct snd_firewire_event_motu_notification {
|
|||
__u32 message; /* MOTU-specific bits. */
|
||||
};
|
||||
|
||||
struct snd_firewire_tascam_change {
|
||||
unsigned int index;
|
||||
__be32 before;
|
||||
__be32 after;
|
||||
};
|
||||
|
||||
struct snd_firewire_event_tascam_control {
|
||||
unsigned int type;
|
||||
struct snd_firewire_tascam_change changes[0];
|
||||
};
|
||||
|
||||
union snd_firewire_event {
|
||||
struct snd_firewire_event_common common;
|
||||
struct snd_firewire_event_lock_status lock_status;
|
||||
struct snd_firewire_event_dice_notification dice_notification;
|
||||
struct snd_firewire_event_efw_response efw_response;
|
||||
struct snd_firewire_event_digi00x_message digi00x_message;
|
||||
struct snd_firewire_event_tascam_control tascam_control;
|
||||
struct snd_firewire_event_motu_notification motu_notification;
|
||||
};
|
||||
|
||||
|
@ -66,6 +79,7 @@ union snd_firewire_event {
|
|||
#define SNDRV_FIREWIRE_IOCTL_GET_INFO _IOR('H', 0xf8, struct snd_firewire_get_info)
|
||||
#define SNDRV_FIREWIRE_IOCTL_LOCK _IO('H', 0xf9)
|
||||
#define SNDRV_FIREWIRE_IOCTL_UNLOCK _IO('H', 0xfa)
|
||||
#define SNDRV_FIREWIRE_IOCTL_TASCAM_STATE _IOR('H', 0xfb, struct snd_firewire_tascam_state)
|
||||
|
||||
#define SNDRV_FIREWIRE_TYPE_DICE 1
|
||||
#define SNDRV_FIREWIRE_TYPE_FIREWORKS 2
|
||||
|
@ -88,4 +102,10 @@ struct snd_firewire_get_info {
|
|||
* Returns -EBUSY if the driver is already streaming.
|
||||
*/
|
||||
|
||||
#define SNDRV_FIREWIRE_TASCAM_STATE_COUNT 64
|
||||
|
||||
struct snd_firewire_tascam_state {
|
||||
__be32 data[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
|
||||
};
|
||||
|
||||
#endif /* _UAPI_SOUND_FIREWIRE_H_INCLUDED */
|
||||
|
|
|
@ -776,7 +776,7 @@ static int check_codec(struct aoa_codec *codec,
|
|||
struct codec_connection *cc;
|
||||
|
||||
/* if the codec has a 'codec' node, we require a reference */
|
||||
if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
|
||||
if (of_node_name_eq(codec->node, "codec")) {
|
||||
snprintf(propname, sizeof(propname),
|
||||
"platform-%s-codec-ref", codec->name);
|
||||
ref = of_get_property(ldev->sound, propname, NULL);
|
||||
|
@ -1008,8 +1008,8 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
|
|||
return -ENODEV;
|
||||
|
||||
/* by breaking out we keep a reference */
|
||||
while ((sound = of_get_next_child(sdev->ofdev.dev.of_node, sound))) {
|
||||
if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
|
||||
for_each_child_of_node(sdev->ofdev.dev.of_node, sound) {
|
||||
if (of_node_is_type(sound, "soundchip"))
|
||||
break;
|
||||
}
|
||||
if (!sound)
|
||||
|
|
|
@ -74,11 +74,11 @@ static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
of = &soundbus_dev->ofdev;
|
||||
|
||||
/* stuff we want to pass to /sbin/hotplug */
|
||||
retval = add_uevent_var(env, "OF_NAME=%s", of->dev.of_node->name);
|
||||
retval = add_uevent_var(env, "OF_NAME=%pOFn", of->dev.of_node);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = add_uevent_var(env, "OF_TYPE=%s", of->dev.of_node->type);
|
||||
retval = add_uevent_var(env, "OF_TYPE=%s", of_node_get_device_type(of->dev.of_node));
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
|||
struct device_node *np)
|
||||
{
|
||||
struct i2sbus_dev *dev;
|
||||
struct device_node *child = NULL, *sound = NULL;
|
||||
struct device_node *child, *sound = NULL;
|
||||
struct resource *r;
|
||||
int i, layout = 0, rlen, ok = force;
|
||||
char node_name[6];
|
||||
|
@ -177,8 +177,8 @@ static int i2sbus_add_dev(struct macio_dev *macio,
|
|||
return 0;
|
||||
|
||||
i = 0;
|
||||
while ((child = of_get_next_child(np, child))) {
|
||||
if (strcmp(child->name, "sound") == 0) {
|
||||
for_each_child_of_node(np, child) {
|
||||
if (of_node_name_eq(child, "sound")) {
|
||||
i++;
|
||||
sound = child;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/stat.h>
|
||||
/* FIX UP */
|
||||
#include "soundbus.h"
|
||||
|
||||
#define soundbus_config_of_attr(field, format_string) \
|
||||
static ssize_t \
|
||||
field##_show (struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct soundbus_dev *mdev = to_soundbus_device (dev); \
|
||||
return sprintf (buf, format_string, mdev->ofdev.dev.of_node->field); \
|
||||
}
|
||||
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
|
@ -25,17 +17,33 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
|||
strcat(buf, "\n");
|
||||
length = strlen(buf);
|
||||
} else {
|
||||
length = sprintf(buf, "of:N%sT%s\n",
|
||||
of->dev.of_node->name, of->dev.of_node->type);
|
||||
length = sprintf(buf, "of:N%pOFn%c%s\n",
|
||||
of->dev.of_node, 'T',
|
||||
of_node_get_device_type(of->dev.of_node));
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
soundbus_config_of_attr (name, "%s\n");
|
||||
static ssize_t name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct soundbus_dev *sdev = to_soundbus_device(dev);
|
||||
struct platform_device *of = &sdev->ofdev;
|
||||
|
||||
return sprintf(buf, "%pOFn\n", of->dev.of_node);
|
||||
}
|
||||
static DEVICE_ATTR_RO(name);
|
||||
soundbus_config_of_attr (type, "%s\n");
|
||||
|
||||
static ssize_t type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct soundbus_dev *sdev = to_soundbus_device(dev);
|
||||
struct platform_device *of = &sdev->ofdev;
|
||||
|
||||
return sprintf(buf, "%s\n", of_node_get_device_type(of->dev.of_node));
|
||||
}
|
||||
static DEVICE_ATTR_RO(type);
|
||||
|
||||
struct attribute *soundbus_dev_attrs[] = {
|
||||
|
|
|
@ -171,7 +171,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
|
|||
}
|
||||
|
||||
data->stream.ops->free(&data->stream);
|
||||
kfree(data->stream.runtime->buffer);
|
||||
if (!data->stream.runtime->dma_buffer_p)
|
||||
kfree(data->stream.runtime->buffer);
|
||||
kfree(data->stream.runtime);
|
||||
kfree(data);
|
||||
return 0;
|
||||
|
@ -505,7 +506,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
|
|||
struct snd_compr_params *params)
|
||||
{
|
||||
unsigned int buffer_size;
|
||||
void *buffer;
|
||||
void *buffer = NULL;
|
||||
|
||||
buffer_size = params->buffer.fragment_size * params->buffer.fragments;
|
||||
if (stream->ops->copy) {
|
||||
|
@ -514,7 +515,18 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
|
|||
* the data from core
|
||||
*/
|
||||
} else {
|
||||
buffer = kmalloc(buffer_size, GFP_KERNEL);
|
||||
if (stream->runtime->dma_buffer_p) {
|
||||
|
||||
if (buffer_size > stream->runtime->dma_buffer_p->bytes)
|
||||
dev_err(&stream->device->dev,
|
||||
"Not enough DMA buffer");
|
||||
else
|
||||
buffer = stream->runtime->dma_buffer_p->area;
|
||||
|
||||
} else {
|
||||
buffer = kmalloc(buffer_size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
|
@ -348,22 +348,41 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* add a new kcontrol object; call with card->controls_rwsem locked */
|
||||
static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
||||
enum snd_ctl_add_mode {
|
||||
CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE,
|
||||
};
|
||||
|
||||
/* add/replace a new kcontrol object; call with card->controls_rwsem locked */
|
||||
static int __snd_ctl_add_replace(struct snd_card *card,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
enum snd_ctl_add_mode mode)
|
||||
{
|
||||
struct snd_ctl_elem_id id;
|
||||
unsigned int idx;
|
||||
unsigned int count;
|
||||
struct snd_kcontrol *old;
|
||||
int err;
|
||||
|
||||
id = kcontrol->id;
|
||||
if (id.index > UINT_MAX - kcontrol->count)
|
||||
return -EINVAL;
|
||||
|
||||
if (snd_ctl_find_id(card, &id)) {
|
||||
dev_err(card->dev,
|
||||
"control %i:%i:%i:%s:%i is already present\n",
|
||||
id.iface, id.device, id.subdevice, id.name, id.index);
|
||||
return -EBUSY;
|
||||
old = snd_ctl_find_id(card, &id);
|
||||
if (!old) {
|
||||
if (mode == CTL_REPLACE)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (mode == CTL_ADD_EXCLUSIVE) {
|
||||
dev_err(card->dev,
|
||||
"control %i:%i:%i:%s:%i is already present\n",
|
||||
id.iface, id.device, id.subdevice, id.name,
|
||||
id.index);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
err = snd_ctl_remove(card, old);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (snd_ctl_find_hole(card, kcontrol->count) < 0)
|
||||
|
@ -382,6 +401,29 @@ static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ctl_add_replace(struct snd_card *card,
|
||||
struct snd_kcontrol *kcontrol,
|
||||
enum snd_ctl_add_mode mode)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
|
||||
if (! kcontrol)
|
||||
return err;
|
||||
if (snd_BUG_ON(!card || !kcontrol->info))
|
||||
goto error;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
err = __snd_ctl_add_replace(card, kcontrol, mode);
|
||||
up_write(&card->controls_rwsem);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
snd_ctl_free_one(kcontrol);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_ctl_add - add the control instance to the card
|
||||
* @card: the card instance
|
||||
|
@ -398,23 +440,7 @@ static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|||
*/
|
||||
int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
|
||||
if (! kcontrol)
|
||||
return err;
|
||||
if (snd_BUG_ON(!card || !kcontrol->info))
|
||||
goto error;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
err = __snd_ctl_add(card, kcontrol);
|
||||
up_write(&card->controls_rwsem);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
snd_ctl_free_one(kcontrol);
|
||||
return err;
|
||||
return snd_ctl_add_replace(card, kcontrol, CTL_ADD_EXCLUSIVE);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_add);
|
||||
|
||||
|
@ -435,53 +461,8 @@ EXPORT_SYMBOL(snd_ctl_add);
|
|||
int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
|
||||
bool add_on_replace)
|
||||
{
|
||||
struct snd_ctl_elem_id id;
|
||||
unsigned int count;
|
||||
unsigned int idx;
|
||||
struct snd_kcontrol *old;
|
||||
int ret;
|
||||
|
||||
if (!kcontrol)
|
||||
return -EINVAL;
|
||||
if (snd_BUG_ON(!card || !kcontrol->info)) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
id = kcontrol->id;
|
||||
down_write(&card->controls_rwsem);
|
||||
old = snd_ctl_find_id(card, &id);
|
||||
if (!old) {
|
||||
if (add_on_replace)
|
||||
goto add;
|
||||
up_write(&card->controls_rwsem);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
ret = snd_ctl_remove(card, old);
|
||||
if (ret < 0) {
|
||||
up_write(&card->controls_rwsem);
|
||||
goto error;
|
||||
}
|
||||
add:
|
||||
if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
|
||||
up_write(&card->controls_rwsem);
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
list_add_tail(&kcontrol->list, &card->controls);
|
||||
card->controls_count += kcontrol->count;
|
||||
kcontrol->id.numid = card->last_numid + 1;
|
||||
card->last_numid += kcontrol->count;
|
||||
id = kcontrol->id;
|
||||
count = kcontrol->count;
|
||||
up_write(&card->controls_rwsem);
|
||||
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
snd_ctl_free_one(kcontrol);
|
||||
return ret;
|
||||
return snd_ctl_add_replace(card, kcontrol,
|
||||
add_on_replace ? CTL_ADD_ON_REPLACE : CTL_REPLACE);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_replace);
|
||||
|
||||
|
@ -1369,7 +1350,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
|||
|
||||
/* This function manage to free the instance on failure. */
|
||||
down_write(&card->controls_rwsem);
|
||||
err = __snd_ctl_add(card, kctl);
|
||||
err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE);
|
||||
if (err < 0) {
|
||||
snd_ctl_free_one(kctl);
|
||||
goto unlock;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/time.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/minors.h>
|
||||
#include <sound/pcm.h>
|
||||
|
@ -129,6 +130,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
|
|||
return -EFAULT;
|
||||
if (stream < 0 || stream > 1)
|
||||
return -EINVAL;
|
||||
stream = array_index_nospec(stream, 2);
|
||||
if (get_user(subdevice, &info->subdevice))
|
||||
return -EFAULT;
|
||||
mutex_lock(®ister_mutex);
|
||||
|
|
|
@ -41,6 +41,7 @@ config SND_OXFW
|
|||
* Mackie(Loud) U.420/U.420d
|
||||
* TASCAM FireOne
|
||||
* Stanton Controllers & Systems 1 Deck/Mixer
|
||||
* APOGEE duet FireWire
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-oxfw.
|
||||
|
@ -161,5 +162,6 @@ config SND_FIREFACE
|
|||
help
|
||||
Say Y here to include support for RME fireface series.
|
||||
* Fireface 400
|
||||
* Fireface 800
|
||||
|
||||
endif # SND_FIREWIRE
|
||||
|
|
|
@ -131,7 +131,7 @@ TRACE_EVENT(in_packet_without_header,
|
|||
__entry->index = index;
|
||||
),
|
||||
TP_printk(
|
||||
"%02u %04u %04x %04x %02d %03u %3u %3u %02u %01u %02u",
|
||||
"%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
|
||||
__entry->second,
|
||||
__entry->cycle,
|
||||
__entry->src,
|
||||
|
@ -169,7 +169,7 @@ TRACE_EVENT(out_packet_without_header,
|
|||
__entry->dest = fw_parent_device(s->unit)->node_id;
|
||||
__entry->payload_quadlets = payload_length / 4;
|
||||
__entry->data_blocks = data_blocks,
|
||||
__entry->data_blocks = s->data_block_counter,
|
||||
__entry->data_block_counter = s->data_block_counter,
|
||||
__entry->packet_index = s->packet_index;
|
||||
__entry->irq = !!in_interrupt();
|
||||
__entry->index = index;
|
||||
|
|
|
@ -654,15 +654,17 @@ end:
|
|||
}
|
||||
|
||||
static int handle_in_packet_without_header(struct amdtp_stream *s,
|
||||
unsigned int payload_quadlets, unsigned int cycle,
|
||||
unsigned int payload_length, unsigned int cycle,
|
||||
unsigned int index)
|
||||
{
|
||||
__be32 *buffer;
|
||||
unsigned int payload_quadlets;
|
||||
unsigned int data_blocks;
|
||||
struct snd_pcm_substream *pcm;
|
||||
unsigned int pcm_frames;
|
||||
|
||||
buffer = s->buffer.packets[s->packet_index].buffer;
|
||||
payload_quadlets = payload_length / 4;
|
||||
data_blocks = payload_quadlets / s->data_block_quadlets;
|
||||
|
||||
trace_in_packet_without_header(s, cycle, payload_quadlets, data_blocks,
|
||||
|
|
|
@ -408,7 +408,7 @@ static const struct ieee1394_device_id bebob_id_table[] = {
|
|||
/* Apogee Electronics, DA/AD/DD-16X (X-FireWire card) */
|
||||
SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x00010048, &spec_normal),
|
||||
/* Apogee Electronics, Ensemble */
|
||||
SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x00001eee, &spec_normal),
|
||||
SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x01eeee, &spec_normal),
|
||||
/* ESI, Quatafire610 */
|
||||
SND_BEBOB_DEV_ENTRY(VEN_ESI, 0x00010064, &spec_normal),
|
||||
/* AcousticReality, eARMasterOne */
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \
|
||||
ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o
|
||||
ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o \
|
||||
ff-protocol-ff800.o
|
||||
obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o
|
||||
|
|
|
@ -8,11 +8,6 @@
|
|||
|
||||
#include "ff.h"
|
||||
|
||||
static inline unsigned int get_multiplier_mode_with_index(unsigned int index)
|
||||
{
|
||||
return ((int)index - 1) / 2;
|
||||
}
|
||||
|
||||
static int hw_rule_rate(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
|
@ -24,10 +19,16 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
|
|||
struct snd_interval t = {
|
||||
.min = UINT_MAX, .max = 0, .integer = 1
|
||||
};
|
||||
unsigned int i, mode;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
|
||||
mode = get_multiplier_mode_with_index(i);
|
||||
enum snd_ff_stream_mode mode;
|
||||
int err;
|
||||
|
||||
err = snd_ff_stream_get_multiplier_mode(i, &mode);
|
||||
if (err < 0)
|
||||
continue;
|
||||
|
||||
if (!snd_interval_test(c, pcm_channels[mode]))
|
||||
continue;
|
||||
|
||||
|
@ -49,10 +50,16 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
|
|||
struct snd_interval t = {
|
||||
.min = UINT_MAX, .max = 0, .integer = 1
|
||||
};
|
||||
unsigned int i, mode;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
|
||||
mode = get_multiplier_mode_with_index(i);
|
||||
enum snd_ff_stream_mode mode;
|
||||
int err;
|
||||
|
||||
err = snd_ff_stream_get_multiplier_mode(i, &mode);
|
||||
if (err < 0)
|
||||
continue;
|
||||
|
||||
if (!snd_interval_test(r, amdtp_rate_table[i]))
|
||||
continue;
|
||||
|
||||
|
@ -66,7 +73,6 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
|
|||
static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
|
||||
const unsigned int *pcm_channels)
|
||||
{
|
||||
unsigned int mode;
|
||||
unsigned int rate, channels;
|
||||
int i;
|
||||
|
||||
|
@ -76,7 +82,12 @@ static void limit_channels_and_rates(struct snd_pcm_hardware *hw,
|
|||
hw->rate_max = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); i++) {
|
||||
mode = get_multiplier_mode_with_index(i);
|
||||
enum snd_ff_stream_mode mode;
|
||||
int err;
|
||||
|
||||
err = snd_ff_stream_get_multiplier_mode(i, &mode);
|
||||
if (err < 0)
|
||||
continue;
|
||||
|
||||
channels = pcm_channels[mode];
|
||||
if (pcm_channels[mode] == 0)
|
||||
|
@ -141,7 +152,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
|
|||
if (err < 0)
|
||||
goto release_lock;
|
||||
|
||||
err = ff->spec->protocol->get_clock(ff, &rate, &src);
|
||||
err = snd_ff_transaction_get_clock(ff, &rate, &src);
|
||||
if (err < 0)
|
||||
goto release_lock;
|
||||
|
||||
|
|
|
@ -12,16 +12,205 @@ static void proc_dump_clock_config(struct snd_info_entry *entry,
|
|||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_ff *ff = entry->private_data;
|
||||
__le32 reg;
|
||||
u32 data;
|
||||
unsigned int rate;
|
||||
const char *src;
|
||||
int err;
|
||||
|
||||
ff->spec->protocol->dump_clock_config(ff, buffer);
|
||||
err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
|
||||
SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
data = le32_to_cpu(reg);
|
||||
|
||||
snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
|
||||
(data & 0x20) ? "Professional" : "Consumer",
|
||||
(data & 0x40) ? "on" : "off");
|
||||
|
||||
snd_iprintf(buffer, "Optical output interface format: %s\n",
|
||||
((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
|
||||
|
||||
snd_iprintf(buffer, "Word output single speed: %s\n",
|
||||
((data >> 8) & 0x20) ? "on" : "off");
|
||||
|
||||
snd_iprintf(buffer, "S/PDIF input interface: %s\n",
|
||||
((data >> 8) & 0x02) ? "Optical" : "Coaxial");
|
||||
|
||||
switch ((data >> 1) & 0x03) {
|
||||
case 0x01:
|
||||
rate = 32000;
|
||||
break;
|
||||
case 0x00:
|
||||
rate = 44100;
|
||||
break;
|
||||
case 0x03:
|
||||
rate = 48000;
|
||||
break;
|
||||
case 0x02:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (data & 0x08)
|
||||
rate *= 2;
|
||||
else if (data & 0x10)
|
||||
rate *= 4;
|
||||
|
||||
snd_iprintf(buffer, "Sampling rate: %d\n", rate);
|
||||
|
||||
if (data & 0x01) {
|
||||
src = "Internal";
|
||||
} else {
|
||||
switch ((data >> 10) & 0x07) {
|
||||
case 0x00:
|
||||
src = "ADAT1";
|
||||
break;
|
||||
case 0x01:
|
||||
src = "ADAT2";
|
||||
break;
|
||||
case 0x03:
|
||||
src = "S/PDIF";
|
||||
break;
|
||||
case 0x04:
|
||||
src = "Word";
|
||||
break;
|
||||
case 0x05:
|
||||
src = "LTC";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "Sync to clock source: %s\n", src);
|
||||
}
|
||||
|
||||
static void proc_dump_sync_status(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
struct snd_ff *ff = entry->private_data;
|
||||
__le32 reg;
|
||||
u32 data;
|
||||
int err;
|
||||
|
||||
ff->spec->protocol->dump_sync_status(ff, buffer);
|
||||
err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
|
||||
SND_FF_REG_SYNC_STATUS, ®, sizeof(reg), 0);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
data = le32_to_cpu(reg);
|
||||
|
||||
snd_iprintf(buffer, "External source detection:\n");
|
||||
|
||||
snd_iprintf(buffer, "Word Clock:");
|
||||
if ((data >> 24) & 0x20) {
|
||||
if ((data >> 24) & 0x40)
|
||||
snd_iprintf(buffer, "sync\n");
|
||||
else
|
||||
snd_iprintf(buffer, "lock\n");
|
||||
} else {
|
||||
snd_iprintf(buffer, "none\n");
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "S/PDIF:");
|
||||
if ((data >> 16) & 0x10) {
|
||||
if ((data >> 16) & 0x04)
|
||||
snd_iprintf(buffer, "sync\n");
|
||||
else
|
||||
snd_iprintf(buffer, "lock\n");
|
||||
} else {
|
||||
snd_iprintf(buffer, "none\n");
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "ADAT1:");
|
||||
if ((data >> 8) & 0x04) {
|
||||
if ((data >> 8) & 0x10)
|
||||
snd_iprintf(buffer, "sync\n");
|
||||
else
|
||||
snd_iprintf(buffer, "lock\n");
|
||||
} else {
|
||||
snd_iprintf(buffer, "none\n");
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "ADAT2:");
|
||||
if ((data >> 8) & 0x08) {
|
||||
if ((data >> 8) & 0x20)
|
||||
snd_iprintf(buffer, "sync\n");
|
||||
else
|
||||
snd_iprintf(buffer, "lock\n");
|
||||
} else {
|
||||
snd_iprintf(buffer, "none\n");
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "\nUsed external source:\n");
|
||||
|
||||
if (((data >> 22) & 0x07) == 0x07) {
|
||||
snd_iprintf(buffer, "None\n");
|
||||
} else {
|
||||
switch ((data >> 22) & 0x07) {
|
||||
case 0x00:
|
||||
snd_iprintf(buffer, "ADAT1:");
|
||||
break;
|
||||
case 0x01:
|
||||
snd_iprintf(buffer, "ADAT2:");
|
||||
break;
|
||||
case 0x03:
|
||||
snd_iprintf(buffer, "S/PDIF:");
|
||||
break;
|
||||
case 0x04:
|
||||
snd_iprintf(buffer, "Word:");
|
||||
break;
|
||||
case 0x07:
|
||||
snd_iprintf(buffer, "Nothing:");
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
default:
|
||||
snd_iprintf(buffer, "unknown:");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((data >> 25) & 0x07) {
|
||||
switch ((data >> 25) & 0x07) {
|
||||
case 0x01:
|
||||
snd_iprintf(buffer, "32000\n");
|
||||
break;
|
||||
case 0x02:
|
||||
snd_iprintf(buffer, "44100\n");
|
||||
break;
|
||||
case 0x03:
|
||||
snd_iprintf(buffer, "48000\n");
|
||||
break;
|
||||
case 0x04:
|
||||
snd_iprintf(buffer, "64000\n");
|
||||
break;
|
||||
case 0x05:
|
||||
snd_iprintf(buffer, "88200\n");
|
||||
break;
|
||||
case 0x06:
|
||||
snd_iprintf(buffer, "96000\n");
|
||||
break;
|
||||
case 0x07:
|
||||
snd_iprintf(buffer, "128000\n");
|
||||
break;
|
||||
case 0x08:
|
||||
snd_iprintf(buffer, "176400\n");
|
||||
break;
|
||||
case 0x09:
|
||||
snd_iprintf(buffer, "192000\n");
|
||||
break;
|
||||
case 0x00:
|
||||
snd_iprintf(buffer, "unknown\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "Multiplied:");
|
||||
snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
|
||||
}
|
||||
|
||||
static void add_node(struct snd_ff *ff, struct snd_info_entry *root,
|
||||
|
|
|
@ -14,85 +14,60 @@
|
|||
#define FF400_ISOC_COMM_START 0x000080100508ull
|
||||
#define FF400_TX_PACKET_FORMAT 0x00008010050cull
|
||||
#define FF400_ISOC_COMM_STOP 0x000080100510ull
|
||||
#define FF400_SYNC_STATUS 0x0000801c0000ull
|
||||
#define FF400_FETCH_PCM_FRAMES 0x0000801c0000ull /* For block request. */
|
||||
#define FF400_CLOCK_CONFIG 0x0000801c0004ull
|
||||
|
||||
#define FF400_MIDI_HIGH_ADDR 0x0000801003f4ull
|
||||
#define FF400_MIDI_RX_PORT_0 0x000080180000ull
|
||||
#define FF400_MIDI_RX_PORT_1 0x000080190000ull
|
||||
|
||||
static int ff400_get_clock(struct snd_ff *ff, unsigned int *rate,
|
||||
enum snd_ff_clock_src *src)
|
||||
/*
|
||||
* Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
|
||||
* we can allocate between 0 and 7 channel.
|
||||
*/
|
||||
static int keep_resources(struct snd_ff *ff, unsigned int rate)
|
||||
{
|
||||
__le32 reg;
|
||||
u32 data;
|
||||
enum snd_ff_stream_mode mode;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
|
||||
FF400_CLOCK_CONFIG, ®, sizeof(reg), 0);
|
||||
// Check whether the given value is supported or not.
|
||||
for (i = 0; i < CIP_SFC_COUNT; i++) {
|
||||
if (amdtp_rate_table[i] == rate)
|
||||
break;
|
||||
}
|
||||
if (i >= CIP_SFC_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
err = snd_ff_stream_get_multiplier_mode(i, &mode);
|
||||
if (err < 0)
|
||||
return err;
|
||||
data = le32_to_cpu(reg);
|
||||
|
||||
/* Calculate sampling rate. */
|
||||
switch ((data >> 1) & 0x03) {
|
||||
case 0x01:
|
||||
*rate = 32000;
|
||||
break;
|
||||
case 0x00:
|
||||
*rate = 44100;
|
||||
break;
|
||||
case 0x03:
|
||||
*rate = 48000;
|
||||
break;
|
||||
case 0x02:
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
/* Keep resources for in-stream. */
|
||||
ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
|
||||
err = fw_iso_resources_allocate(&ff->tx_resources,
|
||||
amdtp_stream_get_max_payload(&ff->tx_stream),
|
||||
fw_parent_device(ff->unit)->max_speed);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (data & 0x08)
|
||||
*rate *= 2;
|
||||
else if (data & 0x10)
|
||||
*rate *= 4;
|
||||
/* Keep resources for out-stream. */
|
||||
err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
|
||||
ff->spec->pcm_playback_channels[mode]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
|
||||
err = fw_iso_resources_allocate(&ff->rx_resources,
|
||||
amdtp_stream_get_max_payload(&ff->rx_stream),
|
||||
fw_parent_device(ff->unit)->max_speed);
|
||||
if (err < 0)
|
||||
fw_iso_resources_free(&ff->tx_resources);
|
||||
|
||||
/* Calculate source of clock. */
|
||||
if (data & 0x01) {
|
||||
*src = SND_FF_CLOCK_SRC_INTERNAL;
|
||||
} else {
|
||||
/* TODO: 0x00, 0x01, 0x02, 0x06, 0x07? */
|
||||
switch ((data >> 10) & 0x07) {
|
||||
case 0x03:
|
||||
*src = SND_FF_CLOCK_SRC_SPDIF;
|
||||
break;
|
||||
case 0x04:
|
||||
*src = SND_FF_CLOCK_SRC_WORD;
|
||||
break;
|
||||
case 0x05:
|
||||
*src = SND_FF_CLOCK_SRC_LTC;
|
||||
break;
|
||||
case 0x00:
|
||||
default:
|
||||
*src = SND_FF_CLOCK_SRC_ADAT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
|
||||
{
|
||||
__le32 reg;
|
||||
int i, err;
|
||||
int err;
|
||||
|
||||
/* Check whether the given value is supported or not. */
|
||||
for (i = 0; i < CIP_SFC_COUNT; i++) {
|
||||
if (amdtp_rate_table[i] == rate)
|
||||
break;
|
||||
}
|
||||
if (i == CIP_SFC_COUNT)
|
||||
return -EINVAL;
|
||||
err = keep_resources(ff, rate);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Set the number of data blocks transferred in a second. */
|
||||
reg = cpu_to_le32(rate);
|
||||
|
@ -142,233 +117,45 @@ static void ff400_finish_session(struct snd_ff *ff)
|
|||
FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0);
|
||||
}
|
||||
|
||||
static int ff400_switch_fetching_mode(struct snd_ff *ff, bool enable)
|
||||
static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
|
||||
{
|
||||
__le32 *reg;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
reg = kcalloc(18, sizeof(__le32), GFP_KERNEL);
|
||||
if (reg == NULL)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < length / 4; i++) {
|
||||
u32 quad = le32_to_cpu(buf[i]);
|
||||
u8 byte;
|
||||
unsigned int index;
|
||||
struct snd_rawmidi_substream *substream;
|
||||
|
||||
if (enable) {
|
||||
/* Message in first port. */
|
||||
/*
|
||||
* Each quadlet is corresponding to data channels in a data
|
||||
* blocks in reverse order. Precisely, quadlets for available
|
||||
* data channels should be enabled. Here, I take second best
|
||||
* to fetch PCM frames from all of data channels regardless of
|
||||
* stf.
|
||||
* This value may represent the index of this unit when the same
|
||||
* units are on the same IEEE 1394 bus. This driver doesn't use
|
||||
* it.
|
||||
*/
|
||||
for (i = 0; i < 18; ++i)
|
||||
reg[i] = cpu_to_le32(0x00000001);
|
||||
}
|
||||
|
||||
err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
|
||||
FF400_FETCH_PCM_FRAMES, reg,
|
||||
sizeof(__le32) * 18, 0);
|
||||
kfree(reg);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ff400_dump_sync_status(struct snd_ff *ff,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
__le32 reg;
|
||||
u32 data;
|
||||
int err;
|
||||
|
||||
err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
|
||||
FF400_SYNC_STATUS, ®, sizeof(reg), 0);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
data = le32_to_cpu(reg);
|
||||
|
||||
snd_iprintf(buffer, "External source detection:\n");
|
||||
|
||||
snd_iprintf(buffer, "Word Clock:");
|
||||
if ((data >> 24) & 0x20) {
|
||||
if ((data >> 24) & 0x40)
|
||||
snd_iprintf(buffer, "sync\n");
|
||||
else
|
||||
snd_iprintf(buffer, "lock\n");
|
||||
} else {
|
||||
snd_iprintf(buffer, "none\n");
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "S/PDIF:");
|
||||
if ((data >> 16) & 0x10) {
|
||||
if ((data >> 16) & 0x04)
|
||||
snd_iprintf(buffer, "sync\n");
|
||||
else
|
||||
snd_iprintf(buffer, "lock\n");
|
||||
} else {
|
||||
snd_iprintf(buffer, "none\n");
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "ADAT:");
|
||||
if ((data >> 8) & 0x04) {
|
||||
if ((data >> 8) & 0x10)
|
||||
snd_iprintf(buffer, "sync\n");
|
||||
else
|
||||
snd_iprintf(buffer, "lock\n");
|
||||
} else {
|
||||
snd_iprintf(buffer, "none\n");
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "\nUsed external source:\n");
|
||||
|
||||
if (((data >> 22) & 0x07) == 0x07) {
|
||||
snd_iprintf(buffer, "None\n");
|
||||
} else {
|
||||
switch ((data >> 22) & 0x07) {
|
||||
case 0x00:
|
||||
snd_iprintf(buffer, "ADAT:");
|
||||
break;
|
||||
case 0x03:
|
||||
snd_iprintf(buffer, "S/PDIF:");
|
||||
break;
|
||||
case 0x04:
|
||||
snd_iprintf(buffer, "Word:");
|
||||
break;
|
||||
case 0x07:
|
||||
snd_iprintf(buffer, "Nothing:");
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
default:
|
||||
snd_iprintf(buffer, "unknown:");
|
||||
break;
|
||||
index = (quad >> 8) & 0xff;
|
||||
if (index > 0) {
|
||||
substream = READ_ONCE(ff->tx_midi_substreams[0]);
|
||||
if (substream != NULL) {
|
||||
byte = quad & 0xff;
|
||||
snd_rawmidi_receive(substream, &byte, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((data >> 25) & 0x07) {
|
||||
switch ((data >> 25) & 0x07) {
|
||||
case 0x01:
|
||||
snd_iprintf(buffer, "32000\n");
|
||||
break;
|
||||
case 0x02:
|
||||
snd_iprintf(buffer, "44100\n");
|
||||
break;
|
||||
case 0x03:
|
||||
snd_iprintf(buffer, "48000\n");
|
||||
break;
|
||||
case 0x04:
|
||||
snd_iprintf(buffer, "64000\n");
|
||||
break;
|
||||
case 0x05:
|
||||
snd_iprintf(buffer, "88200\n");
|
||||
break;
|
||||
case 0x06:
|
||||
snd_iprintf(buffer, "96000\n");
|
||||
break;
|
||||
case 0x07:
|
||||
snd_iprintf(buffer, "128000\n");
|
||||
break;
|
||||
case 0x08:
|
||||
snd_iprintf(buffer, "176400\n");
|
||||
break;
|
||||
case 0x09:
|
||||
snd_iprintf(buffer, "192000\n");
|
||||
break;
|
||||
case 0x00:
|
||||
snd_iprintf(buffer, "unknown\n");
|
||||
break;
|
||||
/* Message in second port. */
|
||||
index = (quad >> 24) & 0xff;
|
||||
if (index > 0) {
|
||||
substream = READ_ONCE(ff->tx_midi_substreams[1]);
|
||||
if (substream != NULL) {
|
||||
byte = (quad >> 16) & 0xff;
|
||||
snd_rawmidi_receive(substream, &byte, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "Multiplied:");
|
||||
snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
|
||||
}
|
||||
|
||||
static void ff400_dump_clock_config(struct snd_ff *ff,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
__le32 reg;
|
||||
u32 data;
|
||||
unsigned int rate;
|
||||
const char *src;
|
||||
int err;
|
||||
|
||||
err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
|
||||
FF400_CLOCK_CONFIG, ®, sizeof(reg), 0);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
data = le32_to_cpu(reg);
|
||||
|
||||
snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
|
||||
(data & 0x20) ? "Professional" : "Consumer",
|
||||
(data & 0x40) ? "on" : "off");
|
||||
|
||||
snd_iprintf(buffer, "Optical output interface format: %s\n",
|
||||
((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
|
||||
|
||||
snd_iprintf(buffer, "Word output single speed: %s\n",
|
||||
((data >> 8) & 0x20) ? "on" : "off");
|
||||
|
||||
snd_iprintf(buffer, "S/PDIF input interface: %s\n",
|
||||
((data >> 8) & 0x02) ? "Optical" : "Coaxial");
|
||||
|
||||
switch ((data >> 1) & 0x03) {
|
||||
case 0x01:
|
||||
rate = 32000;
|
||||
break;
|
||||
case 0x00:
|
||||
rate = 44100;
|
||||
break;
|
||||
case 0x03:
|
||||
rate = 48000;
|
||||
break;
|
||||
case 0x02:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (data & 0x08)
|
||||
rate *= 2;
|
||||
else if (data & 0x10)
|
||||
rate *= 4;
|
||||
|
||||
snd_iprintf(buffer, "Sampling rate: %d\n", rate);
|
||||
|
||||
if (data & 0x01) {
|
||||
src = "Internal";
|
||||
} else {
|
||||
switch ((data >> 10) & 0x07) {
|
||||
case 0x00:
|
||||
src = "ADAT";
|
||||
break;
|
||||
case 0x03:
|
||||
src = "S/PDIF";
|
||||
break;
|
||||
case 0x04:
|
||||
src = "Word";
|
||||
break;
|
||||
case 0x05:
|
||||
src = "LTC";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
snd_iprintf(buffer, "Sync to clock source: %s\n", src);
|
||||
}
|
||||
|
||||
const struct snd_ff_protocol snd_ff_protocol_ff400 = {
|
||||
.get_clock = ff400_get_clock,
|
||||
.handle_midi_msg = ff400_handle_midi_msg,
|
||||
.begin_session = ff400_begin_session,
|
||||
.finish_session = ff400_finish_session,
|
||||
.switch_fetching_mode = ff400_switch_fetching_mode,
|
||||
|
||||
.dump_sync_status = ff400_dump_sync_status,
|
||||
.dump_clock_config = ff400_dump_clock_config,
|
||||
|
||||
.midi_high_addr_reg = FF400_MIDI_HIGH_ADDR,
|
||||
.midi_rx_port_0_reg = FF400_MIDI_RX_PORT_0,
|
||||
.midi_rx_port_1_reg = FF400_MIDI_RX_PORT_1,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* ff-protocol-ff800.c - a part of driver for RME Fireface series
|
||||
*
|
||||
* Copyright (c) 2018 Takashi Sakamoto
|
||||
*
|
||||
* Licensed under the terms of the GNU General Public License, version 2.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
#define FF800_STF 0x0000fc88f000
|
||||
#define FF800_RX_PACKET_FORMAT 0x0000fc88f004
|
||||
#define FF800_ALLOC_TX_STREAM 0x0000fc88f008
|
||||
#define FF800_ISOC_COMM_START 0x0000fc88f00c
|
||||
#define FF800_TX_S800_FLAG 0x00000800
|
||||
#define FF800_ISOC_COMM_STOP 0x0000fc88f010
|
||||
|
||||
#define FF800_TX_PACKET_ISOC_CH 0x0000801c0008
|
||||
|
||||
static int allocate_rx_resources(struct snd_ff *ff)
|
||||
{
|
||||
u32 data;
|
||||
__le32 reg;
|
||||
int err;
|
||||
|
||||
// Controllers should allocate isochronous resources for rx stream.
|
||||
err = fw_iso_resources_allocate(&ff->rx_resources,
|
||||
amdtp_stream_get_max_payload(&ff->rx_stream),
|
||||
fw_parent_device(ff->unit)->max_speed);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
// Set isochronous channel and the number of quadlets of rx packets.
|
||||
data = ff->rx_stream.data_block_quadlets << 3;
|
||||
data = (data << 8) | ff->rx_resources.channel;
|
||||
reg = cpu_to_le32(data);
|
||||
return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
|
||||
FF800_RX_PACKET_FORMAT, ®, sizeof(reg), 0);
|
||||
}
|
||||
|
||||
static int allocate_tx_resources(struct snd_ff *ff)
|
||||
{
|
||||
__le32 reg;
|
||||
unsigned int count;
|
||||
unsigned int tx_isoc_channel;
|
||||
int err;
|
||||
|
||||
reg = cpu_to_le32(ff->tx_stream.data_block_quadlets);
|
||||
err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
|
||||
FF800_ALLOC_TX_STREAM, ®, sizeof(reg), 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
// Wait till the format of tx packet is available.
|
||||
count = 0;
|
||||
while (count++ < 10) {
|
||||
u32 data;
|
||||
err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
|
||||
FF800_TX_PACKET_ISOC_CH, ®, sizeof(reg), 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data = le32_to_cpu(reg);
|
||||
if (data != 0xffffffff) {
|
||||
tx_isoc_channel = data;
|
||||
break;
|
||||
}
|
||||
|
||||
msleep(50);
|
||||
}
|
||||
if (count >= 10)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
// NOTE: this is a makeshift to start OHCI 1394 IR context in the
|
||||
// channel. On the other hand, 'struct fw_iso_resources.allocated' is
|
||||
// not true and it's not deallocated at stop.
|
||||
ff->tx_resources.channel = tx_isoc_channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
|
||||
{
|
||||
__le32 reg;
|
||||
int err;
|
||||
|
||||
reg = cpu_to_le32(rate);
|
||||
err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
|
||||
FF800_STF, ®, sizeof(reg), 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
// If starting isochronous communication immediately, change of STF has
|
||||
// no effect. In this case, the communication runs based on former STF.
|
||||
// Let's sleep for a bit.
|
||||
msleep(100);
|
||||
|
||||
err = allocate_rx_resources(ff);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = allocate_tx_resources(ff);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
reg = cpu_to_le32(0x80000000);
|
||||
reg |= cpu_to_le32(ff->tx_stream.data_block_quadlets);
|
||||
if (fw_parent_device(ff->unit)->max_speed == SCODE_800)
|
||||
reg |= cpu_to_le32(FF800_TX_S800_FLAG);
|
||||
return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
|
||||
FF800_ISOC_COMM_START, ®, sizeof(reg), 0);
|
||||
}
|
||||
|
||||
static void ff800_finish_session(struct snd_ff *ff)
|
||||
{
|
||||
__le32 reg;
|
||||
|
||||
reg = cpu_to_le32(0x80000000);
|
||||
snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
|
||||
FF800_ISOC_COMM_STOP, ®, sizeof(reg), 0);
|
||||
}
|
||||
|
||||
static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length / 4; i++) {
|
||||
u8 byte = le32_to_cpu(buf[i]) & 0xff;
|
||||
struct snd_rawmidi_substream *substream;
|
||||
|
||||
substream = READ_ONCE(ff->tx_midi_substreams[0]);
|
||||
if (substream)
|
||||
snd_rawmidi_receive(substream, &byte, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const struct snd_ff_protocol snd_ff_protocol_ff800 = {
|
||||
.handle_midi_msg = ff800_handle_midi_msg,
|
||||
.begin_session = ff800_begin_session,
|
||||
.finish_session = ff800_finish_session,
|
||||
};
|
|
@ -10,73 +10,71 @@
|
|||
|
||||
#define CALLBACK_TIMEOUT_MS 200
|
||||
|
||||
static int get_rate_mode(unsigned int rate, unsigned int *mode)
|
||||
int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
|
||||
enum snd_ff_stream_mode *mode)
|
||||
{
|
||||
int i;
|
||||
static const enum snd_ff_stream_mode modes[] = {
|
||||
[CIP_SFC_32000] = SND_FF_STREAM_MODE_LOW,
|
||||
[CIP_SFC_44100] = SND_FF_STREAM_MODE_LOW,
|
||||
[CIP_SFC_48000] = SND_FF_STREAM_MODE_LOW,
|
||||
[CIP_SFC_88200] = SND_FF_STREAM_MODE_MID,
|
||||
[CIP_SFC_96000] = SND_FF_STREAM_MODE_MID,
|
||||
[CIP_SFC_176400] = SND_FF_STREAM_MODE_HIGH,
|
||||
[CIP_SFC_192000] = SND_FF_STREAM_MODE_HIGH,
|
||||
};
|
||||
|
||||
for (i = 0; i < CIP_SFC_COUNT; i++) {
|
||||
if (amdtp_rate_table[i] == rate)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == CIP_SFC_COUNT)
|
||||
if (sfc >= CIP_SFC_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
*mode = ((int)i - 1) / 2;
|
||||
*mode = modes[sfc];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
|
||||
* we can allocate between 0 and 7 channel.
|
||||
*/
|
||||
static int keep_resources(struct snd_ff *ff, unsigned int rate)
|
||||
{
|
||||
int mode;
|
||||
int err;
|
||||
|
||||
err = get_rate_mode(rate, &mode);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Keep resources for in-stream. */
|
||||
err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
|
||||
ff->spec->pcm_capture_channels[mode]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
|
||||
err = fw_iso_resources_allocate(&ff->tx_resources,
|
||||
amdtp_stream_get_max_payload(&ff->tx_stream),
|
||||
fw_parent_device(ff->unit)->max_speed);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Keep resources for out-stream. */
|
||||
err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
|
||||
ff->spec->pcm_playback_channels[mode]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
|
||||
err = fw_iso_resources_allocate(&ff->rx_resources,
|
||||
amdtp_stream_get_max_payload(&ff->rx_stream),
|
||||
fw_parent_device(ff->unit)->max_speed);
|
||||
if (err < 0)
|
||||
fw_iso_resources_free(&ff->tx_resources);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void release_resources(struct snd_ff *ff)
|
||||
{
|
||||
fw_iso_resources_free(&ff->tx_resources);
|
||||
fw_iso_resources_free(&ff->rx_resources);
|
||||
}
|
||||
|
||||
static int switch_fetching_mode(struct snd_ff *ff, bool enable)
|
||||
{
|
||||
unsigned int count;
|
||||
__le32 *reg;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i)
|
||||
count = max(count, ff->spec->pcm_playback_channels[i]);
|
||||
|
||||
reg = kcalloc(count, sizeof(__le32), GFP_KERNEL);
|
||||
if (!reg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!enable) {
|
||||
/*
|
||||
* Each quadlet is corresponding to data channels in a data
|
||||
* blocks in reverse order. Precisely, quadlets for available
|
||||
* data channels should be enabled. Here, I take second best
|
||||
* to fetch PCM frames from all of data channels regardless of
|
||||
* stf.
|
||||
*/
|
||||
for (i = 0; i < count; ++i)
|
||||
reg[i] = cpu_to_le32(0x00000001);
|
||||
}
|
||||
|
||||
err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
|
||||
SND_FF_REG_FETCH_PCM_FRAMES, reg,
|
||||
sizeof(__le32) * count, 0);
|
||||
kfree(reg);
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void finish_session(struct snd_ff *ff)
|
||||
{
|
||||
ff->spec->protocol->finish_session(ff);
|
||||
ff->spec->protocol->switch_fetching_mode(ff, false);
|
||||
switch_fetching_mode(ff, false);
|
||||
}
|
||||
|
||||
static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
|
||||
|
@ -149,7 +147,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
|
|||
if (ff->substreams_counter == 0)
|
||||
return 0;
|
||||
|
||||
err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
|
||||
err = snd_ff_transaction_get_clock(ff, &curr_rate, &src);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (curr_rate != rate ||
|
||||
|
@ -168,9 +166,29 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
|
|||
* packets. Then, the device transfers packets.
|
||||
*/
|
||||
if (!amdtp_stream_running(&ff->rx_stream)) {
|
||||
err = keep_resources(ff, rate);
|
||||
enum snd_ff_stream_mode mode;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CIP_SFC_COUNT; ++i) {
|
||||
if (amdtp_rate_table[i] == rate)
|
||||
break;
|
||||
}
|
||||
if (i >= CIP_SFC_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
err = snd_ff_stream_get_multiplier_mode(i, &mode);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
return err;
|
||||
|
||||
err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
|
||||
ff->spec->pcm_capture_channels[mode]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
|
||||
ff->spec->pcm_playback_channels[mode]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = ff->spec->protocol->begin_session(ff, rate);
|
||||
if (err < 0)
|
||||
|
@ -188,7 +206,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
|
|||
goto error;
|
||||
}
|
||||
|
||||
err = ff->spec->protocol->switch_fetching_mode(ff, true);
|
||||
err = switch_fetching_mode(ff, true);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,72 @@
|
|||
|
||||
#include "ff.h"
|
||||
|
||||
#define SND_FF_REG_MIDI_RX_PORT_0 0x000080180000ull
|
||||
#define SND_FF_REG_MIDI_RX_PORT_1 0x000080190000ull
|
||||
|
||||
int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate,
|
||||
enum snd_ff_clock_src *src)
|
||||
{
|
||||
__le32 reg;
|
||||
u32 data;
|
||||
int err;
|
||||
|
||||
err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
|
||||
SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
data = le32_to_cpu(reg);
|
||||
|
||||
/* Calculate sampling rate. */
|
||||
switch ((data >> 1) & 0x03) {
|
||||
case 0x01:
|
||||
*rate = 32000;
|
||||
break;
|
||||
case 0x00:
|
||||
*rate = 44100;
|
||||
break;
|
||||
case 0x03:
|
||||
*rate = 48000;
|
||||
break;
|
||||
case 0x02:
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (data & 0x08)
|
||||
*rate *= 2;
|
||||
else if (data & 0x10)
|
||||
*rate *= 4;
|
||||
|
||||
/* Calculate source of clock. */
|
||||
if (data & 0x01) {
|
||||
*src = SND_FF_CLOCK_SRC_INTERNAL;
|
||||
} else {
|
||||
/* TODO: 0x02, 0x06, 0x07? */
|
||||
switch ((data >> 10) & 0x07) {
|
||||
case 0x00:
|
||||
*src = SND_FF_CLOCK_SRC_ADAT1;
|
||||
break;
|
||||
case 0x01:
|
||||
*src = SND_FF_CLOCK_SRC_ADAT2;
|
||||
break;
|
||||
case 0x03:
|
||||
*src = SND_FF_CLOCK_SRC_SPDIF;
|
||||
break;
|
||||
case 0x04:
|
||||
*src = SND_FF_CLOCK_SRC_WORD;
|
||||
break;
|
||||
case 0x05:
|
||||
*src = SND_FF_CLOCK_SRC_LTC;
|
||||
break;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port,
|
||||
int rcode)
|
||||
{
|
||||
|
@ -90,10 +156,10 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
|
|||
fill_midi_buf(ff, port, i, buf[i]);
|
||||
|
||||
if (port == 0) {
|
||||
addr = ff->spec->protocol->midi_rx_port_0_reg;
|
||||
addr = SND_FF_REG_MIDI_RX_PORT_0;
|
||||
callback = finish_transmit_midi0_msg;
|
||||
} else {
|
||||
addr = ff->spec->protocol->midi_rx_port_1_reg;
|
||||
addr = SND_FF_REG_MIDI_RX_PORT_1;
|
||||
callback = finish_transmit_midi1_msg;
|
||||
}
|
||||
|
||||
|
@ -140,42 +206,10 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request,
|
|||
{
|
||||
struct snd_ff *ff = callback_data;
|
||||
__le32 *buf = data;
|
||||
u32 quad;
|
||||
u8 byte;
|
||||
unsigned int index;
|
||||
struct snd_rawmidi_substream *substream;
|
||||
int i;
|
||||
|
||||
fw_send_response(card, request, RCODE_COMPLETE);
|
||||
|
||||
for (i = 0; i < length / 4; i++) {
|
||||
quad = le32_to_cpu(buf[i]);
|
||||
|
||||
/* Message in first port. */
|
||||
/*
|
||||
* This value may represent the index of this unit when the same
|
||||
* units are on the same IEEE 1394 bus. This driver doesn't use
|
||||
* it.
|
||||
*/
|
||||
index = (quad >> 8) & 0xff;
|
||||
if (index > 0) {
|
||||
substream = READ_ONCE(ff->tx_midi_substreams[0]);
|
||||
if (substream != NULL) {
|
||||
byte = quad & 0xff;
|
||||
snd_rawmidi_receive(substream, &byte, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Message in second port. */
|
||||
index = (quad >> 24) & 0xff;
|
||||
if (index > 0) {
|
||||
substream = READ_ONCE(ff->tx_midi_substreams[1]);
|
||||
if (substream != NULL) {
|
||||
byte = (quad >> 16) & 0xff;
|
||||
snd_rawmidi_receive(substream, &byte, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
ff->spec->protocol->handle_midi_msg(ff, buf, length);
|
||||
}
|
||||
|
||||
static int allocate_own_address(struct snd_ff *ff, int i)
|
||||
|
@ -203,36 +237,33 @@ static int allocate_own_address(struct snd_ff *ff, int i)
|
|||
}
|
||||
|
||||
/*
|
||||
* The configuration to start asynchronous transactions for MIDI messages is in
|
||||
* 0x'0000'8010'051c. This register includes the other options, thus this driver
|
||||
* doesn't touch it and leaves the decision to userspace. The userspace MUST add
|
||||
* 0x04000000 to write transactions to the register to receive any MIDI
|
||||
* messages.
|
||||
*
|
||||
* Here, I just describe MIDI-related offsets of the register, in little-endian
|
||||
* order.
|
||||
*
|
||||
* Controllers are allowed to register higher 4 bytes of address to receive
|
||||
* the transactions. The register is 0x'0000'8010'03f4. On the other hand, the
|
||||
* controllers are not allowed to register lower 4 bytes of the address. They
|
||||
* are forced to select from 4 options by writing corresponding bits to
|
||||
* 0x'0000'8010'051c.
|
||||
* the transactions. Different models have different registers for this purpose;
|
||||
* e.g. 0x'0000'8010'03f4 for Fireface 400.
|
||||
* The controllers are not allowed to register lower 4 bytes of the address.
|
||||
* They are forced to select one of 4 options for the part of address by writing
|
||||
* corresponding bits to 0x'0000'8010'051f.
|
||||
*
|
||||
* The 3rd-6th bits in MSB of this register are used to indicate lower 4 bytes
|
||||
* of address to which the device transferrs the transactions.
|
||||
* - 6th: 0x'....'....'0000'0180
|
||||
* - 5th: 0x'....'....'0000'0100
|
||||
* - 4th: 0x'....'....'0000'0080
|
||||
* - 3rd: 0x'....'....'0000'0000
|
||||
* The 3rd-6th bits of this register are flags to indicate lower 4 bytes of
|
||||
* address to which the device transferrs the transactions. In short:
|
||||
* - 0x20: 0x'....'....'0000'0180
|
||||
* - 0x10: 0x'....'....'0000'0100
|
||||
* - 0x08: 0x'....'....'0000'0080
|
||||
* - 0x04: 0x'....'....'0000'0000
|
||||
*
|
||||
* This driver configure 0x'....'....'0000'0000 for units to receive MIDI
|
||||
* messages. 3rd bit of the register should be configured, however this driver
|
||||
* deligates this task to user space applications due to a restriction that
|
||||
* this register is write-only and the other bits have own effects.
|
||||
* This driver configure 0x'....'....'0000'0000 to receive MIDI messages from
|
||||
* units. The 3rd bit of the register should be configured, however this driver
|
||||
* deligates this task to userspace applications due to a restriction that this
|
||||
* register is write-only and the other bits have own effects.
|
||||
*
|
||||
* The 1st and 2nd bits in LSB of this register are used to cancel transferring
|
||||
* asynchronous transactions. These two bits have the same effect.
|
||||
* - 1st/2nd: cancel transferring
|
||||
* Unlike Fireface 800, Fireface 400 cancels transferring asynchronous
|
||||
* transactions when the 1st and 2nd of the register stand. These two bits have
|
||||
* the same effect.
|
||||
* - 0x02, 0x01: cancel transferring
|
||||
*
|
||||
* On the other hand, the bits have no effect on Fireface 800. This model
|
||||
* cancels asynchronous transactions when the higher 4 bytes of address is
|
||||
* overwritten with zero.
|
||||
*/
|
||||
int snd_ff_transaction_reregister(struct snd_ff *ff)
|
||||
{
|
||||
|
@ -247,7 +278,7 @@ int snd_ff_transaction_reregister(struct snd_ff *ff)
|
|||
addr = (fw_card->node_id << 16) | (ff->async_handler.offset >> 32);
|
||||
reg = cpu_to_le32(addr);
|
||||
return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
|
||||
ff->spec->protocol->midi_high_addr_reg,
|
||||
ff->spec->midi_high_addr,
|
||||
®, sizeof(reg), 0);
|
||||
}
|
||||
|
||||
|
@ -288,7 +319,7 @@ void snd_ff_transaction_unregister(struct snd_ff *ff)
|
|||
/* Release higher 4 bytes of address. */
|
||||
reg = cpu_to_le32(0x00000000);
|
||||
snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
|
||||
ff->spec->protocol->midi_high_addr_reg,
|
||||
ff->spec->midi_high_addr,
|
||||
®, sizeof(reg), 0);
|
||||
|
||||
fw_core_remove_address_handler(&ff->async_handler);
|
||||
|
|
|
@ -145,6 +145,16 @@ static void snd_ff_remove(struct fw_unit *unit)
|
|||
fw_unit_put(ff->unit);
|
||||
}
|
||||
|
||||
static const struct snd_ff_spec spec_ff800 = {
|
||||
.name = "Fireface800",
|
||||
.pcm_capture_channels = {28, 20, 12},
|
||||
.pcm_playback_channels = {28, 20, 12},
|
||||
.midi_in_ports = 1,
|
||||
.midi_out_ports = 1,
|
||||
.protocol = &snd_ff_protocol_ff800,
|
||||
.midi_high_addr = 0x000200000320ull,
|
||||
};
|
||||
|
||||
static const struct snd_ff_spec spec_ff400 = {
|
||||
.name = "Fireface400",
|
||||
.pcm_capture_channels = {18, 14, 10},
|
||||
|
@ -152,9 +162,22 @@ static const struct snd_ff_spec spec_ff400 = {
|
|||
.midi_in_ports = 2,
|
||||
.midi_out_ports = 2,
|
||||
.protocol = &snd_ff_protocol_ff400,
|
||||
.midi_high_addr = 0x0000801003f4ull,
|
||||
};
|
||||
|
||||
static const struct ieee1394_device_id snd_ff_id_table[] = {
|
||||
/* Fireface 800 */
|
||||
{
|
||||
.match_flags = IEEE1394_MATCH_VENDOR_ID |
|
||||
IEEE1394_MATCH_SPECIFIER_ID |
|
||||
IEEE1394_MATCH_VERSION |
|
||||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_RME,
|
||||
.specifier_id = OUI_RME,
|
||||
.version = 0x000001,
|
||||
.model_id = 0x101800,
|
||||
.driver_data = (kernel_ulong_t)&spec_ff800,
|
||||
},
|
||||
/* Fireface 400 */
|
||||
{
|
||||
.match_flags = IEEE1394_MATCH_VENDOR_ID |
|
||||
|
@ -162,7 +185,7 @@ static const struct ieee1394_device_id snd_ff_id_table[] = {
|
|||
IEEE1394_MATCH_VERSION |
|
||||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_RME,
|
||||
.specifier_id = 0x000a35,
|
||||
.specifier_id = OUI_RME,
|
||||
.version = 0x000002,
|
||||
.model_id = 0x101800,
|
||||
.driver_data = (kernel_ulong_t)&spec_ff400,
|
||||
|
|
|
@ -31,23 +31,34 @@
|
|||
#include "../amdtp-stream.h"
|
||||
#include "../iso-resources.h"
|
||||
|
||||
#define SND_FF_STREAM_MODES 3
|
||||
|
||||
#define SND_FF_MAXIMIM_MIDI_QUADS 9
|
||||
#define SND_FF_IN_MIDI_PORTS 2
|
||||
#define SND_FF_OUT_MIDI_PORTS 2
|
||||
|
||||
#define SND_FF_REG_SYNC_STATUS 0x0000801c0000ull
|
||||
/* For block write request. */
|
||||
#define SND_FF_REG_FETCH_PCM_FRAMES 0x0000801c0000ull
|
||||
#define SND_FF_REG_CLOCK_CONFIG 0x0000801c0004ull
|
||||
|
||||
enum snd_ff_stream_mode {
|
||||
SND_FF_STREAM_MODE_LOW = 0,
|
||||
SND_FF_STREAM_MODE_MID,
|
||||
SND_FF_STREAM_MODE_HIGH,
|
||||
SND_FF_STREAM_MODE_COUNT,
|
||||
};
|
||||
|
||||
struct snd_ff_protocol;
|
||||
struct snd_ff_spec {
|
||||
const char *const name;
|
||||
|
||||
const unsigned int pcm_capture_channels[SND_FF_STREAM_MODES];
|
||||
const unsigned int pcm_playback_channels[SND_FF_STREAM_MODES];
|
||||
const unsigned int pcm_capture_channels[SND_FF_STREAM_MODE_COUNT];
|
||||
const unsigned int pcm_playback_channels[SND_FF_STREAM_MODE_COUNT];
|
||||
|
||||
unsigned int midi_in_ports;
|
||||
unsigned int midi_out_ports;
|
||||
|
||||
const struct snd_ff_protocol *protocol;
|
||||
u64 midi_high_addr;
|
||||
};
|
||||
|
||||
struct snd_ff {
|
||||
|
@ -89,31 +100,24 @@ struct snd_ff {
|
|||
enum snd_ff_clock_src {
|
||||
SND_FF_CLOCK_SRC_INTERNAL,
|
||||
SND_FF_CLOCK_SRC_SPDIF,
|
||||
SND_FF_CLOCK_SRC_ADAT,
|
||||
SND_FF_CLOCK_SRC_ADAT1,
|
||||
SND_FF_CLOCK_SRC_ADAT2,
|
||||
SND_FF_CLOCK_SRC_WORD,
|
||||
SND_FF_CLOCK_SRC_LTC,
|
||||
/* TODO: perhaps ADAT2 and TCO exists. */
|
||||
/* TODO: perhaps TCO exists. */
|
||||
};
|
||||
|
||||
struct snd_ff_protocol {
|
||||
int (*get_clock)(struct snd_ff *ff, unsigned int *rate,
|
||||
enum snd_ff_clock_src *src);
|
||||
void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length);
|
||||
int (*begin_session)(struct snd_ff *ff, unsigned int rate);
|
||||
void (*finish_session)(struct snd_ff *ff);
|
||||
int (*switch_fetching_mode)(struct snd_ff *ff, bool enable);
|
||||
|
||||
void (*dump_sync_status)(struct snd_ff *ff,
|
||||
struct snd_info_buffer *buffer);
|
||||
void (*dump_clock_config)(struct snd_ff *ff,
|
||||
struct snd_info_buffer *buffer);
|
||||
|
||||
u64 midi_high_addr_reg;
|
||||
u64 midi_rx_port_0_reg;
|
||||
u64 midi_rx_port_1_reg;
|
||||
};
|
||||
|
||||
extern const struct snd_ff_protocol snd_ff_protocol_ff800;
|
||||
extern const struct snd_ff_protocol snd_ff_protocol_ff400;
|
||||
|
||||
int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate,
|
||||
enum snd_ff_clock_src *src);
|
||||
int snd_ff_transaction_register(struct snd_ff *ff);
|
||||
int snd_ff_transaction_reregister(struct snd_ff *ff);
|
||||
void snd_ff_transaction_unregister(struct snd_ff *ff);
|
||||
|
@ -125,6 +129,8 @@ int amdtp_ff_add_pcm_hw_constraints(struct amdtp_stream *s,
|
|||
int amdtp_ff_init(struct amdtp_stream *s, struct fw_unit *unit,
|
||||
enum amdtp_stream_direction dir);
|
||||
|
||||
int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
|
||||
enum snd_ff_stream_mode *mode);
|
||||
int snd_ff_stream_init_duplex(struct snd_ff *ff);
|
||||
void snd_ff_stream_destroy_duplex(struct snd_ff *ff);
|
||||
int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define VENDOR_LACIE 0x00d04b
|
||||
#define VENDOR_TASCAM 0x00022e
|
||||
#define OUI_STANTON 0x001260
|
||||
#define OUI_APOGEE 0x0003db
|
||||
|
||||
#define MODEL_SATELLITE 0x00200f
|
||||
|
||||
|
@ -397,6 +398,13 @@ static const struct ieee1394_device_id oxfw_id_table[] = {
|
|||
.vendor_id = OUI_STANTON,
|
||||
.model_id = 0x002000,
|
||||
},
|
||||
// APOGEE, duet FireWire
|
||||
{
|
||||
.match_flags = IEEE1394_MATCH_VENDOR_ID |
|
||||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_APOGEE,
|
||||
.model_id = 0x01dddd,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
|
||||
|
|
|
@ -117,6 +117,55 @@ int amdtp_tscm_add_pcm_hw_constraints(struct amdtp_stream *s,
|
|||
return amdtp_stream_add_pcm_hw_constraints(s, runtime);
|
||||
}
|
||||
|
||||
static void read_status_messages(struct amdtp_stream *s,
|
||||
__be32 *buffer, unsigned int data_blocks)
|
||||
{
|
||||
struct snd_tscm *tscm = container_of(s, struct snd_tscm, tx_stream);
|
||||
bool used = READ_ONCE(tscm->hwdep->used);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data_blocks; i++) {
|
||||
unsigned int index;
|
||||
__be32 before;
|
||||
__be32 after;
|
||||
|
||||
index = be32_to_cpu(buffer[0]) % SNDRV_FIREWIRE_TASCAM_STATE_COUNT;
|
||||
before = tscm->state[index];
|
||||
after = buffer[s->data_block_quadlets - 1];
|
||||
|
||||
if (used && index > 4 && index < 16) {
|
||||
__be32 mask;
|
||||
|
||||
if (index == 5)
|
||||
mask = cpu_to_be32(~0x0000ffff);
|
||||
else if (index == 6)
|
||||
mask = cpu_to_be32(~0x0000ffff);
|
||||
else if (index == 8)
|
||||
mask = cpu_to_be32(~0x000f0f00);
|
||||
else
|
||||
mask = cpu_to_be32(~0x00000000);
|
||||
|
||||
if ((before ^ after) & mask) {
|
||||
struct snd_firewire_tascam_change *entry =
|
||||
&tscm->queue[tscm->push_pos];
|
||||
|
||||
spin_lock_irq(&tscm->lock);
|
||||
entry->index = index;
|
||||
entry->before = before;
|
||||
entry->after = after;
|
||||
if (++tscm->push_pos >= SND_TSCM_QUEUE_COUNT)
|
||||
tscm->push_pos = 0;
|
||||
spin_unlock_irq(&tscm->lock);
|
||||
|
||||
wake_up(&tscm->hwdep_wait);
|
||||
}
|
||||
}
|
||||
|
||||
tscm->state[index] = after;
|
||||
buffer += s->data_block_quadlets;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
|
||||
__be32 *buffer,
|
||||
unsigned int data_blocks,
|
||||
|
@ -128,7 +177,7 @@ static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
|
|||
if (data_blocks > 0 && pcm)
|
||||
read_pcm_s32(s, pcm, buffer, data_blocks);
|
||||
|
||||
/* A place holder for control messages. */
|
||||
read_status_messages(s, buffer, data_blocks);
|
||||
|
||||
return data_blocks;
|
||||
}
|
||||
|
|
|
@ -16,18 +16,93 @@
|
|||
|
||||
#include "tascam.h"
|
||||
|
||||
static long tscm_hwdep_read_locked(struct snd_tscm *tscm, char __user *buf,
|
||||
long count, loff_t *offset)
|
||||
{
|
||||
struct snd_firewire_event_lock_status event = {
|
||||
.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
|
||||
};
|
||||
|
||||
event.status = (tscm->dev_lock_count > 0);
|
||||
tscm->dev_lock_changed = false;
|
||||
count = min_t(long, count, sizeof(event));
|
||||
|
||||
spin_unlock_irq(&tscm->lock);
|
||||
|
||||
if (copy_to_user(buf, &event, count))
|
||||
return -EFAULT;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static long tscm_hwdep_read_queue(struct snd_tscm *tscm, char __user *buf,
|
||||
long remained, loff_t *offset)
|
||||
{
|
||||
char __user *pos = buf;
|
||||
unsigned int type = SNDRV_FIREWIRE_EVENT_TASCAM_CONTROL;
|
||||
struct snd_firewire_tascam_change *entries = tscm->queue;
|
||||
long count;
|
||||
|
||||
// At least, one control event can be copied.
|
||||
if (remained < sizeof(type) + sizeof(*entries)) {
|
||||
spin_unlock_irq(&tscm->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Copy the type field later.
|
||||
count = sizeof(type);
|
||||
remained -= sizeof(type);
|
||||
pos += sizeof(type);
|
||||
|
||||
while (true) {
|
||||
unsigned int head_pos;
|
||||
unsigned int tail_pos;
|
||||
unsigned int length;
|
||||
|
||||
if (tscm->pull_pos == tscm->push_pos)
|
||||
break;
|
||||
else if (tscm->pull_pos < tscm->push_pos)
|
||||
tail_pos = tscm->push_pos;
|
||||
else
|
||||
tail_pos = SND_TSCM_QUEUE_COUNT;
|
||||
head_pos = tscm->pull_pos;
|
||||
|
||||
length = (tail_pos - head_pos) * sizeof(*entries);
|
||||
if (remained < length)
|
||||
length = rounddown(remained, sizeof(*entries));
|
||||
if (length == 0)
|
||||
break;
|
||||
|
||||
spin_unlock_irq(&tscm->lock);
|
||||
if (copy_to_user(pos, &entries[head_pos], length))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_irq(&tscm->lock);
|
||||
|
||||
tscm->pull_pos = tail_pos % SND_TSCM_QUEUE_COUNT;
|
||||
|
||||
count += length;
|
||||
remained -= length;
|
||||
pos += length;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&tscm->lock);
|
||||
|
||||
if (copy_to_user(buf, &type, sizeof(type)))
|
||||
return -EFAULT;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
|
||||
loff_t *offset)
|
||||
{
|
||||
struct snd_tscm *tscm = hwdep->private_data;
|
||||
DEFINE_WAIT(wait);
|
||||
union snd_firewire_event event = {
|
||||
.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS,
|
||||
};
|
||||
|
||||
spin_lock_irq(&tscm->lock);
|
||||
|
||||
while (!tscm->dev_lock_changed) {
|
||||
while (!tscm->dev_lock_changed && tscm->push_pos == tscm->pull_pos) {
|
||||
prepare_to_wait(&tscm->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
|
||||
spin_unlock_irq(&tscm->lock);
|
||||
schedule();
|
||||
|
@ -37,15 +112,15 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
|
|||
spin_lock_irq(&tscm->lock);
|
||||
}
|
||||
|
||||
event.lock_status.status = (tscm->dev_lock_count > 0);
|
||||
tscm->dev_lock_changed = false;
|
||||
|
||||
spin_unlock_irq(&tscm->lock);
|
||||
|
||||
count = min_t(long, count, sizeof(event.lock_status));
|
||||
|
||||
if (copy_to_user(buf, &event, count))
|
||||
return -EFAULT;
|
||||
// NOTE: The acquired lock should be released in callee side.
|
||||
if (tscm->dev_lock_changed) {
|
||||
count = tscm_hwdep_read_locked(tscm, buf, count, offset);
|
||||
} else if (tscm->push_pos != tscm->pull_pos) {
|
||||
count = tscm_hwdep_read_queue(tscm, buf, count, offset);
|
||||
} else {
|
||||
spin_unlock_irq(&tscm->lock);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -59,7 +134,7 @@ static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
|
|||
poll_wait(file, &tscm->hwdep_wait, wait);
|
||||
|
||||
spin_lock_irq(&tscm->lock);
|
||||
if (tscm->dev_lock_changed)
|
||||
if (tscm->dev_lock_changed || tscm->push_pos != tscm->pull_pos)
|
||||
events = EPOLLIN | EPOLLRDNORM;
|
||||
else
|
||||
events = 0;
|
||||
|
@ -123,6 +198,14 @@ static int hwdep_unlock(struct snd_tscm *tscm)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int tscm_hwdep_state(struct snd_tscm *tscm, void __user *arg)
|
||||
{
|
||||
if (copy_to_user(arg, tscm->state, sizeof(tscm->state)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
|
||||
{
|
||||
struct snd_tscm *tscm = hwdep->private_data;
|
||||
|
@ -147,6 +230,8 @@ static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
|
|||
return hwdep_lock(tscm);
|
||||
case SNDRV_FIREWIRE_IOCTL_UNLOCK:
|
||||
return hwdep_unlock(tscm);
|
||||
case SNDRV_FIREWIRE_IOCTL_TASCAM_STATE:
|
||||
return tscm_hwdep_state(tscm, (void __user *)arg);
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
@ -185,5 +270,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
|
|||
hwdep->private_data = tscm;
|
||||
hwdep->exclusive = true;
|
||||
|
||||
tscm->hwdep = hwdep;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ struct snd_fw_async_midi_port {
|
|||
int consume_bytes;
|
||||
};
|
||||
|
||||
#define SND_TSCM_QUEUE_COUNT 16
|
||||
|
||||
struct snd_tscm {
|
||||
struct snd_card *card;
|
||||
struct fw_unit *unit;
|
||||
|
@ -89,6 +91,13 @@ struct snd_tscm {
|
|||
|
||||
/* For MIDI message outgoing transactions. */
|
||||
struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX];
|
||||
|
||||
// A cache of status information in tx isoc packets.
|
||||
__be32 state[SNDRV_FIREWIRE_TASCAM_STATE_COUNT];
|
||||
struct snd_hwdep *hwdep;
|
||||
struct snd_firewire_tascam_change queue[SND_TSCM_QUEUE_COUNT];
|
||||
unsigned int pull_pos;
|
||||
unsigned int push_pos;
|
||||
};
|
||||
|
||||
#define TSCM_ADDR_BASE 0xffff00000000ull
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
#include <sound/hdaudio.h>
|
||||
#include "trace.h"
|
||||
|
||||
static void process_unsol_events(struct work_struct *work);
|
||||
|
||||
static const struct hdac_bus_ops default_ops = {
|
||||
.command = snd_hdac_bus_send_cmd,
|
||||
.get_response = snd_hdac_bus_get_response,
|
||||
|
@ -37,7 +35,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
|
|||
bus->io_ops = io_ops;
|
||||
INIT_LIST_HEAD(&bus->stream_list);
|
||||
INIT_LIST_HEAD(&bus->codec_list);
|
||||
INIT_WORK(&bus->unsol_work, process_unsol_events);
|
||||
INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events);
|
||||
spin_lock_init(&bus->reg_lock);
|
||||
mutex_init(&bus->cmd_mutex);
|
||||
bus->irq = -1;
|
||||
|
@ -148,7 +146,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event);
|
|||
/*
|
||||
* process queued unsolicited events
|
||||
*/
|
||||
static void process_unsol_events(struct work_struct *work)
|
||||
void snd_hdac_bus_process_unsol_events(struct work_struct *work)
|
||||
{
|
||||
struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work);
|
||||
struct hdac_device *codec;
|
||||
|
@ -171,6 +169,7 @@ static void process_unsol_events(struct work_struct *work)
|
|||
drv->unsol_event(codec, res);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_bus_process_unsol_events);
|
||||
|
||||
/**
|
||||
* snd_hdac_bus_add_device - Add a codec to bus
|
||||
|
|
|
@ -54,41 +54,44 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
|
|||
/**
|
||||
* snd_hdac_display_power - Power up / down the power refcount
|
||||
* @bus: HDA core bus
|
||||
* @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller
|
||||
* @enable: power up or down
|
||||
*
|
||||
* This function is supposed to be used only by a HD-audio controller
|
||||
* driver that needs the interaction with graphics driver.
|
||||
* This function is used by either HD-audio controller or codec driver that
|
||||
* needs the interaction with graphics driver.
|
||||
*
|
||||
* This function manages a refcount and calls the get_power() and
|
||||
* This function updates the power status, and calls the get_power() and
|
||||
* put_power() ops accordingly, toggling the codec wakeup, too.
|
||||
*
|
||||
* Returns zero for success or a negative error code.
|
||||
*/
|
||||
int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
|
||||
void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)
|
||||
{
|
||||
struct drm_audio_component *acomp = bus->audio_component;
|
||||
|
||||
if (!acomp || !acomp->ops)
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(bus->dev, "display power %s\n",
|
||||
enable ? "enable" : "disable");
|
||||
if (enable)
|
||||
set_bit(idx, &bus->display_power_status);
|
||||
else
|
||||
clear_bit(idx, &bus->display_power_status);
|
||||
|
||||
if (enable) {
|
||||
if (!bus->drm_power_refcount++) {
|
||||
if (!acomp || !acomp->ops)
|
||||
return;
|
||||
|
||||
if (bus->display_power_status) {
|
||||
if (!bus->display_power_active) {
|
||||
if (acomp->ops->get_power)
|
||||
acomp->ops->get_power(acomp->dev);
|
||||
snd_hdac_set_codec_wakeup(bus, true);
|
||||
snd_hdac_set_codec_wakeup(bus, false);
|
||||
bus->display_power_active = true;
|
||||
}
|
||||
} else {
|
||||
WARN_ON(!bus->drm_power_refcount);
|
||||
if (!--bus->drm_power_refcount)
|
||||
if (bus->display_power_active) {
|
||||
if (acomp->ops->put_power)
|
||||
acomp->ops->put_power(acomp->dev);
|
||||
bus->display_power_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_display_power);
|
||||
|
||||
|
@ -321,10 +324,12 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus)
|
|||
if (!acomp)
|
||||
return 0;
|
||||
|
||||
WARN_ON(bus->drm_power_refcount);
|
||||
if (bus->drm_power_refcount > 0 && acomp->ops)
|
||||
if (WARN_ON(bus->display_power_active) && acomp->ops)
|
||||
acomp->ops->put_power(acomp->dev);
|
||||
|
||||
bus->display_power_active = false;
|
||||
bus->display_power_status = 0;
|
||||
|
||||
component_master_del(dev, &hdac_component_master_ops);
|
||||
|
||||
bus->audio_component = NULL;
|
||||
|
|
|
@ -622,23 +622,6 @@ int snd_hdac_power_down_pm(struct hdac_device *codec)
|
|||
EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* snd_hdac_link_power - Enable/disable the link power for a codec
|
||||
* @codec: the codec object
|
||||
* @bool: enable or disable the link power
|
||||
*/
|
||||
int snd_hdac_link_power(struct hdac_device *codec, bool enable)
|
||||
{
|
||||
if (!codec->link_power_control)
|
||||
return 0;
|
||||
|
||||
if (codec->bus->ops->link_power)
|
||||
return codec->bus->ops->link_power(codec->bus, enable);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_link_power);
|
||||
|
||||
/* codec vendor labels */
|
||||
struct hda_vendor_id {
|
||||
unsigned int id;
|
||||
|
|
|
@ -1183,7 +1183,7 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
|
|||
static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,
|
||||
u32 h_stream)
|
||||
{
|
||||
struct hpi_format hpi_format;
|
||||
struct hpi_format hpi_format;
|
||||
u16 format;
|
||||
u16 err;
|
||||
u32 h_control;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/nospec.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/tlv.h>
|
||||
|
@ -1026,6 +1027,8 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
|
|||
|
||||
if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
|
||||
return -EINVAL;
|
||||
ipcm->substream = array_index_nospec(ipcm->substream,
|
||||
EMU10K1_FX8010_PCM_COUNT);
|
||||
if (ipcm->channels > 32)
|
||||
return -EINVAL;
|
||||
pcm = &emu->fx8010.pcm[ipcm->substream];
|
||||
|
@ -1072,6 +1075,8 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
|
|||
|
||||
if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
|
||||
return -EINVAL;
|
||||
ipcm->substream = array_index_nospec(ipcm->substream,
|
||||
EMU10K1_FX8010_PCM_COUNT);
|
||||
pcm = &emu->fx8010.pcm[ipcm->substream];
|
||||
mutex_lock(&emu->fx8010.lock);
|
||||
spin_lock_irq(&emu->reg_lock);
|
||||
|
|
|
@ -226,6 +226,68 @@ config SND_HDA_POWER_SAVE_DEFAULT
|
|||
The default time-out value in seconds for HD-audio automatic
|
||||
power-save mode. 0 means to disable the power-save mode.
|
||||
|
||||
if SND_HDA_INTEL
|
||||
|
||||
# The options below should not be enabled by distributions or
|
||||
# users. They are selected by Intel/Skylake or SOF drivers when they
|
||||
# register for a PCI ID which is also handled by the HDAudio legacy
|
||||
# driver. When this option is selected and the DSP is detected based on
|
||||
# the PCI class/subclass/prog-if, the probe of the HDAudio legacy
|
||||
# aborts. This mechanism removes the need for distributions to use
|
||||
# blacklists. It can be bypassed with module parameters should the
|
||||
# Intel/Skylake or SOF drivers fail to handle a specific platform.
|
||||
|
||||
config SND_HDA_INTEL_DSP_DETECTION_SKL
|
||||
bool
|
||||
help
|
||||
This option is selected by SOF or SST drivers, not users or distros.
|
||||
It enables DSP detection based on PCI class information for
|
||||
Skylake machines.
|
||||
|
||||
config SND_HDA_INTEL_DSP_DETECTION_APL
|
||||
bool
|
||||
help
|
||||
This option is selected by SOF or SST drivers, not users or distros.
|
||||
It enables DSP detection based on PCI class information for
|
||||
Broxton/ApolloLake machines
|
||||
|
||||
config SND_HDA_INTEL_DSP_DETECTION_KBL
|
||||
bool
|
||||
help
|
||||
This option is selected by SOF or SST drivers, not users or distros.
|
||||
It enables DSP detection based on PCI class information for
|
||||
KabyLake machines
|
||||
|
||||
config SND_HDA_INTEL_DSP_DETECTION_GLK
|
||||
bool
|
||||
help
|
||||
This option is selected by SOF or SST drivers, not users or distros.
|
||||
It enables DSP detection based on PCI class information for
|
||||
GeminiLake machines
|
||||
|
||||
config SND_HDA_INTEL_DSP_DETECTION_CNL
|
||||
bool
|
||||
help
|
||||
This option is selected by SOF or SST drivers, not users or distros.
|
||||
It enables DSP detection based on PCI class information for
|
||||
CannonLake machines
|
||||
|
||||
config SND_HDA_INTEL_DSP_DETECTION_CFL
|
||||
bool
|
||||
help
|
||||
This option is selected by SOF or SST drivers, not users or distros.
|
||||
It enables DSP detection based on PCI class information for
|
||||
CoffeeLake machines
|
||||
|
||||
config SND_HDA_INTEL_DSP_DETECTION_ICL
|
||||
bool
|
||||
help
|
||||
This option is selected by SOF or SST drivers, not users or distros.
|
||||
It enables DSP detection based on PCI class information for
|
||||
IceLake machines
|
||||
|
||||
endif ## SND_HDA_INTEL
|
||||
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Helper functions for Dell Mic Mute LED control;
|
||||
* to be included from codec driver
|
||||
*/
|
||||
|
||||
#if IS_ENABLED(CONFIG_DELL_LAPTOP)
|
||||
#include <linux/dell-led.h>
|
||||
|
||||
static int (*dell_micmute_led_set_func)(int);
|
||||
|
||||
static void dell_micmute_update(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
|
||||
dell_micmute_led_set_func(spec->micmute_led.led_value);
|
||||
}
|
||||
|
||||
static void alc_fixup_dell_wmi(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
bool removefunc = false;
|
||||
|
||||
if (action == HDA_FIXUP_ACT_PROBE) {
|
||||
if (!dell_micmute_led_set_func)
|
||||
dell_micmute_led_set_func = symbol_request(dell_micmute_led_set);
|
||||
if (!dell_micmute_led_set_func) {
|
||||
codec_warn(codec, "Failed to find dell wmi symbol dell_micmute_led_set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
removefunc = (dell_micmute_led_set_func(false) < 0) ||
|
||||
(snd_hda_gen_add_micmute_led(codec,
|
||||
dell_micmute_update) < 0);
|
||||
}
|
||||
|
||||
if (dell_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
|
||||
symbol_put(dell_micmute_led_set);
|
||||
dell_micmute_led_set_func = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* CONFIG_DELL_LAPTOP */
|
||||
static void alc_fixup_dell_wmi(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DELL_LAPTOP */
|
|
@ -36,6 +36,7 @@
|
|||
#include "hda_beep.h"
|
||||
#include "hda_jack.h"
|
||||
#include <sound/hda_hwdep.h>
|
||||
#include <sound/hda_component.h>
|
||||
|
||||
#define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core)
|
||||
#define hda_codec_is_power_on(codec) snd_hdac_is_power_on(&codec->core)
|
||||
|
@ -799,6 +800,13 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
|
|||
static unsigned int hda_set_power_state(struct hda_codec *codec,
|
||||
unsigned int power_state);
|
||||
|
||||
/* enable/disable display power per codec */
|
||||
static void codec_display_power(struct hda_codec *codec, bool enable)
|
||||
{
|
||||
if (codec->display_power_control)
|
||||
snd_hdac_display_power(&codec->bus->core, codec->addr, enable);
|
||||
}
|
||||
|
||||
/* also called from hda_bind.c */
|
||||
void snd_hda_codec_register(struct hda_codec *codec)
|
||||
{
|
||||
|
@ -806,7 +814,7 @@ void snd_hda_codec_register(struct hda_codec *codec)
|
|||
return;
|
||||
if (device_is_registered(hda_codec_dev(codec))) {
|
||||
snd_hda_register_beep_device(codec);
|
||||
snd_hdac_link_power(&codec->core, true);
|
||||
codec_display_power(codec, true);
|
||||
pm_runtime_enable(hda_codec_dev(codec));
|
||||
/* it was powered up in snd_hda_codec_new(), now all done */
|
||||
snd_hda_power_down(codec);
|
||||
|
@ -834,7 +842,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
|
|||
|
||||
codec->in_freeing = 1;
|
||||
snd_hdac_device_unregister(&codec->core);
|
||||
snd_hdac_link_power(&codec->core, false);
|
||||
codec_display_power(codec, false);
|
||||
put_device(hda_codec_dev(codec));
|
||||
return 0;
|
||||
}
|
||||
|
@ -2926,7 +2934,7 @@ static int hda_codec_runtime_suspend(struct device *dev)
|
|||
(codec_has_clkstop(codec) && codec_has_epss(codec) &&
|
||||
(state & AC_PWRST_CLK_STOP_OK)))
|
||||
snd_hdac_codec_link_down(&codec->core);
|
||||
snd_hdac_link_power(&codec->core, false);
|
||||
codec_display_power(codec, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2934,7 +2942,7 @@ static int hda_codec_runtime_resume(struct device *dev)
|
|||
{
|
||||
struct hda_codec *codec = dev_to_hda_codec(dev);
|
||||
|
||||
snd_hdac_link_power(&codec->core, true);
|
||||
codec_display_power(codec, true);
|
||||
snd_hdac_codec_link_up(&codec->core);
|
||||
hda_call_codec_resume(codec);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
|
|
|
@ -989,20 +989,9 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr,
|
|||
return azx_rirb_get_response(bus, addr, res);
|
||||
}
|
||||
|
||||
static int azx_link_power(struct hdac_bus *bus, bool enable)
|
||||
{
|
||||
struct azx *chip = bus_to_azx(bus);
|
||||
|
||||
if (chip->ops->link_power)
|
||||
return chip->ops->link_power(chip, enable);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct hdac_bus_ops bus_core_ops = {
|
||||
.command = azx_send_cmd,
|
||||
.get_response = azx_get_response,
|
||||
.link_power = azx_link_power,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SND_HDA_DSP_LOADER
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#else
|
||||
#define AZX_DCAPS_I915_COMPONENT 0 /* NOP */
|
||||
#endif
|
||||
/* 14 unused */
|
||||
#define AZX_DCAPS_INTEL_SHARED (1 << 14) /* shared with ASoC */
|
||||
#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */
|
||||
#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */
|
||||
/* 17 unused */
|
||||
|
@ -50,11 +50,7 @@
|
|||
/* 24 unused */
|
||||
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
|
||||
#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
|
||||
#ifdef CONFIG_SND_HDA_I915
|
||||
#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */
|
||||
#else
|
||||
#define AZX_DCAPS_I915_POWERWELL 0 /* NOP */
|
||||
#endif
|
||||
/* 27 unused */
|
||||
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
|
||||
#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
|
||||
#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/leds.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/tlv.h>
|
||||
|
@ -4035,6 +4036,36 @@ int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led);
|
||||
|
||||
#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
|
||||
static void call_ledtrig_micmute(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
|
||||
ledtrig_audio_set(LED_AUDIO_MICMUTE,
|
||||
spec->micmute_led.led_value ? LED_ON : LED_OFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* snd_hda_gen_fixup_micmute_led - A fixup for mic-mute LED trigger
|
||||
*
|
||||
* Pass this function to the quirk entry if another driver supports the
|
||||
* audio mic-mute LED trigger. Then this will bind the mixer capture switch
|
||||
* change with the LED.
|
||||
*
|
||||
* Note that this fixup has to be called after other fixup that sets
|
||||
* cap_sync_hook. Otherwise the chaining wouldn't work.
|
||||
*/
|
||||
void snd_hda_gen_fixup_micmute_led(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
|
||||
if (action == HDA_FIXUP_ACT_PROBE)
|
||||
snd_hda_gen_add_micmute_led(codec, call_ledtrig_micmute);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_gen_fixup_micmute_led);
|
||||
|
||||
/*
|
||||
* parse digital I/Os and set up NIDs in BIOS auto-parse mode
|
||||
*/
|
||||
|
|
|
@ -357,5 +357,7 @@ int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
|
|||
|
||||
int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
|
||||
void (*hook)(struct hda_codec *));
|
||||
void snd_hda_gen_fixup_micmute_led(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action);
|
||||
|
||||
#endif /* __SOUND_HDA_GENERIC_H */
|
||||
|
|
|
@ -172,6 +172,9 @@ module_param_array(beep_mode, bool, NULL, 0444);
|
|||
MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
|
||||
"(0=off, 1=on) (default=1).");
|
||||
#endif
|
||||
static int skl_pci_binding;
|
||||
module_param_named(pci_binding, skl_pci_binding, int, 0444);
|
||||
MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc");
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int param_set_xint(const char *val, const struct kernel_param *kp);
|
||||
|
@ -310,31 +313,28 @@ enum {
|
|||
#define AZX_DCAPS_INTEL_HASWELL \
|
||||
(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
|
||||
AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
|
||||
AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH))
|
||||
AZX_DCAPS_SNOOP_TYPE(SCH))
|
||||
|
||||
/* Broadwell HDMI can't use position buffer reliably, force to use LPIB */
|
||||
#define AZX_DCAPS_INTEL_BROADWELL \
|
||||
(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\
|
||||
AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
|
||||
AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH))
|
||||
AZX_DCAPS_SNOOP_TYPE(SCH))
|
||||
|
||||
#define AZX_DCAPS_INTEL_BAYTRAIL \
|
||||
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT |\
|
||||
AZX_DCAPS_I915_POWERWELL)
|
||||
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT)
|
||||
|
||||
#define AZX_DCAPS_INTEL_BRASWELL \
|
||||
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
|
||||
AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL)
|
||||
AZX_DCAPS_I915_COMPONENT)
|
||||
|
||||
#define AZX_DCAPS_INTEL_SKYLAKE \
|
||||
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
|
||||
AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\
|
||||
AZX_DCAPS_I915_POWERWELL)
|
||||
AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
|
||||
|
||||
#define AZX_DCAPS_INTEL_BROXTON \
|
||||
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
|
||||
AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\
|
||||
AZX_DCAPS_I915_POWERWELL)
|
||||
AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
|
||||
|
||||
/* quirks for ATI SB / AMD Hudson */
|
||||
#define AZX_DCAPS_PRESET_ATI_SB \
|
||||
|
@ -360,6 +360,7 @@ enum {
|
|||
AZX_DCAPS_NO_64BIT |\
|
||||
AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF)
|
||||
|
||||
#define AZX_DCAPS_INTEL_DSP_DETECTION(conf) (IS_ENABLED(CONFIG_SND_HDA_INTEL_DSP_DETECTION_##conf) ? AZX_DCAPS_INTEL_SHARED : 0)
|
||||
/*
|
||||
* vga_switcheroo support
|
||||
*/
|
||||
|
@ -591,8 +592,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
|
|||
struct pci_dev *pci = chip->pci;
|
||||
u32 val;
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
snd_hdac_set_codec_wakeup(bus, true);
|
||||
snd_hdac_set_codec_wakeup(bus, true);
|
||||
if (chip->driver_type == AZX_DRIVER_SKL) {
|
||||
pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
|
||||
val = val & ~INTEL_HDA_CGCTL_MISCBDCGE;
|
||||
|
@ -604,8 +604,8 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
|
|||
val = val | INTEL_HDA_CGCTL_MISCBDCGE;
|
||||
pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
|
||||
}
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
snd_hdac_set_codec_wakeup(bus, false);
|
||||
|
||||
snd_hdac_set_codec_wakeup(bus, false);
|
||||
|
||||
/* reduce dma latency to avoid noise */
|
||||
if (IS_BXT(pci))
|
||||
|
@ -667,13 +667,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Enable/disable i915 display power for the link */
|
||||
static int azx_intel_link_power(struct azx *chip, bool enable)
|
||||
{
|
||||
struct hdac_bus *bus = azx_bus(chip);
|
||||
|
||||
return snd_hdac_display_power(bus, enable);
|
||||
}
|
||||
#define display_power(chip, enable) \
|
||||
snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable)
|
||||
|
||||
/*
|
||||
* Check whether the current DMA position is acceptable for updating
|
||||
|
@ -930,35 +925,75 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
|
|||
mutex_unlock(&card_list_lock);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define azx_add_card_list(chip) /* NOP */
|
||||
#define azx_del_card_list(chip) /* NOP */
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/*
|
||||
* power management
|
||||
*/
|
||||
static bool azx_is_pm_ready(struct snd_card *card)
|
||||
{
|
||||
struct azx *chip;
|
||||
struct hda_intel *hda;
|
||||
|
||||
if (!card)
|
||||
return false;
|
||||
chip = card->private_data;
|
||||
hda = container_of(chip, struct hda_intel, chip);
|
||||
if (chip->disabled || hda->init_failed || !chip->running)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __azx_runtime_suspend(struct azx *chip)
|
||||
{
|
||||
azx_stop_chip(chip);
|
||||
azx_enter_link_reset(chip);
|
||||
azx_clear_irq_pending(chip);
|
||||
display_power(chip, false);
|
||||
}
|
||||
|
||||
static void __azx_runtime_resume(struct azx *chip)
|
||||
{
|
||||
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
|
||||
struct hdac_bus *bus = azx_bus(chip);
|
||||
struct hda_codec *codec;
|
||||
int status;
|
||||
|
||||
display_power(chip, true);
|
||||
if (hda->need_i915_power)
|
||||
snd_hdac_i915_set_bclk(bus);
|
||||
|
||||
/* Read STATESTS before controller reset */
|
||||
status = azx_readw(chip, STATESTS);
|
||||
|
||||
azx_init_pci(chip);
|
||||
hda_intel_init_chip(chip, true);
|
||||
|
||||
if (status) {
|
||||
list_for_each_codec(codec, &chip->bus)
|
||||
if (status & (1 << codec->addr))
|
||||
schedule_delayed_work(&codec->jackpoll_work,
|
||||
codec->jackpoll_interval);
|
||||
}
|
||||
|
||||
/* power down again for link-controlled chips */
|
||||
if (!hda->need_i915_power)
|
||||
display_power(chip, false);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int azx_suspend(struct device *dev)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip;
|
||||
struct hda_intel *hda;
|
||||
struct hdac_bus *bus;
|
||||
|
||||
if (!card)
|
||||
if (!azx_is_pm_ready(card))
|
||||
return 0;
|
||||
|
||||
chip = card->private_data;
|
||||
hda = container_of(chip, struct hda_intel, chip);
|
||||
if (chip->disabled || hda->init_failed || !chip->running)
|
||||
return 0;
|
||||
|
||||
bus = azx_bus(chip);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
azx_clear_irq_pending(chip);
|
||||
azx_stop_chip(chip);
|
||||
azx_enter_link_reset(chip);
|
||||
__azx_runtime_suspend(chip);
|
||||
if (bus->irq >= 0) {
|
||||
free_irq(bus->irq, chip);
|
||||
bus->irq = -1;
|
||||
|
@ -966,9 +1001,6 @@ static int azx_suspend(struct device *dev)
|
|||
|
||||
if (chip->msi)
|
||||
pci_disable_msi(chip->pci);
|
||||
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
&& hda->need_i915_power)
|
||||
snd_hdac_display_power(bus, false);
|
||||
|
||||
trace_azx_suspend(chip);
|
||||
return 0;
|
||||
|
@ -976,41 +1008,19 @@ static int azx_suspend(struct device *dev)
|
|||
|
||||
static int azx_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev);
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip;
|
||||
struct hda_intel *hda;
|
||||
struct hdac_bus *bus;
|
||||
|
||||
if (!card)
|
||||
if (!azx_is_pm_ready(card))
|
||||
return 0;
|
||||
|
||||
chip = card->private_data;
|
||||
hda = container_of(chip, struct hda_intel, chip);
|
||||
bus = azx_bus(chip);
|
||||
if (chip->disabled || hda->init_failed || !chip->running)
|
||||
return 0;
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
snd_hdac_display_power(bus, true);
|
||||
if (hda->need_i915_power)
|
||||
snd_hdac_i915_set_bclk(bus);
|
||||
}
|
||||
|
||||
if (chip->msi)
|
||||
if (pci_enable_msi(pci) < 0)
|
||||
if (pci_enable_msi(chip->pci) < 0)
|
||||
chip->msi = 0;
|
||||
if (azx_acquire_irq(chip, 1) < 0)
|
||||
return -EIO;
|
||||
azx_init_pci(chip);
|
||||
|
||||
hda_intel_init_chip(chip, true);
|
||||
|
||||
/* power down again for link-controlled chips */
|
||||
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
|
||||
!hda->need_i915_power)
|
||||
snd_hdac_display_power(bus, false);
|
||||
|
||||
__azx_runtime_resume(chip);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
|
||||
trace_azx_resume(chip);
|
||||
|
@ -1045,21 +1055,14 @@ static int azx_thaw_noirq(struct device *dev)
|
|||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int azx_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip;
|
||||
struct hda_intel *hda;
|
||||
|
||||
if (!card)
|
||||
if (!azx_is_pm_ready(card))
|
||||
return 0;
|
||||
|
||||
chip = card->private_data;
|
||||
hda = container_of(chip, struct hda_intel, chip);
|
||||
if (chip->disabled || hda->init_failed)
|
||||
return 0;
|
||||
|
||||
if (!azx_has_pm_runtime(chip))
|
||||
return 0;
|
||||
|
||||
|
@ -1067,13 +1070,7 @@ static int azx_runtime_suspend(struct device *dev)
|
|||
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
|
||||
STATESTS_INT_MASK);
|
||||
|
||||
azx_stop_chip(chip);
|
||||
azx_enter_link_reset(chip);
|
||||
azx_clear_irq_pending(chip);
|
||||
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
&& hda->need_i915_power)
|
||||
snd_hdac_display_power(azx_bus(chip), false);
|
||||
|
||||
__azx_runtime_suspend(chip);
|
||||
trace_azx_runtime_suspend(chip);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1082,51 +1079,18 @@ static int azx_runtime_resume(struct device *dev)
|
|||
{
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip;
|
||||
struct hda_intel *hda;
|
||||
struct hdac_bus *bus;
|
||||
struct hda_codec *codec;
|
||||
int status;
|
||||
|
||||
if (!card)
|
||||
if (!azx_is_pm_ready(card))
|
||||
return 0;
|
||||
|
||||
chip = card->private_data;
|
||||
hda = container_of(chip, struct hda_intel, chip);
|
||||
bus = azx_bus(chip);
|
||||
if (chip->disabled || hda->init_failed)
|
||||
return 0;
|
||||
|
||||
if (!azx_has_pm_runtime(chip))
|
||||
return 0;
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
snd_hdac_display_power(bus, true);
|
||||
if (hda->need_i915_power)
|
||||
snd_hdac_i915_set_bclk(bus);
|
||||
}
|
||||
|
||||
/* Read STATESTS before controller reset */
|
||||
status = azx_readw(chip, STATESTS);
|
||||
|
||||
azx_init_pci(chip);
|
||||
hda_intel_init_chip(chip, true);
|
||||
|
||||
if (status) {
|
||||
list_for_each_codec(codec, &chip->bus)
|
||||
if (status & (1 << codec->addr))
|
||||
schedule_delayed_work(&codec->jackpoll_work,
|
||||
codec->jackpoll_interval);
|
||||
}
|
||||
__azx_runtime_resume(chip);
|
||||
|
||||
/* disable controller Wake Up event*/
|
||||
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
|
||||
~STATESTS_INT_MASK);
|
||||
|
||||
/* power down again for link-controlled chips */
|
||||
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
|
||||
!hda->need_i915_power)
|
||||
snd_hdac_display_power(bus, false);
|
||||
|
||||
trace_azx_runtime_resume(chip);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1167,6 +1131,8 @@ static const struct dev_pm_ops azx_pm = {
|
|||
|
||||
#define AZX_PM_OPS &azx_pm
|
||||
#else
|
||||
#define azx_add_card_list(chip) /* NOP */
|
||||
#define azx_del_card_list(chip) /* NOP */
|
||||
#define AZX_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
@ -1374,11 +1340,8 @@ static int azx_free(struct azx *chip)
|
|||
#ifdef CONFIG_SND_HDA_PATCH_LOADER
|
||||
release_firmware(chip->fw);
|
||||
#endif
|
||||
display_power(chip, false);
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
if (hda->need_i915_power)
|
||||
snd_hdac_display_power(bus, false);
|
||||
}
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT)
|
||||
snd_hdac_i915_exit(bus);
|
||||
kfree(hda);
|
||||
|
@ -1935,8 +1898,7 @@ static int azx_first_init(struct azx *chip)
|
|||
/* initialize chip */
|
||||
azx_init_pci(chip);
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
snd_hdac_i915_set_bclk(bus);
|
||||
snd_hdac_i915_set_bclk(bus);
|
||||
|
||||
hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0);
|
||||
|
||||
|
@ -2078,7 +2040,6 @@ static const struct hda_controller_ops pci_hda_ops = {
|
|||
.disable_msi_reset_irq = disable_msi_reset_irq,
|
||||
.pcm_mmap_prepare = pcm_mmap_prepare,
|
||||
.position_check = azx_position_check,
|
||||
.link_power = azx_intel_link_power,
|
||||
};
|
||||
|
||||
static int azx_probe(struct pci_dev *pci,
|
||||
|
@ -2091,6 +2052,28 @@ static int azx_probe(struct pci_dev *pci,
|
|||
bool schedule_probe;
|
||||
int err;
|
||||
|
||||
/* check if this driver can be used on SKL+ Intel platforms */
|
||||
if (pci_id->driver_data & AZX_DCAPS_INTEL_SHARED) {
|
||||
switch (skl_pci_binding) {
|
||||
case SND_SKL_PCI_BIND_AUTO:
|
||||
if (pci->class != 0x040300) {
|
||||
dev_info(&pci->dev, "The DSP is enabled on this platform, aborting probe\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_info(&pci->dev, "No DSP detected, continuing HDaudio legacy probe\n");
|
||||
break;
|
||||
case SND_SKL_PCI_BIND_LEGACY:
|
||||
dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, bypassed detection logic\n");
|
||||
break;
|
||||
case SND_SKL_PCI_BIND_ASOC:
|
||||
dev_info(&pci->dev, "Module parameter forced binding with SKL+ ASoC driver, aborting probe\n");
|
||||
return -ENODEV;
|
||||
default:
|
||||
dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev >= SNDRV_CARDS)
|
||||
return -ENODEV;
|
||||
if (!enable[dev]) {
|
||||
|
@ -2245,10 +2228,13 @@ static int azx_probe_continue(struct azx *chip)
|
|||
goto out_free;
|
||||
} else {
|
||||
/* don't bother any longer */
|
||||
chip->driver_caps &=
|
||||
~(AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL);
|
||||
chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* HSW/BDW controllers need this power */
|
||||
if (CONTROLLER_IN_GPU(pci))
|
||||
hda->need_i915_power = 1;
|
||||
}
|
||||
|
||||
/* Request display power well for the HDA controller or codec. For
|
||||
|
@ -2256,18 +2242,7 @@ static int azx_probe_continue(struct azx *chip)
|
|||
* this power. For other platforms, like Baytrail/Braswell, only the
|
||||
* display codec needs the power and it can be released after probe.
|
||||
*/
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
/* HSW/BDW controllers need this power */
|
||||
if (CONTROLLER_IN_GPU(pci))
|
||||
hda->need_i915_power = 1;
|
||||
|
||||
err = snd_hdac_display_power(bus, true);
|
||||
if (err < 0) {
|
||||
dev_err(chip->card->dev,
|
||||
"Cannot turn on display power on i915\n");
|
||||
goto i915_power_fail;
|
||||
}
|
||||
}
|
||||
display_power(chip, true);
|
||||
|
||||
err = azx_first_init(chip);
|
||||
if (err < 0)
|
||||
|
@ -2315,11 +2290,8 @@ static int azx_probe_continue(struct azx *chip)
|
|||
pm_runtime_put_autosuspend(&pci->dev);
|
||||
|
||||
out_free:
|
||||
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
&& !hda->need_i915_power)
|
||||
snd_hdac_display_power(bus, false);
|
||||
|
||||
i915_power_fail:
|
||||
if (err < 0 || !hda->need_i915_power)
|
||||
display_power(chip, false);
|
||||
if (err < 0)
|
||||
hda->init_failed = 1;
|
||||
complete_all(&hda->probe_wait);
|
||||
|
@ -2408,34 +2380,48 @@ static const struct pci_device_id azx_ids[] = {
|
|||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
|
||||
/* Sunrise Point-LP */
|
||||
{ PCI_DEVICE(0x8086, 0x9d70),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
|
||||
AZX_DCAPS_INTEL_DSP_DETECTION(SKL)
|
||||
},
|
||||
/* Kabylake */
|
||||
{ PCI_DEVICE(0x8086, 0xa171),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
|
||||
/* Kabylake-LP */
|
||||
{ PCI_DEVICE(0x8086, 0x9d71),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
|
||||
AZX_DCAPS_INTEL_DSP_DETECTION(KBL)
|
||||
},
|
||||
/* Kabylake-H */
|
||||
{ PCI_DEVICE(0x8086, 0xa2f0),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
|
||||
/* Coffelake */
|
||||
{ PCI_DEVICE(0x8086, 0xa348),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
|
||||
AZX_DCAPS_INTEL_DSP_DETECTION(CFL)
|
||||
},
|
||||
/* Cannonlake */
|
||||
{ PCI_DEVICE(0x8086, 0x9dc8),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
|
||||
AZX_DCAPS_INTEL_DSP_DETECTION(CNL)
|
||||
},
|
||||
/* Icelake */
|
||||
{ PCI_DEVICE(0x8086, 0x34c8),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE |
|
||||
AZX_DCAPS_INTEL_DSP_DETECTION(ICL)
|
||||
},
|
||||
/* Broxton-P(Apollolake) */
|
||||
{ PCI_DEVICE(0x8086, 0x5a98),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON |
|
||||
AZX_DCAPS_INTEL_DSP_DETECTION(APL)
|
||||
},
|
||||
/* Broxton-T */
|
||||
{ PCI_DEVICE(0x8086, 0x1a98),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
|
||||
/* Gemini-Lake */
|
||||
{ PCI_DEVICE(0x8086, 0x3198),
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
|
||||
.driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON |
|
||||
AZX_DCAPS_INTEL_DSP_DETECTION(GLK)
|
||||
},
|
||||
/* Haswell */
|
||||
{ PCI_DEVICE(0x8086, 0x0a0c),
|
||||
.driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
|
||||
|
|
|
@ -339,9 +339,15 @@ void snd_hda_jack_report_sync(struct hda_codec *codec)
|
|||
if (jack->nid) {
|
||||
if (!jack->jack || jack->block_report)
|
||||
continue;
|
||||
state = get_jack_plug_state(jack->pin_sense);
|
||||
snd_jack_report(jack->jack,
|
||||
state ? jack->type : 0);
|
||||
state = jack->button_state;
|
||||
if (get_jack_plug_state(jack->pin_sense))
|
||||
state |= jack->type;
|
||||
snd_jack_report(jack->jack, state);
|
||||
if (jack->button_state) {
|
||||
snd_jack_report(jack->jack,
|
||||
state & ~jack->button_state);
|
||||
jack->button_state = 0; /* button released */
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync);
|
||||
|
@ -379,15 +385,19 @@ static void hda_free_jack_priv(struct snd_jack *jack)
|
|||
* @nid: pin NID to assign
|
||||
* @name: string name for the jack
|
||||
* @phantom_jack: flag to deal as a phantom jack
|
||||
* @type: jack type bits to be reported, 0 for guessing from pincfg
|
||||
* @keymap: optional jack / key mapping
|
||||
*
|
||||
* This assigns a jack-detection kctl to the given pin. The kcontrol
|
||||
* will have the given name and index.
|
||||
*/
|
||||
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
|
||||
const char *name, bool phantom_jack)
|
||||
const char *name, bool phantom_jack,
|
||||
int type, const struct hda_jack_keymap *keymap)
|
||||
{
|
||||
struct hda_jack_tbl *jack;
|
||||
int err, state, type;
|
||||
const struct hda_jack_keymap *map;
|
||||
int err, state, buttons;
|
||||
|
||||
jack = snd_hda_jack_tbl_new(codec, nid);
|
||||
if (!jack)
|
||||
|
@ -395,16 +405,30 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
|
|||
if (jack->jack)
|
||||
return 0; /* already created */
|
||||
|
||||
type = get_input_jack_type(codec, nid);
|
||||
err = snd_jack_new(codec->card, name, type,
|
||||
if (!type)
|
||||
type = get_input_jack_type(codec, nid);
|
||||
|
||||
buttons = 0;
|
||||
if (keymap) {
|
||||
for (map = keymap; map->type; map++)
|
||||
buttons |= map->type;
|
||||
}
|
||||
|
||||
err = snd_jack_new(codec->card, name, type | buttons,
|
||||
&jack->jack, true, phantom_jack);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
jack->phantom_jack = !!phantom_jack;
|
||||
jack->type = type;
|
||||
jack->button_state = 0;
|
||||
jack->jack->private_data = jack;
|
||||
jack->jack->private_free = hda_free_jack_priv;
|
||||
if (keymap) {
|
||||
for (map = keymap; map->type; map++)
|
||||
snd_jack_set_key(jack->jack, map->type, map->key);
|
||||
}
|
||||
|
||||
state = snd_hda_jack_detect(codec, nid);
|
||||
snd_jack_report(jack->jack, state ? jack->type : 0);
|
||||
|
||||
|
@ -437,7 +461,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
|
|||
if (phantom_jack)
|
||||
/* Example final name: "Internal Mic Phantom Jack" */
|
||||
strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
|
||||
err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack);
|
||||
err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -508,19 +532,25 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls);
|
||||
|
||||
static void call_jack_callback(struct hda_codec *codec,
|
||||
static void call_jack_callback(struct hda_codec *codec, unsigned int res,
|
||||
struct hda_jack_tbl *jack)
|
||||
{
|
||||
struct hda_jack_callback *cb;
|
||||
|
||||
for (cb = jack->callback; cb; cb = cb->next)
|
||||
for (cb = jack->callback; cb; cb = cb->next) {
|
||||
cb->jack = jack;
|
||||
cb->unsol_res = res;
|
||||
cb->func(codec, cb);
|
||||
}
|
||||
if (jack->gated_jack) {
|
||||
struct hda_jack_tbl *gated =
|
||||
snd_hda_jack_tbl_get(codec, jack->gated_jack);
|
||||
if (gated) {
|
||||
for (cb = gated->callback; cb; cb = cb->next)
|
||||
for (cb = gated->callback; cb; cb = cb->next) {
|
||||
cb->jack = gated;
|
||||
cb->unsol_res = res;
|
||||
cb->func(codec, cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -540,7 +570,7 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
|
|||
return;
|
||||
event->jack_dirty = 1;
|
||||
|
||||
call_jack_callback(codec, event);
|
||||
call_jack_callback(codec, res, event);
|
||||
snd_hda_jack_report_sync(codec);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event);
|
||||
|
@ -566,7 +596,7 @@ void snd_hda_jack_poll_all(struct hda_codec *codec)
|
|||
if (old_sense == get_jack_plug_state(jack->pin_sense))
|
||||
continue;
|
||||
changes = 1;
|
||||
call_jack_callback(codec, jack);
|
||||
call_jack_callback(codec, 0, jack);
|
||||
}
|
||||
if (changes)
|
||||
snd_hda_jack_report_sync(codec);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define __SOUND_HDA_JACK_H
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <sound/jack.h>
|
||||
|
||||
struct auto_pin_cfg;
|
||||
struct hda_jack_tbl;
|
||||
|
@ -24,6 +25,8 @@ struct hda_jack_callback {
|
|||
hda_nid_t nid;
|
||||
hda_jack_callback_fn func;
|
||||
unsigned int private_data; /* arbitrary data */
|
||||
unsigned int unsol_res; /* unsolicited event bits */
|
||||
struct hda_jack_tbl *jack; /* associated jack entry */
|
||||
struct hda_jack_callback *next;
|
||||
};
|
||||
|
||||
|
@ -40,9 +43,15 @@ struct hda_jack_tbl {
|
|||
hda_nid_t gating_jack; /* valid when gating jack plugged */
|
||||
hda_nid_t gated_jack; /* gated is dependent on this jack */
|
||||
int type;
|
||||
int button_state;
|
||||
struct snd_jack *jack;
|
||||
};
|
||||
|
||||
struct hda_jack_keymap {
|
||||
enum snd_jack_types type;
|
||||
int key;
|
||||
};
|
||||
|
||||
struct hda_jack_tbl *
|
||||
snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid);
|
||||
struct hda_jack_tbl *
|
||||
|
@ -82,7 +91,8 @@ static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
|
|||
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
|
||||
|
||||
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
|
||||
const char *name, bool phantom_jack);
|
||||
const char *name, bool phantom_jack,
|
||||
int type, const struct hda_jack_keymap *keymap);
|
||||
int snd_hda_jack_add_kctls(struct hda_codec *codec,
|
||||
const struct auto_pin_cfg *cfg);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
|
@ -344,6 +345,8 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
|
|||
int err;
|
||||
unsigned short gcap;
|
||||
int irq_id = platform_get_irq(pdev, 0);
|
||||
const char *sname;
|
||||
struct device_node *root;
|
||||
|
||||
err = hda_tegra_init_chip(chip, pdev);
|
||||
if (err)
|
||||
|
@ -401,8 +404,23 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* driver name */
|
||||
strcpy(card->driver, "tegra-hda");
|
||||
strcpy(card->shortname, "tegra-hda");
|
||||
|
||||
root = of_find_node_by_path("/");
|
||||
sname = of_get_property(root, "compatible", NULL);
|
||||
of_node_put(root);
|
||||
if (!sname) {
|
||||
dev_err(card->dev,
|
||||
"failed to get compatible property from root node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
/* shortname for card */
|
||||
if (strlen(sname) > sizeof(card->shortname))
|
||||
dev_info(card->dev, "truncating shortname for card\n");
|
||||
strncpy(card->shortname, sname, sizeof(card->shortname));
|
||||
|
||||
/* longname for card */
|
||||
snprintf(card->longname, sizeof(card->longname),
|
||||
"%s at 0x%lx irq %i",
|
||||
card->shortname, bus->addr, bus->irq);
|
||||
|
@ -513,7 +531,7 @@ static void hda_tegra_probe_work(struct work_struct *work)
|
|||
goto out_free;
|
||||
|
||||
/* create codec instances */
|
||||
err = azx_probe_codecs(chip, 0);
|
||||
err = azx_probe_codecs(chip, 8);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
|
||||
|
|
|
@ -1081,6 +1081,18 @@ enum {
|
|||
QUIRK_AE5,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#define ca0132_quirk(spec) ((spec)->quirk)
|
||||
#define ca0132_use_pci_mmio(spec) ((spec)->use_pci_mmio)
|
||||
#define ca0132_use_alt_functions(spec) ((spec)->use_alt_functions)
|
||||
#define ca0132_use_alt_controls(spec) ((spec)->use_alt_controls)
|
||||
#else
|
||||
#define ca0132_quirk(spec) ({ (void)(spec); QUIRK_NONE; })
|
||||
#define ca0132_use_alt_functions(spec) ({ (void)(spec); false; })
|
||||
#define ca0132_use_pci_mmio(spec) ({ (void)(spec); false; })
|
||||
#define ca0132_use_alt_controls(spec) ({ (void)(spec); false; })
|
||||
#endif
|
||||
|
||||
static const struct hda_pintbl alienware_pincfgs[] = {
|
||||
{ 0x0b, 0x90170110 }, /* Builtin Speaker */
|
||||
{ 0x0c, 0x411111f0 }, /* N/A */
|
||||
|
@ -3101,7 +3113,7 @@ static void dspload_post_setup(struct hda_codec *codec)
|
|||
{
|
||||
struct ca0132_spec *spec = codec->spec;
|
||||
codec_dbg(codec, "---- dspload_post_setup ------\n");
|
||||
if (!spec->use_alt_functions) {
|
||||
if (!ca0132_use_alt_functions(spec)) {
|
||||
/*set DSP speaker to 2.0 configuration*/
|
||||
chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080);
|
||||
chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x19), 0x3f800000);
|
||||
|
@ -3333,7 +3345,7 @@ static void ca0132_gpio_init(struct hda_codec *codec)
|
|||
{
|
||||
struct ca0132_spec *spec = codec->spec;
|
||||
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
case QUIRK_AE5:
|
||||
snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
|
||||
|
@ -3344,6 +3356,8 @@ static void ca0132_gpio_init(struct hda_codec *codec)
|
|||
snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
|
||||
snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5B);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3353,7 +3367,7 @@ static void ca0132_gpio_setup(struct hda_codec *codec)
|
|||
{
|
||||
struct ca0132_spec *spec = codec->spec;
|
||||
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DIRECTION, 0x07);
|
||||
|
@ -3372,6 +3386,8 @@ static void ca0132_gpio_setup(struct hda_codec *codec)
|
|||
snd_hda_codec_write(codec, 0x01, 0,
|
||||
AC_VERB_SET_GPIO_DATA, 0x0C);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4172,7 +4188,7 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
|
|||
|
||||
switch (spec->cur_out_type) {
|
||||
case SPEAKER_OUT:
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
ca0113_mmio_gpio_set(codec, 7, false);
|
||||
ca0113_mmio_gpio_set(codec, 4, true);
|
||||
|
@ -4203,10 +4219,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
|
|||
chipio_set_control_param(codec, 0x0d, 0xa4);
|
||||
chipio_write(codec, 0x18b03c, 0x00000012);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HEADPHONE_OUT:
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
ca0113_mmio_gpio_set(codec, 7, true);
|
||||
ca0113_mmio_gpio_set(codec, 4, true);
|
||||
|
@ -4238,10 +4256,12 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
|
|||
chipio_set_control_param(codec, 0x0d, 0xa1);
|
||||
chipio_write(codec, 0x18b03c, 0x00000012);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SURROUND_OUT:
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
ca0113_mmio_gpio_set(codec, 7, false);
|
||||
ca0113_mmio_gpio_set(codec, 4, true);
|
||||
|
@ -4272,6 +4292,8 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
|
|||
chipio_set_control_param(codec, 0x0d, 0xa4);
|
||||
chipio_write(codec, 0x18b03c, 0x00000012);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4446,7 +4468,7 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work)
|
|||
to_delayed_work(work), struct ca0132_spec, unsol_hp_work);
|
||||
struct hda_jack_tbl *jack;
|
||||
|
||||
if (spec->use_alt_functions)
|
||||
if (ca0132_use_alt_functions(spec))
|
||||
ca0132_alt_select_out(spec->codec);
|
||||
else
|
||||
ca0132_select_out(spec->codec);
|
||||
|
@ -4530,14 +4552,14 @@ static int ca0132_alt_set_vipsource(struct hda_codec *codec, int val)
|
|||
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
|
||||
if (spec->quirk == QUIRK_R3DI)
|
||||
if (ca0132_quirk(spec) == QUIRK_R3DI)
|
||||
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
|
||||
|
||||
|
||||
if (spec->in_enum_val == REAR_LINE_IN)
|
||||
tmp = FLOAT_ZERO;
|
||||
else {
|
||||
if (spec->quirk == QUIRK_SBZ)
|
||||
if (ca0132_quirk(spec) == QUIRK_SBZ)
|
||||
tmp = FLOAT_THREE;
|
||||
else
|
||||
tmp = FLOAT_ONE;
|
||||
|
@ -4549,7 +4571,7 @@ static int ca0132_alt_set_vipsource(struct hda_codec *codec, int val)
|
|||
codec_dbg(codec, "%s: on.", __func__);
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000);
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000);
|
||||
if (spec->quirk == QUIRK_R3DI)
|
||||
if (ca0132_quirk(spec) == QUIRK_R3DI)
|
||||
chipio_set_conn_rate(codec, 0x0F, SR_16_000);
|
||||
|
||||
if (spec->effects_switch[VOICE_FOCUS - EFFECT_START_NID])
|
||||
|
@ -4645,7 +4667,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
|
|||
|
||||
switch (spec->cur_mic_type) {
|
||||
case REAR_MIC:
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
case QUIRK_R3D:
|
||||
ca0113_mmio_gpio_set(codec, 0, false);
|
||||
|
@ -4669,14 +4691,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
|
|||
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
|
||||
if (spec->quirk == QUIRK_R3DI)
|
||||
if (ca0132_quirk(spec) == QUIRK_R3DI)
|
||||
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
|
||||
|
||||
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
|
||||
|
||||
chipio_set_stream_control(codec, 0x03, 1);
|
||||
chipio_set_stream_control(codec, 0x04, 1);
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
chipio_write(codec, 0x18B098, 0x0000000C);
|
||||
chipio_write(codec, 0x18B09C, 0x0000000C);
|
||||
|
@ -4689,12 +4711,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
|
|||
chipio_write(codec, 0x18B098, 0x0000000C);
|
||||
chipio_write(codec, 0x18B09C, 0x0000004C);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
|
||||
break;
|
||||
case REAR_LINE_IN:
|
||||
ca0132_mic_boost_set(codec, 0);
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
case QUIRK_R3D:
|
||||
ca0113_mmio_gpio_set(codec, 0, false);
|
||||
|
@ -4705,28 +4729,32 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
|
|||
case QUIRK_AE5:
|
||||
ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
|
||||
if (spec->quirk == QUIRK_R3DI)
|
||||
if (ca0132_quirk(spec) == QUIRK_R3DI)
|
||||
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
|
||||
|
||||
tmp = FLOAT_ZERO;
|
||||
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
|
||||
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
case QUIRK_AE5:
|
||||
chipio_write(codec, 0x18B098, 0x00000000);
|
||||
chipio_write(codec, 0x18B09C, 0x00000000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
chipio_set_stream_control(codec, 0x03, 1);
|
||||
chipio_set_stream_control(codec, 0x04, 1);
|
||||
break;
|
||||
case FRONT_MIC:
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
case QUIRK_R3D:
|
||||
ca0113_mmio_gpio_set(codec, 0, true);
|
||||
|
@ -4748,7 +4776,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
|
|||
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
|
||||
if (spec->quirk == QUIRK_R3DI)
|
||||
if (ca0132_quirk(spec) == QUIRK_R3DI)
|
||||
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
|
||||
|
||||
dspio_set_uint_param(codec, 0x80, 0x00, tmp);
|
||||
|
@ -4756,7 +4784,7 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
|
|||
chipio_set_stream_control(codec, 0x03, 1);
|
||||
chipio_set_stream_control(codec, 0x04, 1);
|
||||
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
chipio_write(codec, 0x18B098, 0x0000000C);
|
||||
chipio_write(codec, 0x18B09C, 0x000000CC);
|
||||
|
@ -4765,6 +4793,8 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
|
|||
chipio_write(codec, 0x18B098, 0x0000000C);
|
||||
chipio_write(codec, 0x18B09C, 0x0000004C);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
|
||||
break;
|
||||
|
@ -4859,7 +4889,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
|
|||
val = 0;
|
||||
|
||||
/* If Voice Focus on SBZ, set to two channel. */
|
||||
if ((nid == VOICE_FOCUS) && (spec->use_pci_mmio)
|
||||
if ((nid == VOICE_FOCUS) && ca0132_use_pci_mmio(spec)
|
||||
&& (spec->cur_mic_type != REAR_LINE_IN)) {
|
||||
if (spec->effects_switch[CRYSTAL_VOICE -
|
||||
EFFECT_START_NID]) {
|
||||
|
@ -4878,7 +4908,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
|
|||
* For SBZ noise reduction, there's an extra command
|
||||
* to module ID 0x47. No clue why.
|
||||
*/
|
||||
if ((nid == NOISE_REDUCTION) && (spec->use_pci_mmio)
|
||||
if ((nid == NOISE_REDUCTION) && ca0132_use_pci_mmio(spec)
|
||||
&& (spec->cur_mic_type != REAR_LINE_IN)) {
|
||||
if (spec->effects_switch[CRYSTAL_VOICE -
|
||||
EFFECT_START_NID]) {
|
||||
|
@ -4894,7 +4924,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
|
|||
}
|
||||
|
||||
/* If rear line in disable effects. */
|
||||
if (spec->use_alt_functions &&
|
||||
if (ca0132_use_alt_functions(spec) &&
|
||||
spec->in_enum_val == REAR_LINE_IN)
|
||||
val = 0;
|
||||
}
|
||||
|
@ -4924,7 +4954,7 @@ static int ca0132_pe_switch_set(struct hda_codec *codec)
|
|||
codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n",
|
||||
spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]);
|
||||
|
||||
if (spec->use_alt_functions)
|
||||
if (ca0132_use_alt_functions(spec))
|
||||
ca0132_alt_select_out(codec);
|
||||
|
||||
i = OUT_EFFECT_START_NID - EFFECT_START_NID;
|
||||
|
@ -4984,7 +5014,7 @@ static int ca0132_cvoice_switch_set(struct hda_codec *codec)
|
|||
|
||||
/* set correct vipsource */
|
||||
oldval = stop_mic1(codec);
|
||||
if (spec->use_alt_functions)
|
||||
if (ca0132_use_alt_functions(spec))
|
||||
ret |= ca0132_alt_set_vipsource(codec, 1);
|
||||
else
|
||||
ret |= ca0132_set_vipsource(codec, 1);
|
||||
|
@ -5053,7 +5083,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
|
|||
auto_jack =
|
||||
spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
|
||||
if (!auto_jack) {
|
||||
if (spec->use_alt_functions)
|
||||
if (ca0132_use_alt_functions(spec))
|
||||
ca0132_alt_select_out(codec);
|
||||
else
|
||||
ca0132_select_out(codec);
|
||||
|
@ -5070,7 +5100,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
|
|||
}
|
||||
|
||||
if (nid == VNID_HP_ASEL) {
|
||||
if (spec->use_alt_functions)
|
||||
if (ca0132_use_alt_functions(spec))
|
||||
ca0132_alt_select_out(codec);
|
||||
else
|
||||
ca0132_select_out(codec);
|
||||
|
@ -5784,7 +5814,7 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
|
|||
/* mic boost */
|
||||
if (nid == spec->input_pins[0]) {
|
||||
spec->cur_mic_boost = *valp;
|
||||
if (spec->use_alt_functions) {
|
||||
if (ca0132_use_alt_functions(spec)) {
|
||||
if (spec->in_enum_val != REAR_LINE_IN)
|
||||
changed = ca0132_mic_boost_set(codec, *valp);
|
||||
} else {
|
||||
|
@ -6080,7 +6110,7 @@ static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
|
|||
/* If using alt_controls, add FX: prefix. But, don't add FX:
|
||||
* prefix to OutFX or InFX enable controls.
|
||||
*/
|
||||
if ((spec->use_alt_controls) && (nid <= IN_EFFECT_END_NID))
|
||||
if (ca0132_use_alt_controls(spec) && (nid <= IN_EFFECT_END_NID))
|
||||
sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]);
|
||||
else
|
||||
sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
|
||||
|
@ -6357,7 +6387,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
|
|||
return err;
|
||||
}
|
||||
/* Setup vmaster with surround slaves for desktop ca0132 devices */
|
||||
if (spec->use_alt_functions) {
|
||||
if (ca0132_use_alt_functions(spec)) {
|
||||
snd_hda_set_vmaster_tlv(codec, spec->dacs[0], HDA_OUTPUT,
|
||||
spec->tlv);
|
||||
snd_hda_add_vmaster(codec, "Master Playback Volume",
|
||||
|
@ -6377,7 +6407,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
|
|||
num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
|
||||
for (i = 0; i < num_fx; i++) {
|
||||
/* Desktop cards break if Echo Cancellation is used. */
|
||||
if (spec->use_pci_mmio) {
|
||||
if (ca0132_use_pci_mmio(spec)) {
|
||||
if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
|
||||
OUT_EFFECTS_COUNT))
|
||||
continue;
|
||||
|
@ -6394,7 +6424,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
|
|||
* EQ presets, and Smart Volume presets. Also, change names to add FX
|
||||
* prefix, and change PlayEnhancement and CrystalVoice to match.
|
||||
*/
|
||||
if (spec->use_alt_controls) {
|
||||
if (ca0132_use_alt_controls(spec)) {
|
||||
err = ca0132_alt_add_svm_enum(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -6448,7 +6478,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
|
|||
* to select the new outputs and inputs, plus add the new mic boost
|
||||
* setting control.
|
||||
*/
|
||||
if (spec->use_alt_functions) {
|
||||
if (ca0132_use_alt_functions(spec)) {
|
||||
err = ca0132_alt_add_output_enum(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -6459,14 +6489,14 @@ static int ca0132_build_controls(struct hda_codec *codec)
|
|||
* ZxR only has microphone input, there is no front panel
|
||||
* header on the card, and aux-in is handled by the DBPro board.
|
||||
*/
|
||||
if (spec->quirk != QUIRK_ZXR) {
|
||||
if (ca0132_quirk(spec) != QUIRK_ZXR) {
|
||||
err = ca0132_alt_add_input_enum(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (spec->quirk == QUIRK_AE5) {
|
||||
if (ca0132_quirk(spec) == QUIRK_AE5) {
|
||||
err = ae5_add_headphone_gain_enum(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -6475,7 +6505,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (spec->quirk == QUIRK_ZXR) {
|
||||
if (ca0132_quirk(spec) == QUIRK_ZXR) {
|
||||
err = zxr_add_headphone_gain_switch(codec);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -6505,7 +6535,7 @@ static int ca0132_build_controls(struct hda_codec *codec)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (spec->use_alt_functions)
|
||||
if (ca0132_use_alt_functions(spec))
|
||||
ca0132_alt_add_chmap_ctls(codec);
|
||||
|
||||
return 0;
|
||||
|
@ -6583,7 +6613,7 @@ static int ca0132_build_pcms(struct hda_codec *codec)
|
|||
info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
if (spec->use_alt_functions) {
|
||||
if (ca0132_use_alt_functions(spec)) {
|
||||
info->own_chmap = true;
|
||||
info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap
|
||||
= ca0132_alt_chmaps;
|
||||
|
@ -6597,7 +6627,7 @@ static int ca0132_build_pcms(struct hda_codec *codec)
|
|||
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
|
||||
|
||||
/* With the DSP enabled, desktops don't use this ADC. */
|
||||
if (!spec->use_alt_functions) {
|
||||
if (!ca0132_use_alt_functions(spec)) {
|
||||
info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
@ -6795,7 +6825,7 @@ static void ca0132_init_dmic(struct hda_codec *codec)
|
|||
* Bit 6: set to select Data2, clear for Data1
|
||||
* Bit 7: set to enable DMic, clear for AMic
|
||||
*/
|
||||
if (spec->quirk == QUIRK_ALIENWARE_M17XR4)
|
||||
if (ca0132_quirk(spec) == QUIRK_ALIENWARE_M17XR4)
|
||||
val = 0x33;
|
||||
else
|
||||
val = 0x23;
|
||||
|
@ -6877,7 +6907,7 @@ static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
|
|||
/* Mic 1 Setup */
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
|
||||
if (spec->quirk == QUIRK_R3DI) {
|
||||
if (ca0132_quirk(spec) == QUIRK_R3DI) {
|
||||
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
|
||||
tmp = FLOAT_ONE;
|
||||
} else
|
||||
|
@ -6887,7 +6917,7 @@ static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
|
|||
/* Mic 2 setup (not present on desktop cards) */
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
|
||||
if (spec->quirk == QUIRK_R3DI)
|
||||
if (ca0132_quirk(spec) == QUIRK_R3DI)
|
||||
chipio_set_conn_rate(codec, 0x0F, SR_96_000);
|
||||
tmp = FLOAT_ZERO;
|
||||
dspio_set_uint_param(codec, 0x80, 0x01, tmp);
|
||||
|
@ -6949,7 +6979,7 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
|
|||
chipio_set_stream_channels(codec, 0x0C, 6);
|
||||
chipio_set_stream_control(codec, 0x0C, 1);
|
||||
/* No clue what these control */
|
||||
if (spec->quirk == QUIRK_SBZ) {
|
||||
if (ca0132_quirk(spec) == QUIRK_SBZ) {
|
||||
chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0);
|
||||
chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1);
|
||||
chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2);
|
||||
|
@ -6962,7 +6992,7 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
|
|||
chipio_write_no_mutex(codec, 0x190054, 0x0001edc9);
|
||||
chipio_write_no_mutex(codec, 0x190058, 0x0001eaca);
|
||||
chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb);
|
||||
} else if (spec->quirk == QUIRK_ZXR) {
|
||||
} else if (ca0132_quirk(spec) == QUIRK_ZXR) {
|
||||
chipio_write_no_mutex(codec, 0x190038, 0x000140c2);
|
||||
chipio_write_no_mutex(codec, 0x19003c, 0x000141c3);
|
||||
chipio_write_no_mutex(codec, 0x190040, 0x000150c4);
|
||||
|
@ -6992,7 +7022,7 @@ static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec)
|
|||
* why this is, but multiple tests have confirmed it.
|
||||
*/
|
||||
for (i = 0; i < 2; i++) {
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
case QUIRK_AE5:
|
||||
tmp = 0x00000003;
|
||||
|
@ -7021,6 +7051,8 @@ static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec)
|
|||
tmp = 0x00000000;
|
||||
dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
msleep(100);
|
||||
}
|
||||
|
@ -7043,7 +7075,7 @@ static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
|
|||
chipio_set_stream_control(codec, 0x03, 1);
|
||||
chipio_set_stream_control(codec, 0x04, 1);
|
||||
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
chipio_write(codec, 0x18b098, 0x0000000c);
|
||||
chipio_write(codec, 0x18b09C, 0x0000000c);
|
||||
|
@ -7052,6 +7084,8 @@ static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
|
|||
chipio_write(codec, 0x18b098, 0x0000000c);
|
||||
chipio_write(codec, 0x18b09c, 0x0000004c);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7273,7 +7307,7 @@ static void r3d_setup_defaults(struct hda_codec *codec)
|
|||
/* Set speaker source? */
|
||||
dspio_set_uint_param(codec, 0x32, 0x00, tmp);
|
||||
|
||||
if (spec->quirk == QUIRK_R3DI)
|
||||
if (ca0132_quirk(spec) == QUIRK_R3DI)
|
||||
r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED);
|
||||
|
||||
/* Setup effect defaults */
|
||||
|
@ -7420,7 +7454,7 @@ static void ca0132_init_flags(struct hda_codec *codec)
|
|||
{
|
||||
struct ca0132_spec *spec = codec->spec;
|
||||
|
||||
if (spec->use_alt_functions) {
|
||||
if (ca0132_use_alt_functions(spec)) {
|
||||
chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, 1);
|
||||
chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, 1);
|
||||
chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, 1);
|
||||
|
@ -7453,7 +7487,7 @@ static void ca0132_init_params(struct hda_codec *codec)
|
|||
{
|
||||
struct ca0132_spec *spec = codec->spec;
|
||||
|
||||
if (spec->use_alt_functions) {
|
||||
if (ca0132_use_alt_functions(spec)) {
|
||||
chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
|
||||
chipio_set_conn_rate(codec, 0x0B, SR_48_000);
|
||||
chipio_set_control_param(codec, CONTROL_PARAM_SPDIF1_SOURCE, 0);
|
||||
|
@ -7490,7 +7524,7 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
|
|||
* can use the default firmware, but I'll leave the option in case
|
||||
* it needs it again.
|
||||
*/
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
case QUIRK_R3D:
|
||||
case QUIRK_AE5:
|
||||
|
@ -7564,7 +7598,7 @@ static void ca0132_download_dsp(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
/* For codecs using alt functions, this is already done earlier */
|
||||
if (spec->dsp_state == DSP_DOWNLOADED && (!spec->use_alt_functions))
|
||||
if (spec->dsp_state == DSP_DOWNLOADED && !ca0132_use_alt_functions(spec))
|
||||
ca0132_set_dsp_msr(codec, true);
|
||||
}
|
||||
|
||||
|
@ -7601,7 +7635,7 @@ static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
|
|||
{
|
||||
struct ca0132_spec *spec = codec->spec;
|
||||
|
||||
if (spec->use_alt_functions)
|
||||
if (ca0132_use_alt_functions(spec))
|
||||
ca0132_alt_select_in(codec);
|
||||
else
|
||||
ca0132_select_mic(codec);
|
||||
|
@ -7616,7 +7650,7 @@ static void ca0132_init_unsol(struct hda_codec *codec)
|
|||
snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
|
||||
ca0132_process_dsp_response);
|
||||
/* Front headphone jack detection */
|
||||
if (spec->use_alt_functions)
|
||||
if (ca0132_use_alt_functions(spec))
|
||||
snd_hda_jack_detect_enable_callback(codec,
|
||||
spec->unsol_tag_front_hp, hp_callback);
|
||||
}
|
||||
|
@ -7706,7 +7740,7 @@ static void ca0132_init_chip(struct hda_codec *codec)
|
|||
mutex_init(&spec->chipio_mutex);
|
||||
|
||||
spec->cur_out_type = SPEAKER_OUT;
|
||||
if (!spec->use_alt_functions)
|
||||
if (!ca0132_use_alt_functions(spec))
|
||||
spec->cur_mic_type = DIGITAL_MIC;
|
||||
else
|
||||
spec->cur_mic_type = REAR_MIC;
|
||||
|
@ -7732,7 +7766,7 @@ static void ca0132_init_chip(struct hda_codec *codec)
|
|||
* Sets defaults for the effect slider controls, only for alternative
|
||||
* ca0132 codecs. Also sets x-bass crossover frequency to 80hz.
|
||||
*/
|
||||
if (spec->use_alt_controls) {
|
||||
if (ca0132_use_alt_controls(spec)) {
|
||||
spec->xbass_xover_freq = 8;
|
||||
for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++)
|
||||
spec->fx_ctl_val[i] = effect_slider_defaults[i];
|
||||
|
@ -7747,7 +7781,7 @@ static void ca0132_init_chip(struct hda_codec *codec)
|
|||
* the daughter board. So, there is no input enum control, and we need
|
||||
* to make sure that spec->in_enum_val is set properly.
|
||||
*/
|
||||
if (spec->quirk == QUIRK_ZXR)
|
||||
if (ca0132_quirk(spec) == QUIRK_ZXR)
|
||||
spec->in_enum_val = REAR_MIC;
|
||||
|
||||
#ifdef ENABLE_TUNING_CONTROLS
|
||||
|
@ -8088,27 +8122,27 @@ static void ca0132_mmio_init(struct hda_codec *codec)
|
|||
{
|
||||
struct ca0132_spec *spec = codec->spec;
|
||||
|
||||
if (spec->quirk == QUIRK_AE5)
|
||||
if (ca0132_quirk(spec) == QUIRK_AE5)
|
||||
writel(0x00000001, spec->mem_base + 0x400);
|
||||
else
|
||||
writel(0x00000000, spec->mem_base + 0x400);
|
||||
|
||||
if (spec->quirk == QUIRK_AE5)
|
||||
if (ca0132_quirk(spec) == QUIRK_AE5)
|
||||
writel(0x00000001, spec->mem_base + 0x408);
|
||||
else
|
||||
writel(0x00000000, spec->mem_base + 0x408);
|
||||
|
||||
if (spec->quirk == QUIRK_AE5)
|
||||
if (ca0132_quirk(spec) == QUIRK_AE5)
|
||||
writel(0x00000001, spec->mem_base + 0x40c);
|
||||
else
|
||||
writel(0x00000000, spec->mem_base + 0x40C);
|
||||
|
||||
if (spec->quirk == QUIRK_ZXR)
|
||||
if (ca0132_quirk(spec) == QUIRK_ZXR)
|
||||
writel(0x00880640, spec->mem_base + 0x01C);
|
||||
else
|
||||
writel(0x00880680, spec->mem_base + 0x01C);
|
||||
|
||||
if (spec->quirk == QUIRK_AE5)
|
||||
if (ca0132_quirk(spec) == QUIRK_AE5)
|
||||
writel(0x00000080, spec->mem_base + 0xC0C);
|
||||
else
|
||||
writel(0x00000083, spec->mem_base + 0xC0C);
|
||||
|
@ -8116,7 +8150,7 @@ static void ca0132_mmio_init(struct hda_codec *codec)
|
|||
writel(0x00000030, spec->mem_base + 0xC00);
|
||||
writel(0x00000000, spec->mem_base + 0xC04);
|
||||
|
||||
if (spec->quirk == QUIRK_AE5)
|
||||
if (ca0132_quirk(spec) == QUIRK_AE5)
|
||||
writel(0x00000000, spec->mem_base + 0xC0C);
|
||||
else
|
||||
writel(0x00000003, spec->mem_base + 0xC0C);
|
||||
|
@ -8125,7 +8159,7 @@ static void ca0132_mmio_init(struct hda_codec *codec)
|
|||
writel(0x00000003, spec->mem_base + 0xC0C);
|
||||
writel(0x00000003, spec->mem_base + 0xC0C);
|
||||
|
||||
if (spec->quirk == QUIRK_AE5)
|
||||
if (ca0132_quirk(spec) == QUIRK_AE5)
|
||||
writel(0x00000001, spec->mem_base + 0xC08);
|
||||
else
|
||||
writel(0x000000C1, spec->mem_base + 0xC08);
|
||||
|
@ -8136,7 +8170,7 @@ static void ca0132_mmio_init(struct hda_codec *codec)
|
|||
writel(0x000000C1, spec->mem_base + 0xC08);
|
||||
writel(0x00000080, spec->mem_base + 0xC04);
|
||||
|
||||
if (spec->quirk == QUIRK_AE5) {
|
||||
if (ca0132_quirk(spec) == QUIRK_AE5) {
|
||||
writel(0x00000000, spec->mem_base + 0x42c);
|
||||
writel(0x00000000, spec->mem_base + 0x46c);
|
||||
writel(0x00000000, spec->mem_base + 0x4ac);
|
||||
|
@ -8211,7 +8245,7 @@ static void ca0132_alt_init(struct hda_codec *codec)
|
|||
|
||||
ca0132_alt_vol_setup(codec);
|
||||
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
codec_dbg(codec, "SBZ alt_init");
|
||||
ca0132_gpio_init(codec);
|
||||
|
@ -8248,6 +8282,8 @@ static void ca0132_alt_init(struct hda_codec *codec)
|
|||
snd_hda_sequence_write(codec, spec->chip_init_verbs);
|
||||
snd_hda_sequence_write(codec, spec->desktop_init_verbs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8274,7 +8310,7 @@ static int ca0132_init(struct hda_codec *codec)
|
|||
spec->dsp_reload = true;
|
||||
spec->dsp_state = DSP_DOWNLOAD_INIT;
|
||||
} else {
|
||||
if (spec->quirk == QUIRK_SBZ)
|
||||
if (ca0132_quirk(spec) == QUIRK_SBZ)
|
||||
sbz_dsp_startup_check(codec);
|
||||
return 0;
|
||||
}
|
||||
|
@ -8284,12 +8320,12 @@ static int ca0132_init(struct hda_codec *codec)
|
|||
spec->dsp_state = DSP_DOWNLOAD_INIT;
|
||||
spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
|
||||
|
||||
if (spec->use_pci_mmio)
|
||||
if (ca0132_use_pci_mmio(spec))
|
||||
ca0132_mmio_init(codec);
|
||||
|
||||
snd_hda_power_up_pm(codec);
|
||||
|
||||
if (spec->quirk == QUIRK_AE5)
|
||||
if (ca0132_quirk(spec) == QUIRK_AE5)
|
||||
ae5_register_set(codec);
|
||||
|
||||
ca0132_init_unsol(codec);
|
||||
|
@ -8298,14 +8334,14 @@ static int ca0132_init(struct hda_codec *codec)
|
|||
|
||||
snd_hda_sequence_write(codec, spec->base_init_verbs);
|
||||
|
||||
if (spec->use_alt_functions)
|
||||
if (ca0132_use_alt_functions(spec))
|
||||
ca0132_alt_init(codec);
|
||||
|
||||
ca0132_download_dsp(codec);
|
||||
|
||||
ca0132_refresh_widget_caps(codec);
|
||||
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_R3DI:
|
||||
case QUIRK_R3D:
|
||||
r3d_setup_defaults(codec);
|
||||
|
@ -8334,7 +8370,7 @@ static int ca0132_init(struct hda_codec *codec)
|
|||
|
||||
init_input(codec, cfg->dig_in_pin, spec->dig_in);
|
||||
|
||||
if (!spec->use_alt_functions) {
|
||||
if (!ca0132_use_alt_functions(spec)) {
|
||||
snd_hda_sequence_write(codec, spec->chip_init_verbs);
|
||||
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
|
||||
VENDOR_CHIPIO_PARAM_EX_ID_SET, 0x0D);
|
||||
|
@ -8342,11 +8378,11 @@ static int ca0132_init(struct hda_codec *codec)
|
|||
VENDOR_CHIPIO_PARAM_EX_VALUE_SET, 0x20);
|
||||
}
|
||||
|
||||
if (spec->quirk == QUIRK_SBZ)
|
||||
if (ca0132_quirk(spec) == QUIRK_SBZ)
|
||||
ca0132_gpio_setup(codec);
|
||||
|
||||
snd_hda_sequence_write(codec, spec->spec_init_verbs);
|
||||
if (spec->use_alt_functions) {
|
||||
if (ca0132_use_alt_functions(spec)) {
|
||||
ca0132_alt_select_out(codec);
|
||||
ca0132_alt_select_in(codec);
|
||||
} else {
|
||||
|
@ -8391,7 +8427,7 @@ static void ca0132_free(struct hda_codec *codec)
|
|||
|
||||
cancel_delayed_work_sync(&spec->unsol_hp_work);
|
||||
snd_hda_power_up(codec);
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
sbz_exit_chip(codec);
|
||||
break;
|
||||
|
@ -8407,13 +8443,15 @@ static void ca0132_free(struct hda_codec *codec)
|
|||
case QUIRK_R3DI:
|
||||
r3di_gpio_shutdown(codec);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
snd_hda_sequence_write(codec, spec->base_exit_verbs);
|
||||
ca0132_exit_chip(codec);
|
||||
|
||||
snd_hda_power_down(codec);
|
||||
if (spec->mem_base)
|
||||
if (IS_ENABLED(CONFIG_PCI) && spec->mem_base)
|
||||
pci_iounmap(codec->bus->pci, spec->mem_base);
|
||||
kfree(spec->spec_init_verbs);
|
||||
kfree(codec->spec);
|
||||
|
@ -8461,12 +8499,12 @@ static void ca0132_config(struct hda_codec *codec)
|
|||
spec->multiout.dac_nids = spec->dacs;
|
||||
spec->multiout.num_dacs = 3;
|
||||
|
||||
if (!spec->use_alt_functions)
|
||||
if (!ca0132_use_alt_functions(spec))
|
||||
spec->multiout.max_channels = 2;
|
||||
else
|
||||
spec->multiout.max_channels = 6;
|
||||
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_ALIENWARE:
|
||||
codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__);
|
||||
snd_hda_apply_pincfgs(codec, alienware_pincfgs);
|
||||
|
@ -8491,9 +8529,11 @@ static void ca0132_config(struct hda_codec *codec)
|
|||
codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__);
|
||||
snd_hda_apply_pincfgs(codec, ae5_pincfgs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_ALIENWARE:
|
||||
spec->num_outputs = 2;
|
||||
spec->out_pins[0] = 0x0b; /* speaker out */
|
||||
|
@ -8654,7 +8694,7 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
|
|||
* Since desktop cards use pci_mmio, this can be used to determine
|
||||
* whether or not to use these verbs instead of a separate bool.
|
||||
*/
|
||||
if (spec->use_pci_mmio)
|
||||
if (ca0132_use_pci_mmio(spec))
|
||||
spec->desktop_init_verbs = ca0132_init_verbs1;
|
||||
spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
|
||||
sizeof(struct hda_verb),
|
||||
|
@ -8729,11 +8769,10 @@ static int patch_ca0132(struct hda_codec *codec)
|
|||
spec->quirk = quirk->value;
|
||||
else
|
||||
spec->quirk = QUIRK_NONE;
|
||||
|
||||
if (spec->quirk == QUIRK_SBZ)
|
||||
if (ca0132_quirk(spec) == QUIRK_SBZ)
|
||||
sbz_detect_quirk(codec);
|
||||
|
||||
if (spec->quirk == QUIRK_ZXR_DBPRO)
|
||||
if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
|
||||
codec->patch_ops = dbpro_patch_ops;
|
||||
else
|
||||
codec->patch_ops = ca0132_patch_ops;
|
||||
|
@ -8746,7 +8785,7 @@ static int patch_ca0132(struct hda_codec *codec)
|
|||
spec->num_mixers = 1;
|
||||
|
||||
/* Set which mixers each quirk uses. */
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
spec->mixers[0] = desktop_mixer;
|
||||
snd_hda_codec_set_name(codec, "Sound Blaster Z");
|
||||
|
@ -8775,7 +8814,7 @@ static int patch_ca0132(struct hda_codec *codec)
|
|||
}
|
||||
|
||||
/* Setup whether or not to use alt functions/controls/pci_mmio */
|
||||
switch (spec->quirk) {
|
||||
switch (ca0132_quirk(spec)) {
|
||||
case QUIRK_SBZ:
|
||||
case QUIRK_R3D:
|
||||
case QUIRK_AE5:
|
||||
|
@ -8796,6 +8835,7 @@ static int patch_ca0132(struct hda_codec *codec)
|
|||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
if (spec->use_pci_mmio) {
|
||||
spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
|
||||
if (spec->mem_base == NULL) {
|
||||
|
@ -8803,6 +8843,7 @@ static int patch_ca0132(struct hda_codec *codec)
|
|||
spec->quirk = QUIRK_NONE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
spec->base_init_verbs = ca0132_base_init_verbs;
|
||||
spec->base_exit_verbs = ca0132_base_exit_verbs;
|
||||
|
|
|
@ -923,6 +923,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
|
||||
SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
|
||||
SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
|
||||
SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
|
||||
SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
|
||||
SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
|
||||
SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
|
||||
|
|
|
@ -2142,7 +2142,7 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
|
|||
strncat(hdmi_str, " Phantom",
|
||||
sizeof(hdmi_str) - strlen(hdmi_str) - 1);
|
||||
ret = snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str,
|
||||
phantom_jack);
|
||||
phantom_jack, 0, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
jack = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
|
||||
|
@ -2616,11 +2616,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid)
|
|||
intel_haswell_enable_all_pins(codec, true);
|
||||
intel_haswell_fixup_enable_dp12(codec);
|
||||
|
||||
/* For Haswell/Broadwell, the controller is also in the power well and
|
||||
* can cover the codec power request, and so need not set this flag.
|
||||
*/
|
||||
if (!is_haswell(codec) && !is_broadwell(codec))
|
||||
codec->core.link_power_control = 1;
|
||||
codec->display_power_control = 1;
|
||||
|
||||
codec->patch_ops.set_power_state = haswell_set_power_state;
|
||||
codec->depop_delay = 0;
|
||||
|
@ -2656,7 +2652,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec)
|
|||
/* For Valleyview/Cherryview, only the display codec is in the display
|
||||
* power well and can use link_power ops to request/release the power.
|
||||
*/
|
||||
codec->core.link_power_control = 1;
|
||||
codec->display_power_control = 1;
|
||||
|
||||
codec->depop_delay = 0;
|
||||
codec->auto_runtime_pm = 1;
|
||||
|
@ -3834,6 +3830,10 @@ HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI", patch_tegra_hdmi),
|
|||
HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI", patch_tegra_hdmi),
|
||||
HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI", patch_tegra_hdmi),
|
||||
HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP", patch_tegra_hdmi),
|
||||
HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
|
||||
HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
|
||||
HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
|
||||
HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
|
||||
HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi),
|
||||
HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi),
|
||||
HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi),
|
||||
|
|
|
@ -5380,6 +5380,66 @@ static void alc285_fixup_invalidate_dacs(struct hda_codec *codec,
|
|||
snd_hda_override_wcaps(codec, 0x03, 0);
|
||||
}
|
||||
|
||||
static const struct hda_jack_keymap alc_headset_btn_keymap[] = {
|
||||
{ SND_JACK_BTN_0, KEY_PLAYPAUSE },
|
||||
{ SND_JACK_BTN_1, KEY_VOICECOMMAND },
|
||||
{ SND_JACK_BTN_2, KEY_VOLUMEUP },
|
||||
{ SND_JACK_BTN_3, KEY_VOLUMEDOWN },
|
||||
{}
|
||||
};
|
||||
|
||||
static void alc_headset_btn_callback(struct hda_codec *codec,
|
||||
struct hda_jack_callback *jack)
|
||||
{
|
||||
int report = 0;
|
||||
|
||||
if (jack->unsol_res & (7 << 13))
|
||||
report |= SND_JACK_BTN_0;
|
||||
|
||||
if (jack->unsol_res & (1 << 16 | 3 << 8))
|
||||
report |= SND_JACK_BTN_1;
|
||||
|
||||
/* Volume up key */
|
||||
if (jack->unsol_res & (7 << 23))
|
||||
report |= SND_JACK_BTN_2;
|
||||
|
||||
/* Volume down key */
|
||||
if (jack->unsol_res & (7 << 10))
|
||||
report |= SND_JACK_BTN_3;
|
||||
|
||||
jack->jack->button_state = report;
|
||||
}
|
||||
|
||||
static void alc_fixup_headset_jack(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
|
||||
switch (action) {
|
||||
case HDA_FIXUP_ACT_PRE_PROBE:
|
||||
snd_hda_jack_detect_enable_callback(codec, 0x55,
|
||||
alc_headset_btn_callback);
|
||||
snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", false,
|
||||
SND_JACK_HEADSET, alc_headset_btn_keymap);
|
||||
break;
|
||||
case HDA_FIXUP_ACT_INIT:
|
||||
switch (codec->core.vendor_id) {
|
||||
case 0x10ec0225:
|
||||
case 0x10ec0295:
|
||||
case 0x10ec0299:
|
||||
alc_write_coef_idx(codec, 0x48, 0xd011);
|
||||
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
|
||||
alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8);
|
||||
break;
|
||||
case 0x10ec0236:
|
||||
case 0x10ec0256:
|
||||
alc_write_coef_idx(codec, 0x48, 0xd011);
|
||||
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* for hda_fixup_thinkpad_acpi() */
|
||||
#include "thinkpad_helper.c"
|
||||
|
||||
|
@ -5390,9 +5450,6 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
|
|||
hda_fixup_thinkpad_acpi(codec, fix, action);
|
||||
}
|
||||
|
||||
/* for dell wmi mic mute led */
|
||||
#include "dell_wmi_helper.c"
|
||||
|
||||
/* for alc295_fixup_hp_top_speakers */
|
||||
#include "hp_x360_helper.c"
|
||||
|
||||
|
@ -5470,7 +5527,7 @@ enum {
|
|||
ALC292_FIXUP_TPT440_DOCK,
|
||||
ALC292_FIXUP_TPT440,
|
||||
ALC283_FIXUP_HEADSET_MIC,
|
||||
ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
|
||||
ALC255_FIXUP_MIC_MUTE_LED,
|
||||
ALC282_FIXUP_ASPIRE_V5_PINS,
|
||||
ALC280_FIXUP_HP_GPIO4,
|
||||
ALC286_FIXUP_HP_GPIO_LED,
|
||||
|
@ -5515,6 +5572,7 @@ enum {
|
|||
ALC298_FIXUP_TPT470_DOCK,
|
||||
ALC255_FIXUP_DUMMY_LINEOUT_VERB,
|
||||
ALC255_FIXUP_DELL_HEADSET_MIC,
|
||||
ALC256_FIXUP_HUAWEI_MBXP_PINS,
|
||||
ALC295_FIXUP_HP_X360,
|
||||
ALC221_FIXUP_HP_HEADSET_MIC,
|
||||
ALC285_FIXUP_LENOVO_HEADPHONE_NOISE,
|
||||
|
@ -5523,6 +5581,7 @@ enum {
|
|||
ALC294_FIXUP_ASUS_MIC,
|
||||
ALC294_FIXUP_ASUS_HEADSET_MIC,
|
||||
ALC294_FIXUP_ASUS_SPK,
|
||||
ALC225_FIXUP_HEADSET_JACK,
|
||||
};
|
||||
|
||||
static const struct hda_fixup alc269_fixups[] = {
|
||||
|
@ -5770,7 +5829,7 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_headset_mode,
|
||||
.chained = true,
|
||||
.chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
|
||||
.chain_id = ALC255_FIXUP_MIC_MUTE_LED
|
||||
},
|
||||
[ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
|
@ -5794,6 +5853,24 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.chained = true,
|
||||
.chain_id = ALC269_FIXUP_HEADSET_MIC
|
||||
},
|
||||
[ALC256_FIXUP_HUAWEI_MBXP_PINS] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = (const struct hda_pintbl[]) {
|
||||
{0x12, 0x90a60130},
|
||||
{0x13, 0x40000000},
|
||||
{0x14, 0x90170110},
|
||||
{0x18, 0x411111f0},
|
||||
{0x19, 0x04a11040},
|
||||
{0x1a, 0x411111f0},
|
||||
{0x1b, 0x90170112},
|
||||
{0x1d, 0x40759a05},
|
||||
{0x1e, 0x411111f0},
|
||||
{0x21, 0x04211020},
|
||||
{ }
|
||||
},
|
||||
.chained = true,
|
||||
.chain_id = ALC255_FIXUP_MIC_MUTE_LED
|
||||
},
|
||||
[ALC269_FIXUP_ASUS_X101_FUNC] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc269_fixup_x101_headset_mic,
|
||||
|
@ -5996,7 +6073,7 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_headset_mode_alc255,
|
||||
.chained = true,
|
||||
.chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
|
||||
.chain_id = ALC255_FIXUP_MIC_MUTE_LED
|
||||
},
|
||||
[ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
|
@ -6031,9 +6108,9 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
{ },
|
||||
},
|
||||
},
|
||||
[ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED] = {
|
||||
[ALC255_FIXUP_MIC_MUTE_LED] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_dell_wmi,
|
||||
.v.func = snd_hda_gen_fixup_micmute_led,
|
||||
},
|
||||
[ALC282_FIXUP_ASPIRE_V5_PINS] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
|
@ -6092,7 +6169,7 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_headset_mode_dell_alc288,
|
||||
.chained = true,
|
||||
.chain_id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED
|
||||
.chain_id = ALC255_FIXUP_MIC_MUTE_LED
|
||||
},
|
||||
[ALC288_FIXUP_DELL1_MIC_NO_PRESENCE] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
|
@ -6441,6 +6518,10 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.chained = true,
|
||||
.chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
|
||||
},
|
||||
[ALC225_FIXUP_HEADSET_JACK] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc_fixup_headset_jack,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||||
|
@ -6573,6 +6654,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
|
||||
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK),
|
||||
SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
|
@ -6680,6 +6762,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
|
||||
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
|
||||
SND_PCI_QUIRK(0x19e5, 0x3200, "Huawei MBX", ALC255_FIXUP_MIC_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x19e5, 0x3201, "Huawei MBX", ALC255_FIXUP_MIC_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MBXP", ALC256_FIXUP_HUAWEI_MBXP_PINS),
|
||||
SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
|
||||
|
||||
#if 0
|
||||
|
@ -6805,7 +6890,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
|
|||
{.id = ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "alc255-dell2"},
|
||||
{.id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc293-dell1"},
|
||||
{.id = ALC283_FIXUP_HEADSET_MIC, .name = "alc283-headset"},
|
||||
{.id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, .name = "alc255-dell-mute"},
|
||||
{.id = ALC255_FIXUP_MIC_MUTE_LED, .name = "alc255-dell-mute"},
|
||||
{.id = ALC282_FIXUP_ASPIRE_V5_PINS, .name = "aspire-v5"},
|
||||
{.id = ALC280_FIXUP_HP_GPIO4, .name = "hp-gpio4"},
|
||||
{.id = ALC286_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
|
||||
|
@ -6844,6 +6929,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
|
|||
{.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
|
||||
{.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
|
||||
{.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
|
||||
{.id = ALC225_FIXUP_HEADSET_JACK, .name = "alc-sense-combo"},
|
||||
{}
|
||||
};
|
||||
#define ALC225_STANDARD_PINS \
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
* to be included from codec driver
|
||||
*/
|
||||
|
||||
#if IS_ENABLED(CONFIG_THINKPAD_ACPI)
|
||||
#if IS_ENABLED(CONFIG_THINKPAD_ACPI) && IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/thinkpad_acpi.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
static int (*led_set_func)(int, bool);
|
||||
static void (*old_vmaster_hook)(void *, int);
|
||||
|
||||
static bool is_thinkpad(struct hda_codec *codec)
|
||||
|
@ -23,50 +22,20 @@ static void update_tpacpi_mute_led(void *private_data, int enabled)
|
|||
if (old_vmaster_hook)
|
||||
old_vmaster_hook(private_data, enabled);
|
||||
|
||||
if (led_set_func)
|
||||
led_set_func(TPACPI_LED_MUTE, !enabled);
|
||||
}
|
||||
|
||||
static void update_tpacpi_micmute(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
|
||||
led_set_func(TPACPI_LED_MICMUTE, spec->micmute_led.led_value);
|
||||
ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON);
|
||||
}
|
||||
|
||||
static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
bool removefunc = false;
|
||||
|
||||
if (action == HDA_FIXUP_ACT_PROBE) {
|
||||
if (!is_thinkpad(codec))
|
||||
return;
|
||||
if (!led_set_func)
|
||||
led_set_func = symbol_request(tpacpi_led_set);
|
||||
if (!led_set_func) {
|
||||
codec_warn(codec,
|
||||
"Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
removefunc = true;
|
||||
if (led_set_func(TPACPI_LED_MUTE, false) >= 0) {
|
||||
old_vmaster_hook = spec->vmaster_mute.hook;
|
||||
spec->vmaster_mute.hook = update_tpacpi_mute_led;
|
||||
removefunc = false;
|
||||
}
|
||||
if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0 &&
|
||||
!snd_hda_gen_add_micmute_led(codec,
|
||||
update_tpacpi_micmute))
|
||||
removefunc = false;
|
||||
}
|
||||
|
||||
if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
|
||||
symbol_put(tpacpi_led_set);
|
||||
led_set_func = NULL;
|
||||
old_vmaster_hook = NULL;
|
||||
old_vmaster_hook = spec->vmaster_mute.hook;
|
||||
spec->vmaster_mute.hook = update_tpacpi_mute_led;
|
||||
snd_hda_gen_fixup_micmute_led(codec, fix, action);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/math64.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/nospec.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
|
@ -4092,15 +4093,16 @@ static int snd_hdsp_channel_info(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_channel_info *info)
|
||||
{
|
||||
struct hdsp *hdsp = snd_pcm_substream_chip(substream);
|
||||
int mapped_channel;
|
||||
unsigned int channel = info->channel;
|
||||
|
||||
if (snd_BUG_ON(info->channel >= hdsp->max_channels))
|
||||
if (snd_BUG_ON(channel >= hdsp->max_channels))
|
||||
return -EINVAL;
|
||||
channel = array_index_nospec(channel, hdsp->max_channels);
|
||||
|
||||
if (hdsp->channel_map[channel] < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((mapped_channel = hdsp->channel_map[info->channel]) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
info->offset = mapped_channel * HDSP_CHANNEL_BUFFER_BYTES;
|
||||
info->offset = hdsp->channel_map[channel] * HDSP_CHANNEL_BUFFER_BYTES;
|
||||
info->first = 0;
|
||||
info->step = 32;
|
||||
return 0;
|
||||
|
|
|
@ -908,7 +908,7 @@ static void detect_byte_swap(struct snd_pmac *chip)
|
|||
|
||||
/* if seems that Keylargo can't byte-swap */
|
||||
for (mio = chip->node->parent; mio; mio = mio->parent) {
|
||||
if (strcmp(mio->name, "mac-io") == 0) {
|
||||
if (of_node_name_eq(mio, "mac-io")) {
|
||||
if (of_device_is_compatible(mio, "Keylargo"))
|
||||
chip->can_byte_swap = 0;
|
||||
break;
|
||||
|
@ -1313,7 +1313,7 @@ int snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
|
|||
} else if (chip->is_pbook_G3) {
|
||||
struct device_node* mio;
|
||||
for (mio = chip->node->parent; mio; mio = mio->parent) {
|
||||
if (strcmp(mio->name, "mac-io") == 0) {
|
||||
if (of_node_name_eq(mio, "mac-io")) {
|
||||
struct resource r;
|
||||
if (of_address_to_resource(mio, 0, &r) == 0)
|
||||
chip->macio_base =
|
||||
|
|
|
@ -1365,8 +1365,8 @@ int snd_pmac_tumbler_init(struct snd_pmac *chip)
|
|||
mix->anded_reset = 0;
|
||||
mix->reset_on_sleep = 1;
|
||||
|
||||
for (np = chip->node->child; np; np = np->sibling) {
|
||||
if (!strcmp(np->name, "sound")) {
|
||||
for_each_child_of_node(chip->node, np) {
|
||||
if (of_node_name_eq(np, "sound")) {
|
||||
if (of_get_property(np, "has-anded-reset", NULL))
|
||||
mix->anded_reset = 1;
|
||||
if (of_get_property(np, "layout-id", NULL))
|
||||
|
|
|
@ -46,13 +46,11 @@ source "sound/soc/atmel/Kconfig"
|
|||
source "sound/soc/au1x/Kconfig"
|
||||
source "sound/soc/bcm/Kconfig"
|
||||
source "sound/soc/cirrus/Kconfig"
|
||||
source "sound/soc/davinci/Kconfig"
|
||||
source "sound/soc/dwc/Kconfig"
|
||||
source "sound/soc/fsl/Kconfig"
|
||||
source "sound/soc/hisilicon/Kconfig"
|
||||
source "sound/soc/jz4740/Kconfig"
|
||||
source "sound/soc/nuc900/Kconfig"
|
||||
source "sound/soc/omap/Kconfig"
|
||||
source "sound/soc/kirkwood/Kconfig"
|
||||
source "sound/soc/img/Kconfig"
|
||||
source "sound/soc/intel/Kconfig"
|
||||
|
@ -70,9 +68,11 @@ source "sound/soc/sti/Kconfig"
|
|||
source "sound/soc/stm/Kconfig"
|
||||
source "sound/soc/sunxi/Kconfig"
|
||||
source "sound/soc/tegra/Kconfig"
|
||||
source "sound/soc/ti/Kconfig"
|
||||
source "sound/soc/txx9/Kconfig"
|
||||
source "sound/soc/uniphier/Kconfig"
|
||||
source "sound/soc/ux500/Kconfig"
|
||||
source "sound/soc/xilinx/Kconfig"
|
||||
source "sound/soc/xtensa/Kconfig"
|
||||
source "sound/soc/zte/Kconfig"
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ obj-$(CONFIG_SND_SOC) += atmel/
|
|||
obj-$(CONFIG_SND_SOC) += au1x/
|
||||
obj-$(CONFIG_SND_SOC) += bcm/
|
||||
obj-$(CONFIG_SND_SOC) += cirrus/
|
||||
obj-$(CONFIG_SND_SOC) += davinci/
|
||||
obj-$(CONFIG_SND_SOC) += dwc/
|
||||
obj-$(CONFIG_SND_SOC) += fsl/
|
||||
obj-$(CONFIG_SND_SOC) += hisilicon/
|
||||
|
@ -41,7 +40,6 @@ obj-$(CONFIG_SND_SOC) += mediatek/
|
|||
obj-$(CONFIG_SND_SOC) += meson/
|
||||
obj-$(CONFIG_SND_SOC) += mxs/
|
||||
obj-$(CONFIG_SND_SOC) += nuc900/
|
||||
obj-$(CONFIG_SND_SOC) += omap/
|
||||
obj-$(CONFIG_SND_SOC) += kirkwood/
|
||||
obj-$(CONFIG_SND_SOC) += pxa/
|
||||
obj-$(CONFIG_SND_SOC) += qcom/
|
||||
|
@ -54,8 +52,10 @@ obj-$(CONFIG_SND_SOC) += sti/
|
|||
obj-$(CONFIG_SND_SOC) += stm/
|
||||
obj-$(CONFIG_SND_SOC) += sunxi/
|
||||
obj-$(CONFIG_SND_SOC) += tegra/
|
||||
obj-$(CONFIG_SND_SOC) += ti/
|
||||
obj-$(CONFIG_SND_SOC) += txx9/
|
||||
obj-$(CONFIG_SND_SOC) += uniphier/
|
||||
obj-$(CONFIG_SND_SOC) += ux500/
|
||||
obj-$(CONFIG_SND_SOC) += xilinx/
|
||||
obj-$(CONFIG_SND_SOC) += xtensa/
|
||||
obj-$(CONFIG_SND_SOC) += zte/
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue