sound updates for 3.12-rc1
- HDPM: Updates for AIO/RayDAT support, TCO/sync support - RME96: Add PCM sync support - HD-audio: * A few HDMI/DP audio updates (CA assignment fix, stream switching fix, Intel DP device list support) * Device specific fixes (ASUS/CXT HP mic support, Thinkpad mic improvements, Chromebook fixes, STAC9228 Dell fixes) * Replace the all static quirks for AD codecs with the generic parser * WAKEEN support for handling irqs in the power saving mode - USB-audio: Clean up implicit fb handling and related codes - DAPM is now mandatory for ASoC CODEC drivers; all existing drivers have had some level of DAPM support added. In addition, a lot of cleanups and improvements in DAPM. - Support for ASoC cross-platform compile test - New drivers and support for Analog Devices ADAU1702 and ADAU1401(a), Asahi Kasei Microdevices AK4554, Atmel AT91ASM9x5 and WM8904 based machines, Freescale S/PDIF and SSI AC'97, Renesas R-Car SoCs, Samsung Exynos5420 SoCs, Texas Instruments PCM1681 and PCM1792A and Wolfson Microelectronics WM8997 - DT bindings for kirkwood and i.MX S/PDIF - Clean up and bug fixes: ssm2602, rt5640 and sgtl5000. - Core helpers for bitbanged AC'97 reset -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJSJ2E+AAoJEGwxgFQ9KSmkQQgP/izfCaTbvFsFOCwn8V8qgKCv fBnakk1IQp7vaMxx1g0wall9clZbnae7sCgst5aCeLjCglzIUHqgsX5xr23QQfPF WEVzW2LhrTmrRIVDnG0v1W5gUaYJk8H6qyMOkVWGtZvpn1M88TbJDv+P2ff3VqqU G1yqeogXGduForHkhDw2TCvnu5WNQGWtvd5O+QtT8kqWqUWqM5sWBbdl1oMpQUnm 0/YmFDSkNRSi8tXerYnfUf1qQuh40efHJ2oql3vfh8+I8nwPqZWScl5e+IwfgBPb azF0oeQM++R8/iZ89vk3hwndKzSN1y6Ok47gM2v+PwcJYoaEGDuIP8mVklUNQR9v ZK1n6AwlyxGH8snBKBX9upqcuT2xycBleh4sYw/t61/T4ne9L7WYY6a69dIetZ5e ALbzI1UP12S0oWiot/mqOcVLEneRNgKAD+K6Xcq7MYEA4g3MXbwWNrQRKRk3Hy5b BDWh39lb7Uh/v+D81UJEfy1UgsSOunUdsGV6AAsam9THW47+2+gO10MvALNueJhH QGOUVapLS553i6i7dZPj1tdumM8AKiqTRE9Bgsn4nWS3jOLtaO7EajOHoBha1JuG S9IxAMgI8y6h2ZXBTcdGrTFBjvbN9o0S3xYTAG0Z1hWGPTbKCxkpopZdbmHs1qJi Xsy9nBk9Dg2DEKDnZ555 =wbLt -----END PGP SIGNATURE----- Merge tag 'sound-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound updates from Takashi Iwai: "Changes are seen in a wide range of codes, mainly due to ASoC DAPM requirements; HD-audio shows a high peak in diffstat, it's just a removal of bunch of old static quirks. Some highlights: - HDPM: Updates for AIO/RayDAT support, TCO/sync support - RME96: Add PCM sync support - HD-audio: * A few HDMI/DP audio updates (CA assignment fix, stream switching fix, Intel DP device list support) * Device specific fixes (ASUS/CXT HP mic support, Thinkpad mic improvements, Chromebook fixes, STAC9228 Dell fixes) * Replace the all static quirks for AD codecs with the generic parser * WAKEEN support for handling irqs in the power saving mode - USB-audio: Clean up implicit fb handling and related codes - DAPM is now mandatory for ASoC CODEC drivers; all existing drivers have had some level of DAPM support added. In addition, a lot of cleanups and improvements in DAPM. - Support for ASoC cross-platform compile test - New drivers and support for Analog Devices ADAU1702 and ADAU1401(a), Asahi Kasei Microdevices AK4554, Atmel AT91ASM9x5 and WM8904 based machines, Freescale S/PDIF and SSI AC'97, Renesas R-Car SoCs, Samsung Exynos5420 SoCs, Texas Instruments PCM1681 and PCM1792A and Wolfson Microelectronics WM8997 - DT bindings for kirkwood and i.MX S/PDIF - Clean up and bug fixes: ssm2602, rt5640 and sgtl5000. - Core helpers for bitbanged AC'97 reset" * tag 'sound-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (375 commits) ALSA: hda - Re-setup HDMI pin and audio infoframe on stream switches ALSA: hda - hdmi: Fallback to ALSA allocation when selecting CA ASoC: mxs-sgtl5000: Configure the dai_links as unidirectional ASoC: soc-pcm: Allow to specify unidirectional dai_link ASoC: fsl_spdif: Staticse non-exported symbols ASoC: ssm2602: Fix cache sync ASoC: Remove unused sysfs_registered field from snd_soc_codec struct ASoC: Remove unused debugfs_dapm field from snd_soc_{platform,codec} struct ASoC: Remove unused control_type field from snd_soc_codec struct ASoC: fsl: Add one blank space after ':=' in Makefile ASoC: fsl: Add wrapping for dev_dbg() in fsl_spdif.c ASoC: rt5640: change widget sequence for depop ASoC: dapm: Fix auto-disable for inverted controls ASoC: fsl: Drop SND_SOC_FSL_UTILS from SND_SOC_IMX_SPDIF ASoC: Samsung: Do not queue cyclic buffers multiple times ASoC: ep93xx-i2s: Remove unnecessary dev_set_drvdata() ASoC: designware_i2s: Remove unnecessary dev_set_drvdata() ASoC: fsl_spdif: remove redundant dev_err call in fsl_spdif_probe() ASoC: fsl: Add S/PDIF machine driver ASoc: kirkwood: Use the Kirkwood audio driver in Dove boards ...
This commit is contained in:
commit
977dbfcf8e
|
@ -7,9 +7,30 @@ Required properties:
|
|||
- reg: Should contain SSC registers location and length
|
||||
- interrupts: Should contain SSC interrupt
|
||||
|
||||
Example:
|
||||
|
||||
Required properties for devices compatible with "atmel,at91sam9g45-ssc":
|
||||
- dmas: DMA specifier, consisting of a phandle to DMA controller node,
|
||||
the memory interface and SSC DMA channel ID (for tx and rx).
|
||||
See Documentation/devicetree/bindings/dma/atmel-dma.txt for details.
|
||||
- dma-names: Must be "tx", "rx".
|
||||
|
||||
Examples:
|
||||
- PDC transfer:
|
||||
ssc0: ssc@fffbc000 {
|
||||
compatible = "atmel,at91rm9200-ssc";
|
||||
reg = <0xfffbc000 0x4000>;
|
||||
interrupts = <14 4 5>;
|
||||
};
|
||||
|
||||
- DMA transfer:
|
||||
ssc0: ssc@f0010000 {
|
||||
compatible = "atmel,at91sam9g45-ssc";
|
||||
reg = <0xf0010000 0x4000>;
|
||||
interrupts = <28 4 5>;
|
||||
dmas = <&dma0 1 13>,
|
||||
<&dma0 1 14>;
|
||||
dma-names = "tx", "rx";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
|
65
Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt
Normal file
65
Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt
Normal file
|
@ -0,0 +1,65 @@
|
|||
Device tree bindings for Marvell PXA SSP ports
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be one of
|
||||
mrvl,pxa25x-ssp
|
||||
mvrl,pxa25x-nssp
|
||||
mrvl,pxa27x-ssp
|
||||
mrvl,pxa3xx-ssp
|
||||
mvrl,pxa168-ssp
|
||||
mrvl,pxa910-ssp
|
||||
mrvl,ce4100-ssp
|
||||
mrvl,lpss-ssp
|
||||
|
||||
- reg: The memory base
|
||||
- dmas: Two dma phandles, one for rx, one for tx
|
||||
- dma-names: Must be "rx", "tx"
|
||||
|
||||
|
||||
Example for PXA3xx:
|
||||
|
||||
ssp0: ssp@41000000 {
|
||||
compatible = "mrvl,pxa3xx-ssp";
|
||||
reg = <0x41000000 0x40>;
|
||||
ssp-id = <1>;
|
||||
interrupts = <24>;
|
||||
clock-names = "pxa27x-ssp.0";
|
||||
dmas = <&dma 13
|
||||
&dma 14>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
ssp1: ssp@41700000 {
|
||||
compatible = "mrvl,pxa3xx-ssp";
|
||||
reg = <0x41700000 0x40>;
|
||||
ssp-id = <2>;
|
||||
interrupts = <16>;
|
||||
clock-names = "pxa27x-ssp.1";
|
||||
dmas = <&dma 15
|
||||
&dma 16>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
ssp2: ssp@41900000 {
|
||||
compatibl3 = "mrvl,pxa3xx-ssp";
|
||||
reg = <0x41900000 0x40>;
|
||||
ssp-id = <3>;
|
||||
interrupts = <0>;
|
||||
clock-names = "pxa27x-ssp.2";
|
||||
dmas = <&dma 66
|
||||
&dma 67>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
ssp3: ssp@41a00000 {
|
||||
compatible = "mrvl,pxa3xx-ssp";
|
||||
reg = <0x41a00000 0x40>;
|
||||
ssp-id = <4>;
|
||||
interrupts = <13>;
|
||||
clock-names = "pxa27x-ssp.3";
|
||||
dmas = <&dma 2
|
||||
&dma 3>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
11
Documentation/devicetree/bindings/sound/ak4554.c
Normal file
11
Documentation/devicetree/bindings/sound/ak4554.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
AK4554 ADC/DAC
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "asahi-kasei,ak4554"
|
||||
|
||||
Example:
|
||||
|
||||
ak4554-adc-dac {
|
||||
compatible = "asahi-kasei,ak4554";
|
||||
};
|
|
@ -13,6 +13,25 @@ Required properties:
|
|||
- #gpio-cells : Should be two. The first cell is the pin number and the
|
||||
second cell is used to specify optional parameters (currently unused).
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* SPK_OUTP
|
||||
* SPK_OUTN
|
||||
* HP_OUT_L
|
||||
* HP_OUT_R
|
||||
* AUX_OUT_P
|
||||
* AUX_OUT_N
|
||||
* LINE_IN_L
|
||||
* LINE_IN_R
|
||||
* PHONE_P
|
||||
* PHONE_N
|
||||
* MIC1_P
|
||||
* MIC1_N
|
||||
* MIC2_P
|
||||
* MIC2_N
|
||||
* MICBIAS1
|
||||
* DMICDAT
|
||||
|
||||
Example:
|
||||
|
||||
alc5632: alc5632@1e {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
* Atmel at91sam9x5ek wm8731 audio complex
|
||||
|
||||
Required properties:
|
||||
- compatible: "atmel,sam9x5-wm8731-audio"
|
||||
- atmel,model: The user-visible name of this sound complex.
|
||||
- atmel,ssc-controller: The phandle of the SSC controller
|
||||
- atmel,audio-codec: The phandle of the WM8731 audio codec
|
||||
- atmel,audio-routing: A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the connection's sink,
|
||||
the second being the connection's source.
|
||||
|
||||
Available audio endpoints for the audio-routing table:
|
||||
|
||||
Board connectors:
|
||||
* Headphone Jack
|
||||
* Line In Jack
|
||||
|
||||
wm8731 pins:
|
||||
cf Documentation/devicetree/bindings/sound/wm8731.txt
|
||||
|
||||
Example:
|
||||
sound {
|
||||
compatible = "atmel,sam9x5-wm8731-audio";
|
||||
|
||||
atmel,model = "wm8731 @ AT91SAM9X5EK";
|
||||
|
||||
atmel,audio-routing =
|
||||
"Headphone Jack", "RHPOUT",
|
||||
"Headphone Jack", "LHPOUT",
|
||||
"LLINEIN", "Line In Jack",
|
||||
"RLINEIN", "Line In Jack";
|
||||
|
||||
atmel,ssc-controller = <&ssc0>;
|
||||
atmel,audio-codec = <&wm8731>;
|
||||
};
|
55
Documentation/devicetree/bindings/sound/atmel-wm8904.txt
Normal file
55
Documentation/devicetree/bindings/sound/atmel-wm8904.txt
Normal file
|
@ -0,0 +1,55 @@
|
|||
Atmel ASoC driver with wm8904 audio codec complex
|
||||
|
||||
Required properties:
|
||||
- compatible: "atmel,asoc-wm8904"
|
||||
- atmel,model: The user-visible name of this sound complex.
|
||||
- atmel,audio-routing: A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the connection's sink,
|
||||
the second being the connection's source. Valid names for sources and
|
||||
sinks are the WM8904's pins, and the jacks on the board:
|
||||
|
||||
WM8904 pins:
|
||||
|
||||
* IN1L
|
||||
* IN1R
|
||||
* IN2L
|
||||
* IN2R
|
||||
* IN3L
|
||||
* IN3R
|
||||
* HPOUTL
|
||||
* HPOUTR
|
||||
* LINEOUTL
|
||||
* LINEOUTR
|
||||
* MICBIAS
|
||||
|
||||
Board connectors:
|
||||
|
||||
* Headphone Jack
|
||||
* Line In Jack
|
||||
* Mic
|
||||
|
||||
- atmel,ssc-controller: The phandle of the SSC controller
|
||||
- atmel,audio-codec: The phandle of the WM8904 audio codec
|
||||
|
||||
Optional properties:
|
||||
- pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
|
||||
|
||||
Example:
|
||||
sound {
|
||||
compatible = "atmel,asoc-wm8904";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_pck0_as_mck>;
|
||||
|
||||
atmel,model = "wm8904 @ AT91SAM9N12EK";
|
||||
|
||||
atmel,audio-routing =
|
||||
"Headphone Jack", "HPOUTL",
|
||||
"Headphone Jack", "HPOUTR",
|
||||
"IN2L", "Line In Jack",
|
||||
"IN2R", "Line In Jack",
|
||||
"Mic", "MICBIAS",
|
||||
"IN1L", "Mic";
|
||||
|
||||
atmel,ssc-controller = <&ssc0>;
|
||||
atmel,audio-codec = <&wm8904>;
|
||||
};
|
54
Documentation/devicetree/bindings/sound/fsl,spdif.txt
Normal file
54
Documentation/devicetree/bindings/sound/fsl,spdif.txt
Normal file
|
@ -0,0 +1,54 @@
|
|||
Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller
|
||||
|
||||
The Freescale S/PDIF audio block is a stereo transceiver that allows the
|
||||
processor to receive and transmit digital audio via an coaxial cable or
|
||||
a fibre cable.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Compatible list, must contain "fsl,imx35-spdif".
|
||||
|
||||
- reg : Offset and length of the register set for the device.
|
||||
|
||||
- interrupts : Contains the spdif interrupt.
|
||||
|
||||
- dmas : Generic dma devicetree binding as described in
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
|
||||
- dma-names : Two dmas have to be defined, "tx" and "rx".
|
||||
|
||||
- clocks : Contains an entry for each entry in clock-names.
|
||||
|
||||
- clock-names : Includes the following entries:
|
||||
"core" The core clock of spdif controller
|
||||
"rxtx<0-7>" Clock source list for tx and rx clock.
|
||||
This clock list should be identical to
|
||||
the source list connecting to the spdif
|
||||
clock mux in "SPDIF Transceiver Clock
|
||||
Diagram" of SoC reference manual. It
|
||||
can also be referred to TxClk_Source
|
||||
bit of register SPDIF_STC.
|
||||
|
||||
Example:
|
||||
|
||||
spdif: spdif@02004000 {
|
||||
compatible = "fsl,imx35-spdif";
|
||||
reg = <0x02004000 0x4000>;
|
||||
interrupts = <0 52 0x04>;
|
||||
dmas = <&sdma 14 18 0>,
|
||||
<&sdma 15 18 0>;
|
||||
dma-names = "rx", "tx";
|
||||
|
||||
clocks = <&clks 197>, <&clks 3>,
|
||||
<&clks 197>, <&clks 107>,
|
||||
<&clks 0>, <&clks 118>,
|
||||
<&clks 62>, <&clks 139>,
|
||||
<&clks 0>;
|
||||
clock-names = "core", "rxtx0",
|
||||
"rxtx1", "rxtx2",
|
||||
"rxtx3", "rxtx4",
|
||||
"rxtx5", "rxtx6",
|
||||
"rxtx7";
|
||||
|
||||
status = "okay";
|
||||
};
|
|
@ -43,10 +43,22 @@ Required properties:
|
|||
together. This would still allow different sample sizes,
|
||||
but not different sample rates.
|
||||
|
||||
Required are also ac97 link bindings if ac97 is used. See
|
||||
Documentation/devicetree/bindings/sound/soc-ac97link.txt for the necessary
|
||||
bindings.
|
||||
|
||||
Optional properties:
|
||||
- codec-handle: Phandle to a 'codec' node that defines an audio
|
||||
codec connected to this SSI. This node is typically
|
||||
a child of an I2C or other control node.
|
||||
- fsl,fiq-stream-filter: Bool property. Disabled DMA and use FIQ instead to
|
||||
filter the codec stream. This is necessary for some boards
|
||||
where an incompatible codec is connected to this SSI, e.g.
|
||||
on pca100 and pcm043.
|
||||
- dmas: Generic dma devicetree binding as described in
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
- dma-names: Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq
|
||||
is not defined.
|
||||
|
||||
Child 'codec' node required properties:
|
||||
- compatible: Compatible list, contains the name of the codec
|
34
Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
Normal file
34
Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
Freescale i.MX audio complex with S/PDIF transceiver
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "fsl,imx-audio-spdif"
|
||||
|
||||
- model : The user-visible name of this sound complex
|
||||
|
||||
- spdif-controller : The phandle of the i.MX S/PDIF controller
|
||||
|
||||
|
||||
Optional properties:
|
||||
|
||||
- spdif-out : This is a boolean property. If present, the transmitting
|
||||
function of S/PDIF will be enabled, indicating there's a physical
|
||||
S/PDIF out connector/jack on the board or it's connecting to some
|
||||
other IP block, such as an HDMI encoder/display-controller.
|
||||
|
||||
- spdif-in : This is a boolean property. If present, the receiving
|
||||
function of S/PDIF will be enabled, indicating there's a physical
|
||||
S/PDIF in connector/jack on the board.
|
||||
|
||||
* Note: At least one of these two properties should be set in the DT binding.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
sound-spdif {
|
||||
compatible = "fsl,imx-audio-spdif";
|
||||
model = "imx-spdif";
|
||||
spdif-controller = <&spdif>;
|
||||
spdif-out;
|
||||
spdif-in;
|
||||
};
|
|
@ -5,6 +5,15 @@ Required properties:
|
|||
or "fsl,imx31-audmux" for the version firstly used on i.MX31.
|
||||
- reg : Should contain AUDMUX registers location and length
|
||||
|
||||
An initial configuration can be setup using child nodes.
|
||||
|
||||
Required properties of optional child nodes:
|
||||
- fsl,audmux-port : Integer of the audmux port that is configured by this
|
||||
child node.
|
||||
- fsl,port-config : List of configuration options for the specific port. For
|
||||
imx31-audmux and above, it is a list of tuples <ptcr pdcr>. For
|
||||
imx21-audmux it is a list of pcr values.
|
||||
|
||||
Example:
|
||||
|
||||
audmux@021d8000 {
|
||||
|
|
28
Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt
Normal file
28
Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
Marvell PXA SSP CPU DAI bindings
|
||||
|
||||
Required properties:
|
||||
|
||||
compatible Must be "mrvl,pxa-ssp-dai"
|
||||
port A phandle reference to a PXA ssp upstream device
|
||||
|
||||
Example:
|
||||
|
||||
/* upstream device */
|
||||
|
||||
ssp0: ssp@41000000 {
|
||||
compatible = "mrvl,pxa3xx-ssp";
|
||||
reg = <0x41000000 0x40>;
|
||||
interrupts = <24>;
|
||||
clock-names = "pxa27x-ssp.0";
|
||||
dmas = <&dma 13
|
||||
&dma 14>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
/* DAI as user */
|
||||
|
||||
ssp_dai0: ssp_dai@0 {
|
||||
compatible = "mrvl,pxa-ssp-dai";
|
||||
port = <&ssp0>;
|
||||
};
|
||||
|
15
Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt
Normal file
15
Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
DT bindings for ARM PXA2xx PCM platform driver
|
||||
|
||||
This is just a dummy driver that registers the PXA ASoC platform driver.
|
||||
It does not have any resources assigned.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible 'mrvl,pxa-pcm-audio'
|
||||
|
||||
Example:
|
||||
|
||||
pxa_pcm_audio: snd_soc_pxa_audio {
|
||||
compatible = "mrvl,pxa-pcm-audio";
|
||||
};
|
||||
|
29
Documentation/devicetree/bindings/sound/mvebu-audio.txt
Normal file
29
Documentation/devicetree/bindings/sound/mvebu-audio.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
* mvebu (Kirkwood, Dove, Armada 370) audio controller
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "marvell,mvebu-audio"
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
||||
- interrupts: list of two irq numbers.
|
||||
The first irq is used for data flow and the second one is used for errors.
|
||||
|
||||
- clocks: one or two phandles.
|
||||
The first one is mandatory and defines the internal clock.
|
||||
The second one is optional and defines an external clock.
|
||||
|
||||
- clock-names: names associated to the clocks:
|
||||
"internal" for the internal clock
|
||||
"extclk" for the external clock
|
||||
|
||||
Example:
|
||||
|
||||
i2s1: audio-controller@b4000 {
|
||||
compatible = "marvell,mvebu-audio";
|
||||
reg = <0xb4000 0x2210>;
|
||||
interrupts = <21>, <22>;
|
||||
clocks = <&gate_clk 13>;
|
||||
clock-names = "internal";
|
||||
};
|
|
@ -11,28 +11,8 @@ Required properties:
|
|||
- nvidia,audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the connection's sink,
|
||||
the second being the connection's source. Valid names for sources and
|
||||
sinks are the ALC5632's pins:
|
||||
|
||||
ALC5632 pins:
|
||||
|
||||
* SPK_OUTP
|
||||
* SPK_OUTN
|
||||
* HP_OUT_L
|
||||
* HP_OUT_R
|
||||
* AUX_OUT_P
|
||||
* AUX_OUT_N
|
||||
* LINE_IN_L
|
||||
* LINE_IN_R
|
||||
* PHONE_P
|
||||
* PHONE_N
|
||||
* MIC1_P
|
||||
* MIC1_N
|
||||
* MIC2_P
|
||||
* MIC2_N
|
||||
* MICBIAS1
|
||||
* DMICDAT
|
||||
|
||||
Board connectors:
|
||||
sinks are the ALC5632's pins as documented in the binding for the device
|
||||
and:
|
||||
|
||||
* Headset Stereophone
|
||||
* Int Spk
|
||||
|
|
|
@ -11,32 +11,12 @@ Required properties:
|
|||
- nvidia,audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the connection's sink,
|
||||
the second being the connection's source. Valid names for sources and
|
||||
sinks are the RT5640's pins, and the jacks on the board:
|
||||
|
||||
RT5640 pins:
|
||||
|
||||
* DMIC1
|
||||
* DMIC2
|
||||
* MICBIAS1
|
||||
* IN1P
|
||||
* IN1R
|
||||
* IN2P
|
||||
* IN2R
|
||||
* HPOL
|
||||
* HPOR
|
||||
* LOUTL
|
||||
* LOUTR
|
||||
* MONOP
|
||||
* MONON
|
||||
* SPOLP
|
||||
* SPOLN
|
||||
* SPORP
|
||||
* SPORN
|
||||
|
||||
Board connectors:
|
||||
sinks are the RT5640's pins (as documented in its binding), and the jacks
|
||||
on the board:
|
||||
|
||||
* Headphones
|
||||
* Speakers
|
||||
* Mic Jack
|
||||
|
||||
- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
|
||||
connected to the CODEC.
|
||||
|
|
|
@ -11,31 +11,8 @@ Required properties:
|
|||
- nvidia,audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the connection's sink,
|
||||
the second being the connection's source. Valid names for sources and
|
||||
sinks are the WM8753's pins, and the jacks on the board:
|
||||
|
||||
WM8753 pins:
|
||||
|
||||
* LOUT1
|
||||
* LOUT2
|
||||
* ROUT1
|
||||
* ROUT2
|
||||
* MONO1
|
||||
* MONO2
|
||||
* OUT3
|
||||
* OUT4
|
||||
* LINE1
|
||||
* LINE2
|
||||
* RXP
|
||||
* RXN
|
||||
* ACIN
|
||||
* ACOP
|
||||
* MIC1N
|
||||
* MIC1
|
||||
* MIC2N
|
||||
* MIC2
|
||||
* Mic Bias
|
||||
|
||||
Board connectors:
|
||||
sinks are the WM8753's pins as documented in the binding for the WM8753,
|
||||
and the jacks on the board:
|
||||
|
||||
* Headphone Jack
|
||||
* Mic Jack
|
||||
|
|
|
@ -11,28 +11,8 @@ Required properties:
|
|||
- nvidia,audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the connection's sink,
|
||||
the second being the connection's source. Valid names for sources and
|
||||
sinks are the WM8903's pins, and the jacks on the board:
|
||||
|
||||
WM8903 pins:
|
||||
|
||||
* IN1L
|
||||
* IN1R
|
||||
* IN2L
|
||||
* IN2R
|
||||
* IN3L
|
||||
* IN3R
|
||||
* DMICDAT
|
||||
* HPOUTL
|
||||
* HPOUTR
|
||||
* LINEOUTL
|
||||
* LINEOUTR
|
||||
* LOP
|
||||
* LON
|
||||
* ROP
|
||||
* RON
|
||||
* MICBIAS
|
||||
|
||||
Board connectors:
|
||||
sinks are the WM8903's pins (documented in the WM8903 binding document),
|
||||
and the jacks on the board:
|
||||
|
||||
* Headphone Jack
|
||||
* Int Spk
|
||||
|
|
18
Documentation/devicetree/bindings/sound/pcm1792a.txt
Normal file
18
Documentation/devicetree/bindings/sound/pcm1792a.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
Texas Instruments pcm1792a DT bindings
|
||||
|
||||
This driver supports the SPI bus.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "ti,pcm1792a"
|
||||
|
||||
For required properties on SPI, please consult
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Examples:
|
||||
|
||||
codec_spi: 1792a@0 {
|
||||
compatible = "ti,pcm1792a";
|
||||
spi-max-frequency = <600000>;
|
||||
};
|
||||
|
|
@ -18,6 +18,26 @@ Optional properties:
|
|||
|
||||
- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* DMIC1
|
||||
* DMIC2
|
||||
* MICBIAS1
|
||||
* IN1P
|
||||
* IN1R
|
||||
* IN2P
|
||||
* IN2R
|
||||
* HPOL
|
||||
* HPOR
|
||||
* LOUTL
|
||||
* LOUTR
|
||||
* MONOP
|
||||
* MONON
|
||||
* SPOLP
|
||||
* SPOLN
|
||||
* SPORP
|
||||
* SPORN
|
||||
|
||||
Example:
|
||||
|
||||
rt5640 {
|
||||
|
|
|
@ -2,7 +2,15 @@
|
|||
|
||||
Required SoC Specific Properties:
|
||||
|
||||
- compatible : "samsung,i2s-v5"
|
||||
- compatible : should be one of the following.
|
||||
- samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
|
||||
- samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
|
||||
secondary fifo, s/w reset control and internal mux for root clk src.
|
||||
- samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with
|
||||
secondary fifo, s/w reset control, internal mux for root clk src and
|
||||
TDM support. TDM (Time division multiplexing) is to allow transfer of
|
||||
multiple channel audio data on single data line.
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- dmas: list of DMA controller phandle and DMA request line ordered pairs.
|
||||
|
@ -21,13 +29,6 @@ Required SoC Specific Properties:
|
|||
|
||||
Optional SoC Specific Properties:
|
||||
|
||||
- samsung,supports-6ch: If the I2S Primary sound source has 5.1 Channel
|
||||
support, this flag is enabled.
|
||||
- samsung,supports-rstclr: This flag should be set if I2S software reset bit
|
||||
control is required. When this flag is set I2S software reset bit will be
|
||||
enabled or disabled based on need.
|
||||
- samsung,supports-secdai:If I2S block has a secondary FIFO and internal DMA,
|
||||
then this flag is enabled.
|
||||
- samsung,idma-addr: Internal DMA register base address of the audio
|
||||
sub system(used in secondary sound source).
|
||||
- pinctrl-0: Should specify pin control groups used for this controller.
|
||||
|
@ -36,7 +37,7 @@ Optional SoC Specific Properties:
|
|||
Example:
|
||||
|
||||
i2s0: i2s@03830000 {
|
||||
compatible = "samsung,i2s-v5";
|
||||
compatible = "samsung,s5pv210-i2s";
|
||||
reg = <0x03830000 0x100>;
|
||||
dmas = <&pdma0 10
|
||||
&pdma0 9
|
||||
|
@ -46,9 +47,6 @@ i2s0: i2s@03830000 {
|
|||
<&clock_audss EXYNOS_I2S_BUS>,
|
||||
<&clock_audss EXYNOS_SCLK_I2S>;
|
||||
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
|
||||
samsung,supports-6ch;
|
||||
samsung,supports-rstclr;
|
||||
samsung,supports-secdai;
|
||||
samsung,idma-addr = <0x03000000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2s0_bus>;
|
||||
|
|
28
Documentation/devicetree/bindings/sound/soc-ac97link.txt
Normal file
28
Documentation/devicetree/bindings/sound/soc-ac97link.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
AC97 link bindings
|
||||
|
||||
These bindings can be included within any other device node.
|
||||
|
||||
Required properties:
|
||||
- pinctrl-names: Has to contain following states to setup the correct
|
||||
pinmuxing for the used gpios:
|
||||
"ac97-running": AC97-link is active
|
||||
"ac97-reset": AC97-link reset state
|
||||
"ac97-warm-reset": AC97-link warm reset state
|
||||
- ac97-gpios: List of gpio phandles with args in the order ac97-sync,
|
||||
ac97-sdata, ac97-reset
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
ssi {
|
||||
...
|
||||
|
||||
pinctrl-names = "default", "ac97-running", "ac97-reset", "ac97-warm-reset";
|
||||
pinctrl-0 = <&ac97link_running>;
|
||||
pinctrl-1 = <&ac97link_running>;
|
||||
pinctrl-2 = <&ac97link_reset>;
|
||||
pinctrl-3 = <&ac97link_warm_reset>;
|
||||
ac97-gpios = <&gpio3 20 0 &gpio3 22 0 &gpio3 28 0>;
|
||||
|
||||
...
|
||||
};
|
15
Documentation/devicetree/bindings/sound/ti,pcm1681.txt
Normal file
15
Documentation/devicetree/bindings/sound/ti,pcm1681.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
Texas Instruments PCM1681 8-channel PWM Processor
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should contain "ti,pcm1681".
|
||||
- reg: The i2c address. Should contain <0x4c>.
|
||||
|
||||
Examples:
|
||||
|
||||
i2c_bus {
|
||||
pcm1681@4c {
|
||||
compatible = "ti,pcm1681";
|
||||
reg = <0x4c>;
|
||||
};
|
||||
};
|
|
@ -3,7 +3,14 @@ Texas Instruments - tlv320aic3x Codec module
|
|||
The tlv320aic3x serial control bus communicates through I2C protocols
|
||||
|
||||
Required properties:
|
||||
- compatible - "string" - "ti,tlv320aic3x"
|
||||
|
||||
- compatible - "string" - One of:
|
||||
"ti,tlv320aic3x" - Generic TLV320AIC3x device
|
||||
"ti,tlv320aic33" - TLV320AIC33
|
||||
"ti,tlv320aic3007" - TLV320AIC3007
|
||||
"ti,tlv320aic3106" - TLV320AIC3106
|
||||
|
||||
|
||||
- reg - <int> - I2C slave address
|
||||
|
||||
|
||||
|
|
|
@ -16,3 +16,12 @@ codec: wm8731@1a {
|
|||
compatible = "wlf,wm8731";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
||||
Available audio endpoints for an audio-routing table:
|
||||
* LOUT: Left Channel Line Output
|
||||
* ROUT: Right Channel Line Output
|
||||
* LHPOUT: Left Channel Headphone Output
|
||||
* RHPOUT: Right Channel Headphone Output
|
||||
* LLINEIN: Left Channel Line Input
|
||||
* RLINEIN: Right Channel Line Input
|
||||
* MICIN: Microphone Input
|
||||
|
|
|
@ -10,9 +10,31 @@ Required properties:
|
|||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* LOUT1
|
||||
* LOUT2
|
||||
* ROUT1
|
||||
* ROUT2
|
||||
* MONO1
|
||||
* MONO2
|
||||
* OUT3
|
||||
* OUT4
|
||||
* LINE1
|
||||
* LINE2
|
||||
* RXP
|
||||
* RXN
|
||||
* ACIN
|
||||
* ACOP
|
||||
* MIC1N
|
||||
* MIC1
|
||||
* MIC2N
|
||||
* MIC2
|
||||
* Mic Bias
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8737@1a {
|
||||
codec: wm8753@1a {
|
||||
compatible = "wlf,wm8753";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
|
|
@ -28,6 +28,25 @@ Optional properties:
|
|||
performed. If any entry has the value 0xffffffff, that GPIO's
|
||||
configuration will not be modified.
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* IN1L
|
||||
* IN1R
|
||||
* IN2L
|
||||
* IN2R
|
||||
* IN3L
|
||||
* IN3R
|
||||
* DMICDAT
|
||||
* HPOUTL
|
||||
* HPOUTR
|
||||
* LINEOUTL
|
||||
* LINEOUTR
|
||||
* LOP
|
||||
* LON
|
||||
* ROP
|
||||
* RON
|
||||
* MICBIAS
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8903@1a {
|
||||
|
|
|
@ -32,6 +32,10 @@ Optional properties:
|
|||
The second cell is the flags, encoded as the trigger masks from
|
||||
Documentation/devicetree/bindings/interrupts.txt
|
||||
|
||||
- clocks : A list of up to two phandle and clock specifier pairs
|
||||
- clock-names : A list of clock names sorted in the same order as clocks.
|
||||
Valid clock names are "MCLK1" and "MCLK2".
|
||||
|
||||
- wlf,gpio-cfg : A list of GPIO configuration register values. If absent,
|
||||
no configuration of these registers is performed. If any value is
|
||||
over 0xffff then the register will be left as default. If present 11
|
||||
|
|
|
@ -244,6 +244,7 @@ STAC9227/9228/9229/927x
|
|||
5stack-no-fp D965 5stack without front panel
|
||||
dell-3stack Dell Dimension E520
|
||||
dell-bios Fixes with Dell BIOS setup
|
||||
dell-bios-amic Fixes with Dell BIOS setup including analog mic
|
||||
volknob Fixes with volume-knob widget 0x24
|
||||
auto BIOS setup (default)
|
||||
|
||||
|
|
|
@ -454,6 +454,8 @@ The generic parser supports the following hints:
|
|||
- need_dac_fix (bool): limits the DACs depending on the channel count
|
||||
- primary_hp (bool): probe headphone jacks as the primary outputs;
|
||||
default true
|
||||
- multi_io (bool): try probing multi-I/O config (e.g. shared
|
||||
line-in/surround, mic/clfe jacks)
|
||||
- multi_cap_vol (bool): provide multiple capture volumes
|
||||
- inv_dmic_split (bool): provide split internal mic volume/switch for
|
||||
phase-inverted digital mics
|
||||
|
|
13
MAINTAINERS
13
MAINTAINERS
|
@ -595,6 +595,7 @@ S: Supported
|
|||
F: sound/soc/codecs/adau*
|
||||
F: sound/soc/codecs/adav*
|
||||
F: sound/soc/codecs/ad1*
|
||||
F: sound/soc/codecs/ad7*
|
||||
F: sound/soc/codecs/ssm*
|
||||
F: sound/soc/codecs/sigmadsp.*
|
||||
|
||||
|
@ -7694,6 +7695,17 @@ F: include/sound/
|
|||
F: include/uapi/sound/
|
||||
F: sound/
|
||||
|
||||
SOUND - COMPRESSED AUDIO
|
||||
M: Vinod Koul <vinod.koul@intel.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
|
||||
S: Supported
|
||||
F: Documentation/sound/alsa/compress_offload.txt
|
||||
F: include/sound/compress_driver.h
|
||||
F: include/uapi/sound/compress_*
|
||||
F: sound/core/compress_offload.c
|
||||
F: sound/soc/soc-compress.c
|
||||
|
||||
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
|
||||
M: Liam Girdwood <lgirdwood@gmail.com>
|
||||
M: Mark Brown <broonie@kernel.org>
|
||||
|
@ -7701,6 +7713,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
|
|||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
W: http://alsa-project.org/main/index.php/ASoC
|
||||
S: Supported
|
||||
F: Documentation/sound/alsa/soc/
|
||||
F: sound/soc/
|
||||
F: include/sound/soc*
|
||||
|
||||
|
|
|
@ -405,7 +405,7 @@
|
|||
};
|
||||
|
||||
i2s0: i2s@03830000 {
|
||||
compatible = "samsung,i2s-v5";
|
||||
compatible = "samsung,s5pv210-i2s";
|
||||
reg = <0x03830000 0x100>;
|
||||
dmas = <&pdma0 10
|
||||
&pdma0 9
|
||||
|
@ -415,16 +415,13 @@
|
|||
<&clock_audss EXYNOS_I2S_BUS>,
|
||||
<&clock_audss EXYNOS_SCLK_I2S>;
|
||||
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
|
||||
samsung,supports-6ch;
|
||||
samsung,supports-rstclr;
|
||||
samsung,supports-secdai;
|
||||
samsung,idma-addr = <0x03000000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2s0_bus>;
|
||||
};
|
||||
|
||||
i2s1: i2s@12D60000 {
|
||||
compatible = "samsung,i2s-v5";
|
||||
compatible = "samsung,s3c6410-i2s";
|
||||
reg = <0x12D60000 0x100>;
|
||||
dmas = <&pdma1 12
|
||||
&pdma1 11>;
|
||||
|
@ -436,7 +433,7 @@
|
|||
};
|
||||
|
||||
i2s2: i2s@12D70000 {
|
||||
compatible = "samsung,i2s-v5";
|
||||
compatible = "samsung,s3c6410-i2s";
|
||||
reg = <0x12D70000 0x100>;
|
||||
dmas = <&pdma0 12
|
||||
&pdma0 11>;
|
||||
|
|
|
@ -108,8 +108,8 @@ static void __init dove_clk_init(void)
|
|||
orion_clkdev_add(NULL, "sdhci-dove.1", sdio1);
|
||||
orion_clkdev_add(NULL, "orion_nand", nand);
|
||||
orion_clkdev_add(NULL, "cafe1000-ccic.0", camera);
|
||||
orion_clkdev_add(NULL, "kirkwood-i2s.0", i2s0);
|
||||
orion_clkdev_add(NULL, "kirkwood-i2s.1", i2s1);
|
||||
orion_clkdev_add(NULL, "mvebu-audio.0", i2s0);
|
||||
orion_clkdev_add(NULL, "mvebu-audio.1", i2s1);
|
||||
orion_clkdev_add(NULL, "mv_crypto", crypto);
|
||||
orion_clkdev_add(NULL, "dove-ac97", ac97);
|
||||
orion_clkdev_add(NULL, "dove-pdma", pdma);
|
||||
|
|
|
@ -264,7 +264,7 @@ void __init kirkwood_clk_init(void)
|
|||
orion_clkdev_add(NULL, MV_XOR_NAME ".1", xor1);
|
||||
orion_clkdev_add("0", "pcie", pex0);
|
||||
orion_clkdev_add("1", "pcie", pex1);
|
||||
orion_clkdev_add(NULL, "kirkwood-i2s", audio);
|
||||
orion_clkdev_add(NULL, "mvebu-audio", audio);
|
||||
orion_clkdev_add(NULL, MV64XXX_I2C_CTLR_NAME ".0", runit);
|
||||
orion_clkdev_add(NULL, MV64XXX_I2C_CTLR_NAME ".1", runit);
|
||||
|
||||
|
@ -560,7 +560,7 @@ void __init kirkwood_timer_init(void)
|
|||
/*****************************************************************************
|
||||
* Audio
|
||||
****************************************************************************/
|
||||
static struct resource kirkwood_i2s_resources[] = {
|
||||
static struct resource kirkwood_audio_resources[] = {
|
||||
[0] = {
|
||||
.start = AUDIO_PHYS_BASE,
|
||||
.end = AUDIO_PHYS_BASE + SZ_16K - 1,
|
||||
|
@ -573,29 +573,23 @@ static struct resource kirkwood_i2s_resources[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
|
||||
static struct kirkwood_asoc_platform_data kirkwood_audio_data = {
|
||||
.burst = 128,
|
||||
};
|
||||
|
||||
static struct platform_device kirkwood_i2s_device = {
|
||||
.name = "kirkwood-i2s",
|
||||
static struct platform_device kirkwood_audio_device = {
|
||||
.name = "mvebu-audio",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(kirkwood_i2s_resources),
|
||||
.resource = kirkwood_i2s_resources,
|
||||
.num_resources = ARRAY_SIZE(kirkwood_audio_resources),
|
||||
.resource = kirkwood_audio_resources,
|
||||
.dev = {
|
||||
.platform_data = &kirkwood_i2s_data,
|
||||
.platform_data = &kirkwood_audio_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device kirkwood_pcm_device = {
|
||||
.name = "kirkwood-pcm-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
void __init kirkwood_audio_init(void)
|
||||
{
|
||||
platform_device_register(&kirkwood_i2s_device);
|
||||
platform_device_register(&kirkwood_pcm_device);
|
||||
platform_device_register(&kirkwood_audio_device);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <mach/hardware.h>
|
||||
|
@ -60,6 +62,30 @@ struct ssp_device *pxa_ssp_request(int port, const char *label)
|
|||
}
|
||||
EXPORT_SYMBOL(pxa_ssp_request);
|
||||
|
||||
struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
|
||||
const char *label)
|
||||
{
|
||||
struct ssp_device *ssp = NULL;
|
||||
|
||||
mutex_lock(&ssp_lock);
|
||||
|
||||
list_for_each_entry(ssp, &ssp_list, node) {
|
||||
if (ssp->of_node == of_node && ssp->use_count == 0) {
|
||||
ssp->use_count++;
|
||||
ssp->label = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&ssp_lock);
|
||||
|
||||
if (&ssp->node == &ssp_list)
|
||||
return NULL;
|
||||
|
||||
return ssp;
|
||||
}
|
||||
EXPORT_SYMBOL(pxa_ssp_request_of);
|
||||
|
||||
void pxa_ssp_free(struct ssp_device *ssp)
|
||||
{
|
||||
mutex_lock(&ssp_lock);
|
||||
|
@ -72,96 +98,126 @@ void pxa_ssp_free(struct ssp_device *ssp)
|
|||
}
|
||||
EXPORT_SYMBOL(pxa_ssp_free);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pxa_ssp_of_ids[] = {
|
||||
{ .compatible = "mrvl,pxa25x-ssp", .data = (void *) PXA25x_SSP },
|
||||
{ .compatible = "mvrl,pxa25x-nssp", .data = (void *) PXA25x_NSSP },
|
||||
{ .compatible = "mrvl,pxa27x-ssp", .data = (void *) PXA27x_SSP },
|
||||
{ .compatible = "mrvl,pxa3xx-ssp", .data = (void *) PXA3xx_SSP },
|
||||
{ .compatible = "mvrl,pxa168-ssp", .data = (void *) PXA168_SSP },
|
||||
{ .compatible = "mrvl,pxa910-ssp", .data = (void *) PXA910_SSP },
|
||||
{ .compatible = "mrvl,ce4100-ssp", .data = (void *) CE4100_SSP },
|
||||
{ .compatible = "mrvl,lpss-ssp", .data = (void *) LPSS_SSP },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids);
|
||||
#endif
|
||||
|
||||
static int pxa_ssp_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *id = platform_get_device_id(pdev);
|
||||
struct resource *res;
|
||||
struct ssp_device *ssp;
|
||||
int ret = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
ssp = kzalloc(sizeof(struct ssp_device), GFP_KERNEL);
|
||||
if (ssp == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory");
|
||||
ssp = devm_kzalloc(dev, sizeof(struct ssp_device), GFP_KERNEL);
|
||||
if (ssp == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ssp->pdev = pdev;
|
||||
|
||||
ssp->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(ssp->clk)) {
|
||||
ret = PTR_ERR(ssp->clk);
|
||||
goto err_free;
|
||||
}
|
||||
ssp->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(ssp->clk))
|
||||
return PTR_ERR(ssp->clk);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "no SSP RX DRCMR defined\n");
|
||||
ret = -ENODEV;
|
||||
goto err_free_clk;
|
||||
}
|
||||
ssp->drcmr_rx = res->start;
|
||||
if (dev->of_node) {
|
||||
struct of_phandle_args dma_spec;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "no SSP TX DRCMR defined\n");
|
||||
ret = -ENODEV;
|
||||
goto err_free_clk;
|
||||
/*
|
||||
* FIXME: we should allocate the DMA channel from this
|
||||
* context and pass the channel down to the ssp users.
|
||||
* For now, we lookup the rx and tx indices manually
|
||||
*/
|
||||
|
||||
/* rx */
|
||||
of_parse_phandle_with_args(np, "dmas", "#dma-cells",
|
||||
0, &dma_spec);
|
||||
ssp->drcmr_rx = dma_spec.args[0];
|
||||
of_node_put(dma_spec.np);
|
||||
|
||||
/* tx */
|
||||
of_parse_phandle_with_args(np, "dmas", "#dma-cells",
|
||||
1, &dma_spec);
|
||||
ssp->drcmr_tx = dma_spec.args[0];
|
||||
of_node_put(dma_spec.np);
|
||||
} else {
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(dev, "no SSP RX DRCMR defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ssp->drcmr_rx = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (res == NULL) {
|
||||
dev_err(dev, "no SSP TX DRCMR defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ssp->drcmr_tx = res->start;
|
||||
}
|
||||
ssp->drcmr_tx = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "no memory resource defined\n");
|
||||
ret = -ENODEV;
|
||||
goto err_free_clk;
|
||||
dev_err(dev, "no memory resource defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
res = request_mem_region(res->start, resource_size(res),
|
||||
pdev->name);
|
||||
res = devm_request_mem_region(dev, res->start, resource_size(res),
|
||||
pdev->name);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "failed to request memory resource\n");
|
||||
ret = -EBUSY;
|
||||
goto err_free_clk;
|
||||
dev_err(dev, "failed to request memory resource\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ssp->phys_base = res->start;
|
||||
|
||||
ssp->mmio_base = ioremap(res->start, resource_size(res));
|
||||
ssp->mmio_base = devm_ioremap(dev, res->start, resource_size(res));
|
||||
if (ssp->mmio_base == NULL) {
|
||||
dev_err(&pdev->dev, "failed to ioremap() registers\n");
|
||||
ret = -ENODEV;
|
||||
goto err_free_mem;
|
||||
dev_err(dev, "failed to ioremap() registers\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ssp->irq = platform_get_irq(pdev, 0);
|
||||
if (ssp->irq < 0) {
|
||||
dev_err(&pdev->dev, "no IRQ resource defined\n");
|
||||
ret = -ENODEV;
|
||||
goto err_free_io;
|
||||
dev_err(dev, "no IRQ resource defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (dev->of_node) {
|
||||
const struct of_device_id *id =
|
||||
of_match_device(of_match_ptr(pxa_ssp_of_ids), dev);
|
||||
ssp->type = (int) id->data;
|
||||
} else {
|
||||
const struct platform_device_id *id =
|
||||
platform_get_device_id(pdev);
|
||||
ssp->type = (int) id->driver_data;
|
||||
|
||||
/* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
|
||||
* starts from 0, do a translation here
|
||||
*/
|
||||
ssp->port_id = pdev->id + 1;
|
||||
}
|
||||
|
||||
/* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
|
||||
* starts from 0, do a translation here
|
||||
*/
|
||||
ssp->port_id = pdev->id + 1;
|
||||
ssp->use_count = 0;
|
||||
ssp->type = (int)id->driver_data;
|
||||
ssp->of_node = dev->of_node;
|
||||
|
||||
mutex_lock(&ssp_lock);
|
||||
list_add(&ssp->node, &ssp_list);
|
||||
mutex_unlock(&ssp_lock);
|
||||
|
||||
platform_set_drvdata(pdev, ssp);
|
||||
return 0;
|
||||
|
||||
err_free_io:
|
||||
iounmap(ssp->mmio_base);
|
||||
err_free_mem:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
err_free_clk:
|
||||
clk_put(ssp->clk);
|
||||
err_free:
|
||||
kfree(ssp);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa_ssp_remove(struct platform_device *pdev)
|
||||
|
@ -201,8 +257,9 @@ static struct platform_driver pxa_ssp_driver = {
|
|||
.probe = pxa_ssp_probe,
|
||||
.remove = pxa_ssp_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "pxa2xx-ssp",
|
||||
.owner = THIS_MODULE,
|
||||
.name = "pxa2xx-ssp",
|
||||
.of_match_table = of_match_ptr(pxa_ssp_of_ids),
|
||||
},
|
||||
.id_table = ssp_id_table,
|
||||
};
|
||||
|
|
|
@ -82,7 +82,8 @@ static int s3c_dma_config(unsigned ch, struct samsung_dma_config *param)
|
|||
static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
|
||||
{
|
||||
struct cb_data *data;
|
||||
int len = (param->cap == DMA_CYCLIC) ? param->period : param->len;
|
||||
dma_addr_t pos = param->buf;
|
||||
dma_addr_t end = param->buf + param->len;
|
||||
|
||||
list_for_each_entry(data, &dma_list, node)
|
||||
if (data->ch == ch)
|
||||
|
@ -94,7 +95,15 @@ static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
|
|||
data->fp_param = param->fp_param;
|
||||
}
|
||||
|
||||
s3c2410_dma_enqueue(ch, (void *)data, param->buf, len);
|
||||
if (param->cap != DMA_CYCLIC) {
|
||||
s3c2410_dma_enqueue(ch, (void *)data, param->buf, param->len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (pos < end) {
|
||||
s3c2410_dma_enqueue(ch, (void *)data, pos, param->period);
|
||||
pos += param->period;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
56
include/dt-bindings/sound/fsl-imx-audmux.h
Normal file
56
include/dt-bindings/sound/fsl-imx-audmux.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef __DT_FSL_IMX_AUDMUX_H
|
||||
#define __DT_FSL_IMX_AUDMUX_H
|
||||
|
||||
#define MX27_AUDMUX_HPCR1_SSI0 0
|
||||
#define MX27_AUDMUX_HPCR2_SSI1 1
|
||||
#define MX27_AUDMUX_HPCR3_SSI_PINS_4 2
|
||||
#define MX27_AUDMUX_PPCR1_SSI_PINS_1 3
|
||||
#define MX27_AUDMUX_PPCR2_SSI_PINS_2 4
|
||||
#define MX27_AUDMUX_PPCR3_SSI_PINS_3 5
|
||||
|
||||
#define MX31_AUDMUX_PORT1_SSI0 0
|
||||
#define MX31_AUDMUX_PORT2_SSI1 1
|
||||
#define MX31_AUDMUX_PORT3_SSI_PINS_3 2
|
||||
#define MX31_AUDMUX_PORT4_SSI_PINS_4 3
|
||||
#define MX31_AUDMUX_PORT5_SSI_PINS_5 4
|
||||
#define MX31_AUDMUX_PORT6_SSI_PINS_6 5
|
||||
#define MX31_AUDMUX_PORT7_SSI_PINS_7 6
|
||||
|
||||
#define MX51_AUDMUX_PORT1_SSI0 0
|
||||
#define MX51_AUDMUX_PORT2_SSI1 1
|
||||
#define MX51_AUDMUX_PORT3 2
|
||||
#define MX51_AUDMUX_PORT4 3
|
||||
#define MX51_AUDMUX_PORT5 4
|
||||
#define MX51_AUDMUX_PORT6 5
|
||||
#define MX51_AUDMUX_PORT7 6
|
||||
|
||||
/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */
|
||||
#define IMX_AUDMUX_V1_PCR_INMMASK(x) ((x) & 0xff)
|
||||
#define IMX_AUDMUX_V1_PCR_INMEN (1 << 8)
|
||||
#define IMX_AUDMUX_V1_PCR_TXRXEN (1 << 10)
|
||||
#define IMX_AUDMUX_V1_PCR_SYN (1 << 12)
|
||||
#define IMX_AUDMUX_V1_PCR_RXDSEL(x) (((x) & 0x7) << 13)
|
||||
#define IMX_AUDMUX_V1_PCR_RFCSEL(x) (((x) & 0xf) << 20)
|
||||
#define IMX_AUDMUX_V1_PCR_RCLKDIR (1 << 24)
|
||||
#define IMX_AUDMUX_V1_PCR_RFSDIR (1 << 25)
|
||||
#define IMX_AUDMUX_V1_PCR_TFCSEL(x) (((x) & 0xf) << 26)
|
||||
#define IMX_AUDMUX_V1_PCR_TCLKDIR (1 << 30)
|
||||
#define IMX_AUDMUX_V1_PCR_TFSDIR (1 << 31)
|
||||
|
||||
/* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */
|
||||
#define IMX_AUDMUX_V2_PTCR_TFSDIR (1 << 31)
|
||||
#define IMX_AUDMUX_V2_PTCR_TFSEL(x) (((x) & 0xf) << 27)
|
||||
#define IMX_AUDMUX_V2_PTCR_TCLKDIR (1 << 26)
|
||||
#define IMX_AUDMUX_V2_PTCR_TCSEL(x) (((x) & 0xf) << 22)
|
||||
#define IMX_AUDMUX_V2_PTCR_RFSDIR (1 << 21)
|
||||
#define IMX_AUDMUX_V2_PTCR_RFSEL(x) (((x) & 0xf) << 17)
|
||||
#define IMX_AUDMUX_V2_PTCR_RCLKDIR (1 << 16)
|
||||
#define IMX_AUDMUX_V2_PTCR_RCSEL(x) (((x) & 0xf) << 12)
|
||||
#define IMX_AUDMUX_V2_PTCR_SYN (1 << 11)
|
||||
|
||||
#define IMX_AUDMUX_V2_PDCR_RXDSEL(x) (((x) & 0x7) << 13)
|
||||
#define IMX_AUDMUX_V2_PDCR_TXRXEN (1 << 12)
|
||||
#define IMX_AUDMUX_V2_PDCR_MODE(x) (((x) & 0x3) << 8)
|
||||
#define IMX_AUDMUX_V2_PDCR_INMMASK(x) ((x) & 0xff)
|
||||
|
||||
#endif /* __DT_FSL_IMX_AUDMUX_H */
|
|
@ -11,7 +11,7 @@ struct atmel_ssc_platform_data {
|
|||
|
||||
struct ssc_device {
|
||||
struct list_head list;
|
||||
resource_size_t phybase;
|
||||
dma_addr_t phybase;
|
||||
void __iomem *regs;
|
||||
struct platform_device *pdev;
|
||||
struct atmel_ssc_platform_data *pdata;
|
||||
|
|
96
include/linux/mfd/arizona/gpio.h
Normal file
96
include/linux/mfd/arizona/gpio.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* GPIO configuration for Arizona devices
|
||||
*
|
||||
* Copyright 2013 Wolfson Microelectronics. PLC.
|
||||
*
|
||||
* Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _ARIZONA_GPIO_H
|
||||
#define _ARIZONA_GPIO_H
|
||||
|
||||
#define ARIZONA_GP_FN_TXLRCLK 0x00
|
||||
#define ARIZONA_GP_FN_GPIO 0x01
|
||||
#define ARIZONA_GP_FN_IRQ1 0x02
|
||||
#define ARIZONA_GP_FN_IRQ2 0x03
|
||||
#define ARIZONA_GP_FN_OPCLK 0x04
|
||||
#define ARIZONA_GP_FN_FLL1_OUT 0x05
|
||||
#define ARIZONA_GP_FN_FLL2_OUT 0x06
|
||||
#define ARIZONA_GP_FN_PWM1 0x08
|
||||
#define ARIZONA_GP_FN_PWM2 0x09
|
||||
#define ARIZONA_GP_FN_SYSCLK_UNDERCLOCKED 0x0A
|
||||
#define ARIZONA_GP_FN_ASYNCCLK_UNDERCLOCKED 0x0B
|
||||
#define ARIZONA_GP_FN_FLL1_LOCK 0x0C
|
||||
#define ARIZONA_GP_FN_FLL2_LOCK 0x0D
|
||||
#define ARIZONA_GP_FN_FLL1_CLOCK_OK 0x0F
|
||||
#define ARIZONA_GP_FN_FLL2_CLOCK_OK 0x10
|
||||
#define ARIZONA_GP_FN_HEADPHONE_DET 0x12
|
||||
#define ARIZONA_GP_FN_MIC_DET 0x13
|
||||
#define ARIZONA_GP_FN_WSEQ_STATUS 0x15
|
||||
#define ARIZONA_GP_FN_CIF_ADDRESS_ERROR 0x16
|
||||
#define ARIZONA_GP_FN_ASRC1_LOCK 0x1A
|
||||
#define ARIZONA_GP_FN_ASRC2_LOCK 0x1B
|
||||
#define ARIZONA_GP_FN_ASRC_CONFIG_ERROR 0x1C
|
||||
#define ARIZONA_GP_FN_DRC1_SIGNAL_DETECT 0x1D
|
||||
#define ARIZONA_GP_FN_DRC1_ANTICLIP 0x1E
|
||||
#define ARIZONA_GP_FN_DRC1_DECAY 0x1F
|
||||
#define ARIZONA_GP_FN_DRC1_NOISE 0x20
|
||||
#define ARIZONA_GP_FN_DRC1_QUICK_RELEASE 0x21
|
||||
#define ARIZONA_GP_FN_DRC2_SIGNAL_DETECT 0x22
|
||||
#define ARIZONA_GP_FN_DRC2_ANTICLIP 0x23
|
||||
#define ARIZONA_GP_FN_DRC2_DECAY 0x24
|
||||
#define ARIZONA_GP_FN_DRC2_NOISE 0x25
|
||||
#define ARIZONA_GP_FN_DRC2_QUICK_RELEASE 0x26
|
||||
#define ARIZONA_GP_FN_MIXER_DROPPED_SAMPLE 0x27
|
||||
#define ARIZONA_GP_FN_AIF1_CONFIG_ERROR 0x28
|
||||
#define ARIZONA_GP_FN_AIF2_CONFIG_ERROR 0x29
|
||||
#define ARIZONA_GP_FN_AIF3_CONFIG_ERROR 0x2A
|
||||
#define ARIZONA_GP_FN_SPK_TEMP_SHUTDOWN 0x2B
|
||||
#define ARIZONA_GP_FN_SPK_TEMP_WARNING 0x2C
|
||||
#define ARIZONA_GP_FN_UNDERCLOCKED 0x2D
|
||||
#define ARIZONA_GP_FN_OVERCLOCKED 0x2E
|
||||
#define ARIZONA_GP_FN_DSP_IRQ1 0x35
|
||||
#define ARIZONA_GP_FN_DSP_IRQ2 0x36
|
||||
#define ARIZONA_GP_FN_ASYNC_OPCLK 0x3D
|
||||
#define ARIZONA_GP_FN_BOOT_DONE 0x44
|
||||
#define ARIZONA_GP_FN_DSP1_RAM_READY 0x45
|
||||
#define ARIZONA_GP_FN_SYSCLK_ENA_STATUS 0x4B
|
||||
#define ARIZONA_GP_FN_ASYNCCLK_ENA_STATUS 0x4C
|
||||
|
||||
#define ARIZONA_GPN_DIR 0x8000 /* GPN_DIR */
|
||||
#define ARIZONA_GPN_DIR_MASK 0x8000 /* GPN_DIR */
|
||||
#define ARIZONA_GPN_DIR_SHIFT 15 /* GPN_DIR */
|
||||
#define ARIZONA_GPN_DIR_WIDTH 1 /* GPN_DIR */
|
||||
#define ARIZONA_GPN_PU 0x4000 /* GPN_PU */
|
||||
#define ARIZONA_GPN_PU_MASK 0x4000 /* GPN_PU */
|
||||
#define ARIZONA_GPN_PU_SHIFT 14 /* GPN_PU */
|
||||
#define ARIZONA_GPN_PU_WIDTH 1 /* GPN_PU */
|
||||
#define ARIZONA_GPN_PD 0x2000 /* GPN_PD */
|
||||
#define ARIZONA_GPN_PD_MASK 0x2000 /* GPN_PD */
|
||||
#define ARIZONA_GPN_PD_SHIFT 13 /* GPN_PD */
|
||||
#define ARIZONA_GPN_PD_WIDTH 1 /* GPN_PD */
|
||||
#define ARIZONA_GPN_LVL 0x0800 /* GPN_LVL */
|
||||
#define ARIZONA_GPN_LVL_MASK 0x0800 /* GPN_LVL */
|
||||
#define ARIZONA_GPN_LVL_SHIFT 11 /* GPN_LVL */
|
||||
#define ARIZONA_GPN_LVL_WIDTH 1 /* GPN_LVL */
|
||||
#define ARIZONA_GPN_POL 0x0400 /* GPN_POL */
|
||||
#define ARIZONA_GPN_POL_MASK 0x0400 /* GPN_POL */
|
||||
#define ARIZONA_GPN_POL_SHIFT 10 /* GPN_POL */
|
||||
#define ARIZONA_GPN_POL_WIDTH 1 /* GPN_POL */
|
||||
#define ARIZONA_GPN_OP_CFG 0x0200 /* GPN_OP_CFG */
|
||||
#define ARIZONA_GPN_OP_CFG_MASK 0x0200 /* GPN_OP_CFG */
|
||||
#define ARIZONA_GPN_OP_CFG_SHIFT 9 /* GPN_OP_CFG */
|
||||
#define ARIZONA_GPN_OP_CFG_WIDTH 1 /* GPN_OP_CFG */
|
||||
#define ARIZONA_GPN_DB 0x0100 /* GPN_DB */
|
||||
#define ARIZONA_GPN_DB_MASK 0x0100 /* GPN_DB */
|
||||
#define ARIZONA_GPN_DB_SHIFT 8 /* GPN_DB */
|
||||
#define ARIZONA_GPN_DB_WIDTH 1 /* GPN_DB */
|
||||
#define ARIZONA_GPN_FN_MASK 0x007F /* GPN_DB */
|
||||
#define ARIZONA_GPN_FN_SHIFT 0 /* GPN_DB */
|
||||
#define ARIZONA_GPN_FN_WIDTH 7 /* GPN_DB */
|
||||
|
||||
#endif
|
|
@ -36,6 +36,7 @@ struct samsung_i2s {
|
|||
*/
|
||||
#define QUIRK_NO_MUXPSR (1 << 2)
|
||||
#define QUIRK_NEED_RSTCLR (1 << 3)
|
||||
#define QUIRK_SUPPORTS_TDM (1 << 4)
|
||||
/* Quirks of the I2S controller */
|
||||
u32 quirks;
|
||||
dma_addr_t idma_addr;
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
* omap-abe-twl6040.h - ASoC machine driver OMAP4+ devices, header.
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _OMAP_ABE_TWL6040_H_
|
||||
#define _OMAP_ABE_TWL6040_H_
|
||||
|
||||
/* To select if only one channel is connected in a stereo port */
|
||||
#define ABE_TWL6040_LEFT (1 << 0)
|
||||
#define ABE_TWL6040_RIGHT (1 << 1)
|
||||
|
||||
struct omap_abe_twl6040_data {
|
||||
char *card_name;
|
||||
/* Feature flags for connected audio pins */
|
||||
u8 has_hs;
|
||||
u8 has_hf;
|
||||
bool has_ep;
|
||||
u8 has_aux;
|
||||
u8 has_vibra;
|
||||
bool has_dmic;
|
||||
bool has_hsmic;
|
||||
bool has_mainmic;
|
||||
bool has_submic;
|
||||
u8 has_afm;
|
||||
/* Other features */
|
||||
bool jack_detection; /* board can detect jack events */
|
||||
int mclk_freq; /* MCLK frequency speed for twl6040 */
|
||||
};
|
||||
|
||||
#endif /* _OMAP_ABE_TWL6040_H_ */
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include <linux/list.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
|
||||
/*
|
||||
* SSP Serial Port Registers
|
||||
|
@ -190,6 +192,8 @@ struct ssp_device {
|
|||
int irq;
|
||||
int drcmr_rx;
|
||||
int drcmr_tx;
|
||||
|
||||
struct device_node *of_node;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -218,11 +222,18 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
|
|||
#ifdef CONFIG_ARCH_PXA
|
||||
struct ssp_device *pxa_ssp_request(int port, const char *label);
|
||||
void pxa_ssp_free(struct ssp_device *);
|
||||
struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
|
||||
const char *label);
|
||||
#else
|
||||
static inline struct ssp_device *pxa_ssp_request(int port, const char *label)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline struct ssp_device *pxa_ssp_request_of(const struct device_node *n,
|
||||
const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void pxa_ssp_free(struct ssp_device *ssp) {}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/rwsem.h> /* struct rw_semaphore */
|
||||
#include <linux/pm.h> /* pm_message_t */
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
/* number of supported soundcards */
|
||||
#ifdef CONFIG_SND_DYNAMIC_MINORS
|
||||
|
@ -375,6 +376,11 @@ void __snd_printk(unsigned int level, const char *file, int line,
|
|||
*/
|
||||
#define snd_BUG() WARN(1, "BUG?\n")
|
||||
|
||||
/**
|
||||
* Suppress high rates of output when CONFIG_SND_DEBUG is enabled.
|
||||
*/
|
||||
#define snd_printd_ratelimit() printk_ratelimit()
|
||||
|
||||
/**
|
||||
* snd_BUG_ON - debugging check macro
|
||||
* @cond: condition to evaluate
|
||||
|
@ -398,6 +404,8 @@ static inline void _snd_printd(int level, const char *format, ...) {}
|
|||
unlikely(__ret_warn_on); \
|
||||
})
|
||||
|
||||
static inline bool snd_printd_ratelimit(void) { return false; }
|
||||
|
||||
#endif /* CONFIG_SND_DEBUG */
|
||||
|
||||
#ifdef CONFIG_SND_DEBUG_VERBOSE
|
||||
|
|
|
@ -6,13 +6,6 @@
|
|||
|
||||
/* PCM */
|
||||
|
||||
struct pxa2xx_pcm_dma_params {
|
||||
char *name; /* stream identifier */
|
||||
u32 dcmd; /* DMA descriptor dcmd field */
|
||||
volatile u32 *drcmr; /* the DMA request channel to use */
|
||||
u32 dev_addr; /* device physical address for DMA */
|
||||
};
|
||||
|
||||
extern int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
|
||||
|
|
84
include/sound/rcar_snd.h
Normal file
84
include/sound/rcar_snd.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Renesas R-Car SRU/SCU/SSIU/SSI support
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef RCAR_SND_H
|
||||
#define RCAR_SND_H
|
||||
|
||||
#include <linux/sh_clk.h>
|
||||
|
||||
#define RSND_GEN1_SRU 0
|
||||
#define RSND_GEN1_ADG 1
|
||||
#define RSND_GEN1_SSI 2
|
||||
|
||||
#define RSND_GEN2_SRU 0
|
||||
#define RSND_GEN2_ADG 1
|
||||
#define RSND_GEN2_SSIU 2
|
||||
#define RSND_GEN2_SSI 3
|
||||
|
||||
#define RSND_BASE_MAX 4
|
||||
|
||||
/*
|
||||
* flags
|
||||
*
|
||||
* 0xAB000000
|
||||
*
|
||||
* A : clock sharing settings
|
||||
* B : SSI direction
|
||||
*/
|
||||
#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
|
||||
#define RSND_SSI_CLK_FROM_ADG (1 << 30) /* clock parent is master */
|
||||
#define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */
|
||||
#define RSND_SSI_DEPENDENT (1 << 28) /* SSI needs SRU/SCU */
|
||||
|
||||
#define RSND_SSI_PLAY (1 << 24)
|
||||
|
||||
#define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \
|
||||
{ .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
|
||||
#define RSND_SSI_UNUSED \
|
||||
{ .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 }
|
||||
|
||||
struct rsnd_ssi_platform_info {
|
||||
int dai_id;
|
||||
int dma_id;
|
||||
int pio_irq;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* flags
|
||||
*/
|
||||
#define RSND_SCU_USB_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */
|
||||
|
||||
struct rsnd_scu_platform_info {
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* flags
|
||||
*
|
||||
* 0x0000000A
|
||||
*
|
||||
* A : generation
|
||||
*/
|
||||
#define RSND_GEN1 (1 << 0) /* fixme */
|
||||
#define RSND_GEN2 (2 << 0) /* fixme */
|
||||
|
||||
struct rcar_snd_info {
|
||||
u32 flags;
|
||||
struct rsnd_ssi_platform_info *ssi_info;
|
||||
int ssi_info_nr;
|
||||
struct rsnd_scu_platform_info *scu_info;
|
||||
int scu_info_nr;
|
||||
int (*start)(int id);
|
||||
int (*stop)(int id);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -70,121 +70,144 @@ struct device;
|
|||
.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
|
||||
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
|
||||
|
||||
#define SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) \
|
||||
.reg = wreg, .mask = 1, .shift = wshift, \
|
||||
.on_val = winvert ? 0 : 1, .off_val = winvert ? 1 : 0
|
||||
|
||||
/* path domain */
|
||||
#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
|
||||
wcontrols, wncontrols) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
|
||||
#define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
|
||||
wcontrols, wncontrols) \
|
||||
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
|
||||
{ .id = snd_soc_dapm_out_drv, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
|
||||
#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
|
||||
wcontrols, wncontrols)\
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
|
||||
#define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
|
||||
wcontrols, wncontrols)\
|
||||
{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
|
||||
.num_kcontrols = wncontrols}
|
||||
{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
|
||||
#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0}
|
||||
{ .id = snd_soc_dapm_micbias, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = NULL, .num_kcontrols = 0}
|
||||
#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
|
||||
{ .id = snd_soc_dapm_switch, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = 1}
|
||||
#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = 1}
|
||||
#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
|
||||
{ .id = snd_soc_dapm_virt_mux, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = 1}
|
||||
#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
|
||||
.num_kcontrols = 1}
|
||||
{ .id = snd_soc_dapm_value_mux, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = 1}
|
||||
|
||||
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
|
||||
#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
|
||||
wcontrols) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
|
||||
#define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
|
||||
wcontrols)\
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
|
||||
#define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
|
||||
wcontrols)\
|
||||
{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
|
||||
.num_kcontrols = ARRAY_SIZE(wcontrols)}
|
||||
{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
|
||||
|
||||
/* path domain with event - event handler must return 0 for success */
|
||||
#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wncontrols, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wncontrols, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
|
||||
{ .id = snd_soc_dapm_out_drv, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wncontrols, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
|
||||
wcontrols, wncontrols, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, \
|
||||
.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
|
||||
{ .id = snd_soc_dapm_switch, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = 1, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = 1, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
|
||||
{ .id = snd_soc_dapm_virt_mux, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = 1, \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
|
||||
/* additional sequencing control within an event type */
|
||||
#define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .event = wevent, .event_flags = wflags, \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.event = wevent, .event_flags = wflags, \
|
||||
.subseq = wsubseq}
|
||||
#define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
|
||||
wflags) \
|
||||
{ .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, .event = wevent, \
|
||||
.event_flags = wflags, .subseq = wsubseq}
|
||||
{ .id = snd_soc_dapm_supply, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.event = wevent, .event_flags = wflags, .subseq = wsubseq}
|
||||
|
||||
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
|
||||
#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
|
||||
wcontrols, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrol_news = wcontrols, \
|
||||
.num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
|
||||
/* events that are pre and post DAPM */
|
||||
#define SND_SOC_DAPM_PRE(wname, wevent) \
|
||||
|
@ -199,35 +222,36 @@ struct device;
|
|||
/* stream domain */
|
||||
#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
|
||||
.reg = wreg, .shift = wshift, .invert = winvert }
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
|
||||
#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
|
||||
.reg = wreg, .shift = wshift, .invert = winvert, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.event = wevent, .event_flags = wflags }
|
||||
#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
|
||||
.reg = wreg, .shift = wshift, .invert = winvert }
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
|
||||
#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
|
||||
.reg = wreg, .shift = wshift, .invert = winvert, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.event = wevent, .event_flags = wflags }
|
||||
#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert}
|
||||
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
|
||||
#define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, \
|
||||
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
|
||||
#define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
|
||||
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert}
|
||||
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
|
||||
#define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
|
||||
wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, \
|
||||
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
|
||||
{ .id = snd_soc_dapm_clock_supply, .name = wname, \
|
||||
|
@ -241,14 +265,14 @@ struct device;
|
|||
.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
|
||||
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
|
||||
#define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, .event = wevent, \
|
||||
.event_flags = wflags}
|
||||
{ .id = snd_soc_dapm_supply, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.event = wevent, .event_flags = wflags}
|
||||
#define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags) \
|
||||
{ .id = snd_soc_dapm_regulator_supply, .name = wname, \
|
||||
.reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
|
||||
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
|
||||
.invert = wflags}
|
||||
.on_val = wflags}
|
||||
|
||||
|
||||
/* dapm kcontrol types */
|
||||
|
@ -256,14 +280,26 @@ struct device;
|
|||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
|
||||
#define SOC_DAPM_SINGLE_AUTODISABLE(xname, reg, shift, max, invert) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
|
||||
#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
|
||||
.tlv.p = (tlv_array), \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
|
||||
#define SOC_DAPM_SINGLE_TLV_AUTODISABLE(xname, reg, shift, max, invert, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
|
||||
.tlv.p = (tlv_array), \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
|
||||
#define SOC_DAPM_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
|
@ -333,6 +369,7 @@ struct snd_soc_dapm_route;
|
|||
struct snd_soc_dapm_context;
|
||||
struct regulator;
|
||||
struct snd_soc_dapm_widget_list;
|
||||
struct snd_soc_dapm_update;
|
||||
|
||||
int dapm_reg_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event);
|
||||
|
@ -376,7 +413,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
|
|||
struct snd_soc_dapm_widget *sink);
|
||||
|
||||
/* dapm path setup */
|
||||
int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
|
||||
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
|
||||
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
|
||||
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
|
||||
const struct snd_soc_dapm_route *route, int num);
|
||||
|
@ -391,10 +428,12 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
|
|||
void snd_soc_dapm_shutdown(struct snd_soc_card *card);
|
||||
|
||||
/* external DAPM widget events */
|
||||
int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
|
||||
struct snd_kcontrol *kcontrol, int connect);
|
||||
int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
|
||||
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e);
|
||||
int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
|
||||
struct snd_kcontrol *kcontrol, int connect,
|
||||
struct snd_soc_dapm_update *update);
|
||||
int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
|
||||
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
|
||||
struct snd_soc_dapm_update *update);
|
||||
|
||||
/* dapm sys fs - used by the core */
|
||||
int snd_soc_dapm_sys_add(struct device *dev);
|
||||
|
@ -424,6 +463,8 @@ void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
|
|||
int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
|
||||
struct snd_soc_dapm_widget_list **list);
|
||||
|
||||
struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol);
|
||||
|
||||
/* dapm widget types */
|
||||
enum snd_soc_dapm_type {
|
||||
snd_soc_dapm_input = 0, /* input pin */
|
||||
|
@ -455,6 +496,7 @@ enum snd_soc_dapm_type {
|
|||
snd_soc_dapm_dai_in, /* link to DAI structure */
|
||||
snd_soc_dapm_dai_out,
|
||||
snd_soc_dapm_dai_link, /* link between two DAI structures */
|
||||
snd_soc_dapm_kcontrol, /* Auto-disabled kcontrol */
|
||||
};
|
||||
|
||||
enum snd_soc_dapm_subclass {
|
||||
|
@ -485,7 +527,6 @@ struct snd_soc_dapm_path {
|
|||
/* source (input) and sink (output) widgets */
|
||||
struct snd_soc_dapm_widget *source;
|
||||
struct snd_soc_dapm_widget *sink;
|
||||
struct snd_kcontrol *kcontrol;
|
||||
|
||||
/* status */
|
||||
u32 connect:1; /* source and sink widgets are connected */
|
||||
|
@ -498,6 +539,7 @@ struct snd_soc_dapm_path {
|
|||
|
||||
struct list_head list_source;
|
||||
struct list_head list_sink;
|
||||
struct list_head list_kcontrol;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
@ -518,12 +560,10 @@ struct snd_soc_dapm_widget {
|
|||
/* dapm control */
|
||||
int reg; /* negative reg = no direct dapm */
|
||||
unsigned char shift; /* bits to shift */
|
||||
unsigned int value; /* widget current value */
|
||||
unsigned int mask; /* non-shifted mask */
|
||||
unsigned int on_val; /* on state value */
|
||||
unsigned int off_val; /* off state value */
|
||||
unsigned char power:1; /* block power status */
|
||||
unsigned char invert:1; /* invert the power bit */
|
||||
unsigned char active:1; /* active stream on DAC, ADC's */
|
||||
unsigned char connected:1; /* connected codec pin */
|
||||
unsigned char new:1; /* cnew complete */
|
||||
|
@ -559,7 +599,6 @@ struct snd_soc_dapm_widget {
|
|||
};
|
||||
|
||||
struct snd_soc_dapm_update {
|
||||
struct snd_soc_dapm_widget *widget;
|
||||
struct snd_kcontrol *kcontrol;
|
||||
int reg;
|
||||
int mask;
|
||||
|
@ -573,8 +612,6 @@ struct snd_soc_dapm_context {
|
|||
struct delayed_work delayed_work;
|
||||
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
|
||||
|
||||
struct snd_soc_dapm_update *update;
|
||||
|
||||
void (*seq_notifier)(struct snd_soc_dapm_context *,
|
||||
enum snd_soc_dapm_type, int);
|
||||
|
||||
|
|
|
@ -133,6 +133,6 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
|
|||
/* internal use only */
|
||||
int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
|
||||
int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
|
||||
int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *);
|
||||
int soc_dpcm_runtime_update(struct snd_soc_card *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,13 +30,13 @@
|
|||
/*
|
||||
* Convenience kcontrol builders
|
||||
*/
|
||||
#define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert) \
|
||||
#define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert, xautodisable) \
|
||||
((unsigned long)&(struct soc_mixer_control) \
|
||||
{.reg = xreg, .rreg = xreg, .shift = shift_left, \
|
||||
.rshift = shift_right, .max = xmax, .platform_max = xmax, \
|
||||
.invert = xinvert})
|
||||
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
|
||||
SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert)
|
||||
.invert = xinvert, .autodisable = xautodisable})
|
||||
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
|
||||
SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
|
||||
#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
|
||||
((unsigned long)&(struct soc_mixer_control) \
|
||||
{.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert})
|
||||
|
@ -52,7 +52,7 @@
|
|||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
|
||||
.put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
|
||||
#define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
|
||||
.info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
|
||||
|
@ -68,7 +68,7 @@
|
|||
.tlv.p = (tlv_array), \
|
||||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
|
||||
.put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
|
||||
#define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
|
||||
|
@ -97,7 +97,7 @@
|
|||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
|
||||
.put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
|
||||
max, invert) }
|
||||
max, invert, 0) }
|
||||
#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
.info = snd_soc_info_volsw, \
|
||||
|
@ -119,7 +119,7 @@
|
|||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
|
||||
.put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
|
||||
max, invert) }
|
||||
max, invert, 0) }
|
||||
#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
|
||||
|
@ -190,14 +190,14 @@
|
|||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
|
||||
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
|
||||
#define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\
|
||||
xhandler_get, xhandler_put) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = \
|
||||
SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) }
|
||||
SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert, 0) }
|
||||
#define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
|
||||
xhandler_get, xhandler_put, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
|
@ -206,7 +206,7 @@
|
|||
.tlv.p = (tlv_array), \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
|
||||
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
|
||||
#define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\
|
||||
xhandler_get, xhandler_put, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
|
@ -216,7 +216,7 @@
|
|||
.info = snd_soc_info_volsw, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \
|
||||
xmax, xinvert) }
|
||||
xmax, xinvert, 0) }
|
||||
#define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\
|
||||
xhandler_get, xhandler_put, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
|
@ -234,7 +234,7 @@
|
|||
.private_value = xdata }
|
||||
#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_ext, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
|
||||
|
@ -468,6 +468,8 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
|
|||
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
*Controls
|
||||
|
@ -475,6 +477,8 @@ int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
|
|||
struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
|
||||
void *data, const char *long_name,
|
||||
const char *prefix);
|
||||
struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
|
||||
const char *name);
|
||||
int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
|
||||
const struct snd_kcontrol_new *controls, int num_controls);
|
||||
int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
|
||||
|
@ -485,8 +489,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
|
|||
const struct snd_kcontrol_new *controls, int num_controls);
|
||||
int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
|
||||
|
@ -497,8 +499,6 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
#define snd_soc_info_bool_ext snd_ctl_boolean_mono_info
|
||||
int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
@ -697,7 +697,6 @@ struct snd_soc_codec {
|
|||
unsigned int probed:1; /* Codec has been probed */
|
||||
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
|
||||
unsigned int ac97_created:1; /* Codec has been created by SoC */
|
||||
unsigned int sysfs_registered:1; /* codec has been sysfs registered */
|
||||
unsigned int cache_init:1; /* codec cache has been initialized */
|
||||
unsigned int using_regmap:1; /* using regmap access */
|
||||
u32 cache_only; /* Suppress writes to hardware */
|
||||
|
@ -705,7 +704,6 @@ struct snd_soc_codec {
|
|||
|
||||
/* codec IO */
|
||||
void *control_data; /* codec control (i2c/3wire) data */
|
||||
enum snd_soc_control_type control_type;
|
||||
hw_write_t hw_write;
|
||||
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
|
||||
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
|
||||
|
@ -724,7 +722,6 @@ struct snd_soc_codec {
|
|||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_codec_root;
|
||||
struct dentry *debugfs_reg;
|
||||
struct dentry *debugfs_dapm;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -849,7 +846,6 @@ struct snd_soc_platform {
|
|||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_platform_root;
|
||||
struct dentry *debugfs_dapm;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -934,6 +930,10 @@ struct snd_soc_dai_link {
|
|||
/* machine stream operations */
|
||||
const struct snd_soc_ops *ops;
|
||||
const struct snd_soc_compr_ops *compr_ops;
|
||||
|
||||
/* For unidirectional dai links */
|
||||
bool playback_only;
|
||||
bool capture_only;
|
||||
};
|
||||
|
||||
struct snd_soc_codec_conf {
|
||||
|
@ -1042,6 +1042,7 @@ struct snd_soc_card {
|
|||
/* Generic DAPM context for the card */
|
||||
struct snd_soc_dapm_context dapm;
|
||||
struct snd_soc_dapm_stats dapm_stats;
|
||||
struct snd_soc_dapm_update *update;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_card_root;
|
||||
|
@ -1087,7 +1088,9 @@ struct snd_soc_pcm_runtime {
|
|||
/* mixer control */
|
||||
struct soc_mixer_control {
|
||||
int min, max, platform_max;
|
||||
unsigned int reg, rreg, shift, rshift, invert;
|
||||
unsigned int reg, rreg, shift, rshift;
|
||||
unsigned int invert:1;
|
||||
unsigned int autodisable:1;
|
||||
};
|
||||
|
||||
struct soc_bytes {
|
||||
|
|
|
@ -111,7 +111,7 @@ struct hdspm_ltc {
|
|||
enum hdspm_ltc_input_format input_format;
|
||||
};
|
||||
|
||||
#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_mixer_ioctl)
|
||||
#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_ltc)
|
||||
|
||||
/**
|
||||
* The status data reflects the device's current state
|
||||
|
|
|
@ -14,12 +14,14 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/pxa2xx-lib.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include <mach/regs-ac97.h>
|
||||
#include <mach/audio.h>
|
||||
|
@ -41,20 +43,20 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
|
|||
.reset = pxa2xx_ac97_reset,
|
||||
};
|
||||
|
||||
static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_out = {
|
||||
.name = "AC97 PCM out",
|
||||
.dev_addr = __PREG(PCDR),
|
||||
.drcmr = &DRCMR(12),
|
||||
.dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
|
||||
DCMD_BURST32 | DCMD_WIDTH4,
|
||||
static unsigned long pxa2xx_ac97_pcm_out_req = 12;
|
||||
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
|
||||
.addr = __PREG(PCDR),
|
||||
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
.maxburst = 32,
|
||||
.filter_data = &pxa2xx_ac97_pcm_out_req,
|
||||
};
|
||||
|
||||
static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_in = {
|
||||
.name = "AC97 PCM in",
|
||||
.dev_addr = __PREG(PCDR),
|
||||
.drcmr = &DRCMR(11),
|
||||
.dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
|
||||
DCMD_BURST32 | DCMD_WIDTH4,
|
||||
static unsigned long pxa2xx_ac97_pcm_in_req = 11;
|
||||
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
|
||||
.addr = __PREG(PCDR),
|
||||
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
.maxburst = 32,
|
||||
.filter_data = &pxa2xx_ac97_pcm_in_req,
|
||||
};
|
||||
|
||||
static struct snd_pcm *pxa2xx_ac97_pcm;
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/pxa2xx-lib.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
|
||||
|
@ -43,6 +45,35 @@ int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
size_t period = params_period_bytes(params);
|
||||
pxa_dma_desc *dma_desc;
|
||||
dma_addr_t dma_buff_phys, next_desc_phys;
|
||||
u32 dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
|
||||
|
||||
/* temporary transition hack */
|
||||
switch (rtd->params->addr_width) {
|
||||
case DMA_SLAVE_BUSWIDTH_1_BYTE:
|
||||
dcmd |= DCMD_WIDTH1;
|
||||
break;
|
||||
case DMA_SLAVE_BUSWIDTH_2_BYTES:
|
||||
dcmd |= DCMD_WIDTH2;
|
||||
break;
|
||||
case DMA_SLAVE_BUSWIDTH_4_BYTES:
|
||||
dcmd |= DCMD_WIDTH4;
|
||||
break;
|
||||
default:
|
||||
/* can't happen */
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rtd->params->maxburst) {
|
||||
case 8:
|
||||
dcmd |= DCMD_BURST8;
|
||||
break;
|
||||
case 16:
|
||||
dcmd |= DCMD_BURST16;
|
||||
break;
|
||||
case 32:
|
||||
dcmd |= DCMD_BURST32;
|
||||
break;
|
||||
}
|
||||
|
||||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
||||
runtime->dma_bytes = totsize;
|
||||
|
@ -55,14 +86,14 @@ int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
dma_desc->ddadr = next_desc_phys;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
dma_desc->dsadr = dma_buff_phys;
|
||||
dma_desc->dtadr = rtd->params->dev_addr;
|
||||
dma_desc->dtadr = rtd->params->addr;
|
||||
} else {
|
||||
dma_desc->dsadr = rtd->params->dev_addr;
|
||||
dma_desc->dsadr = rtd->params->addr;
|
||||
dma_desc->dtadr = dma_buff_phys;
|
||||
}
|
||||
if (period > totsize)
|
||||
period = totsize;
|
||||
dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN;
|
||||
dma_desc->dcmd = dcmd | period | DCMD_ENDIRQEN;
|
||||
dma_desc++;
|
||||
dma_buff_phys += period;
|
||||
} while (totsize -= period);
|
||||
|
@ -76,8 +107,10 @@ int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||
{
|
||||
struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
|
||||
|
||||
if (rtd && rtd->params && rtd->params->drcmr)
|
||||
*rtd->params->drcmr = 0;
|
||||
if (rtd && rtd->params && rtd->params->filter_data) {
|
||||
unsigned long req = *(unsigned long *) rtd->params->filter_data;
|
||||
DRCMR(req) = 0;
|
||||
}
|
||||
|
||||
snd_pcm_set_runtime_buffer(substream, NULL);
|
||||
return 0;
|
||||
|
@ -136,6 +169,7 @@ EXPORT_SYMBOL(pxa2xx_pcm_pointer);
|
|||
int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
|
||||
unsigned long req;
|
||||
|
||||
if (!prtd || !prtd->params)
|
||||
return 0;
|
||||
|
@ -146,7 +180,8 @@ int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
DCSR(prtd->dma_ch) &= ~DCSR_RUN;
|
||||
DCSR(prtd->dma_ch) = 0;
|
||||
DCMD(prtd->dma_ch) = 0;
|
||||
*prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
|
||||
req = *(unsigned long *) prtd->params->filter_data;
|
||||
DRCMR(req) = prtd->dma_ch | DRCMR_MAPVLD;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -155,7 +190,6 @@ EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
|
|||
void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
|
||||
{
|
||||
struct snd_pcm_substream *substream = dev_id;
|
||||
struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
|
||||
int dcsr;
|
||||
|
||||
dcsr = DCSR(dma_ch);
|
||||
|
@ -164,8 +198,8 @@ void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
|
|||
if (dcsr & DCSR_ENDINTR) {
|
||||
snd_pcm_period_elapsed(substream);
|
||||
} else {
|
||||
printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
|
||||
rtd->params->name, dma_ch, dcsr);
|
||||
printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
|
||||
dma_ch, dcsr);
|
||||
snd_pcm_stream_lock(substream);
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
|
||||
snd_pcm_stream_unlock(substream);
|
||||
|
|
|
@ -11,8 +11,11 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pxa2xx-lib.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include "pxa2xx-pcm.h"
|
||||
|
||||
|
@ -40,7 +43,7 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
|
|||
|
||||
rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
client->playback_params : client->capture_params;
|
||||
ret = pxa_request_dma(rtd->params->name, DMA_PRIO_LOW,
|
||||
ret = pxa_request_dma("dma", DMA_PRIO_LOW,
|
||||
pxa2xx_pcm_dma_irq, substream);
|
||||
if (ret < 0)
|
||||
goto err2;
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
|
||||
struct pxa2xx_runtime_data {
|
||||
int dma_ch;
|
||||
struct pxa2xx_pcm_dma_params *params;
|
||||
struct snd_dmaengine_dai_dma_data *params;
|
||||
pxa_dma_desc *dma_desc_array;
|
||||
dma_addr_t dma_desc_array_phys;
|
||||
};
|
||||
|
||||
struct pxa2xx_pcm_client {
|
||||
struct pxa2xx_pcm_dma_params *playback_params;
|
||||
struct pxa2xx_pcm_dma_params *capture_params;
|
||||
struct snd_dmaengine_dai_dma_data *playback_params;
|
||||
struct snd_dmaengine_dai_dma_data *capture_params;
|
||||
int (*startup)(struct snd_pcm_substream *);
|
||||
void (*shutdown)(struct snd_pcm_substream *);
|
||||
int (*prepare)(struct snd_pcm_substream *);
|
||||
|
|
|
@ -6,6 +6,9 @@ config SND_PCM
|
|||
tristate
|
||||
select SND_TIMER
|
||||
|
||||
config SND_DMAENGINE_PCM
|
||||
tristate
|
||||
|
||||
config SND_HWDEP
|
||||
tristate
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ snd-$(CONFIG_SND_JACK) += jack.o
|
|||
snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
|
||||
pcm_memory.o
|
||||
|
||||
snd-pcm-dmaengine-objs := pcm_dmaengine.o
|
||||
|
||||
snd-page-alloc-y := memalloc.o
|
||||
snd-page-alloc-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
|
||||
|
||||
|
@ -30,6 +32,7 @@ obj-$(CONFIG_SND_TIMER) += snd-timer.o
|
|||
obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o
|
||||
obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o
|
||||
obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o
|
||||
obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o
|
||||
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
|
||||
|
||||
obj-$(CONFIG_SND_OSSEMUL) += oss/
|
||||
|
|
|
@ -184,7 +184,7 @@ static void xrun(struct snd_pcm_substream *substream)
|
|||
do { \
|
||||
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
|
||||
xrun_log_show(substream); \
|
||||
if (printk_ratelimit()) { \
|
||||
if (snd_printd_ratelimit()) { \
|
||||
snd_printd("PCM: " fmt, ##args); \
|
||||
} \
|
||||
dump_stack_on_xrun(substream); \
|
||||
|
@ -342,7 +342,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
|||
return -EPIPE;
|
||||
}
|
||||
if (pos >= runtime->buffer_size) {
|
||||
if (printk_ratelimit()) {
|
||||
if (snd_printd_ratelimit()) {
|
||||
char name[16];
|
||||
snd_pcm_debug_name(substream, name, sizeof(name));
|
||||
xrun_log_show(substream);
|
||||
|
|
|
@ -1022,7 +1022,7 @@ static void dummy_proc_write(struct snd_info_entry *entry,
|
|||
if (i >= ARRAY_SIZE(fields))
|
||||
continue;
|
||||
snd_info_get_str(item, ptr, sizeof(item));
|
||||
if (strict_strtoull(item, 0, &val))
|
||||
if (kstrtoull(item, 0, &val))
|
||||
continue;
|
||||
if (fields[i].size == sizeof(int))
|
||||
*get_dummy_int_ptr(dummy, fields[i].offset) = val;
|
||||
|
|
|
@ -49,7 +49,6 @@ struct fwspk {
|
|||
struct snd_card *card;
|
||||
struct fw_unit *unit;
|
||||
const struct device_info *device_info;
|
||||
struct snd_pcm_substream *pcm;
|
||||
struct mutex mutex;
|
||||
struct cmp_connection connection;
|
||||
struct amdtp_out_stream stream;
|
||||
|
@ -363,8 +362,7 @@ static int fwspk_create_pcm(struct fwspk *fwspk)
|
|||
return err;
|
||||
pcm->private_data = fwspk;
|
||||
strcpy(pcm->name, fwspk->device_info->short_name);
|
||||
fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
|
||||
fwspk->pcm->ops = &ops;
|
||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -443,8 +443,7 @@ static void snd_interwave_detect_memory(struct snd_gus_card *gus)
|
|||
for (i = 0; i < 8; ++i)
|
||||
iwave[i] = snd_gf1_peek(gus, bank_pos + i);
|
||||
#ifdef CONFIG_SND_DEBUG_ROM
|
||||
printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos,
|
||||
8, iwave);
|
||||
printk(KERN_DEBUG "ROM at 0x%06x = %8phC\n", bank_pos, iwave);
|
||||
#endif
|
||||
if (strncmp(iwave, "INTRWAVE", 8))
|
||||
continue; /* first check */
|
||||
|
|
|
@ -557,7 +557,6 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
|
|||
unsigned long flags;
|
||||
int err = 0, n = 0;
|
||||
struct dma_buffparms *dmap = adev->dmap_in;
|
||||
int go;
|
||||
|
||||
if (!(adev->open_mode & OPEN_READ))
|
||||
return -EIO;
|
||||
|
@ -584,7 +583,7 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
|
|||
spin_unlock_irqrestore(&dmap->lock,flags);
|
||||
return -EAGAIN;
|
||||
}
|
||||
if ((go = adev->go))
|
||||
if (adev->go)
|
||||
timeout = dmabuf_timeout(dmap);
|
||||
|
||||
spin_unlock_irqrestore(&dmap->lock,flags);
|
||||
|
|
|
@ -152,14 +152,9 @@ config SND_HDA_CODEC_HDMI
|
|||
This module is automatically loaded at probing.
|
||||
|
||||
config SND_HDA_I915
|
||||
bool "Build Display HD-audio controller/codec power well support for i915 cards"
|
||||
bool
|
||||
default y
|
||||
depends on DRM_I915
|
||||
help
|
||||
Say Y here to include full HDMI and DisplayPort HD-audio controller/codec
|
||||
power-well support for Intel Haswell graphics cards based on the i915 driver.
|
||||
|
||||
Note that this option must be enabled for Intel Haswell C+ stepping machines, otherwise
|
||||
the GPU audio controller/codecs will not be initialized or damaged when exit from S3 mode.
|
||||
|
||||
config SND_HDA_CODEC_CIRRUS
|
||||
bool "Build Cirrus Logic codec support"
|
||||
|
|
|
@ -666,6 +666,64 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
|
|||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_get_conn_index);
|
||||
|
||||
|
||||
/* return DEVLIST_LEN parameter of the given widget */
|
||||
static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
unsigned int wcaps = get_wcaps(codec, nid);
|
||||
unsigned int parm;
|
||||
|
||||
if (!codec->dp_mst || !(wcaps & AC_WCAP_DIGITAL) ||
|
||||
get_wcaps_type(wcaps) != AC_WID_PIN)
|
||||
return 0;
|
||||
|
||||
parm = snd_hda_param_read(codec, nid, AC_PAR_DEVLIST_LEN);
|
||||
if (parm == -1 && codec->bus->rirb_error)
|
||||
parm = 0;
|
||||
return parm & AC_DEV_LIST_LEN_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_get_devices - copy device list without cache
|
||||
* @codec: the HDA codec
|
||||
* @nid: NID of the pin to parse
|
||||
* @dev_list: device list array
|
||||
* @max_devices: max. number of devices to store
|
||||
*
|
||||
* Copy the device list. This info is dynamic and so not cached.
|
||||
* Currently called only from hda_proc.c, so not exported.
|
||||
*/
|
||||
int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
|
||||
u8 *dev_list, int max_devices)
|
||||
{
|
||||
unsigned int parm;
|
||||
int i, dev_len, devices;
|
||||
|
||||
parm = get_num_devices(codec, nid);
|
||||
if (!parm) /* not multi-stream capable */
|
||||
return 0;
|
||||
|
||||
dev_len = parm + 1;
|
||||
dev_len = dev_len < max_devices ? dev_len : max_devices;
|
||||
|
||||
devices = 0;
|
||||
while (devices < dev_len) {
|
||||
parm = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_DEVICE_LIST, devices);
|
||||
if (parm == -1 && codec->bus->rirb_error)
|
||||
break;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
dev_list[devices] = (u8)parm;
|
||||
parm >>= 4;
|
||||
devices++;
|
||||
if (devices >= dev_len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hda_queue_unsol_event - add an unsolicited event to queue
|
||||
* @bus: the BUS
|
||||
|
@ -1216,11 +1274,13 @@ static void hda_jackpoll_work(struct work_struct *work)
|
|||
{
|
||||
struct hda_codec *codec =
|
||||
container_of(work, struct hda_codec, jackpoll_work.work);
|
||||
if (!codec->jackpoll_interval)
|
||||
return;
|
||||
|
||||
snd_hda_jack_set_dirty_all(codec);
|
||||
snd_hda_jack_poll_all(codec);
|
||||
|
||||
if (!codec->jackpoll_interval)
|
||||
return;
|
||||
|
||||
queue_delayed_work(codec->bus->workq, &codec->jackpoll_work,
|
||||
codec->jackpoll_interval);
|
||||
}
|
||||
|
|
|
@ -94,6 +94,8 @@ enum {
|
|||
#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32
|
||||
#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33
|
||||
#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34
|
||||
#define AC_VERB_GET_DEVICE_SEL 0xf35
|
||||
#define AC_VERB_GET_DEVICE_LIST 0xf36
|
||||
|
||||
/*
|
||||
* SET verbs
|
||||
|
@ -133,6 +135,7 @@ enum {
|
|||
#define AC_VERB_SET_HDMI_DIP_XMIT 0x732
|
||||
#define AC_VERB_SET_HDMI_CP_CTRL 0x733
|
||||
#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734
|
||||
#define AC_VERB_SET_DEVICE_SEL 0x735
|
||||
|
||||
/*
|
||||
* Parameter IDs
|
||||
|
@ -154,6 +157,7 @@ enum {
|
|||
#define AC_PAR_GPIO_CAP 0x11
|
||||
#define AC_PAR_AMP_OUT_CAP 0x12
|
||||
#define AC_PAR_VOL_KNB_CAP 0x13
|
||||
#define AC_PAR_DEVLIST_LEN 0x15
|
||||
#define AC_PAR_HDMI_LPCM_CAP 0x20
|
||||
|
||||
/*
|
||||
|
@ -251,6 +255,11 @@ enum {
|
|||
#define AC_UNSOL_RES_TAG_SHIFT 26
|
||||
#define AC_UNSOL_RES_SUBTAG (0x1f<<21)
|
||||
#define AC_UNSOL_RES_SUBTAG_SHIFT 21
|
||||
#define AC_UNSOL_RES_DE (0x3f<<15) /* Device Entry
|
||||
* (for DP1.2 MST)
|
||||
*/
|
||||
#define AC_UNSOL_RES_DE_SHIFT 15
|
||||
#define AC_UNSOL_RES_IA (1<<2) /* Inactive (for DP1.2 MST) */
|
||||
#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */
|
||||
#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */
|
||||
#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */
|
||||
|
@ -352,6 +361,10 @@ enum {
|
|||
#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */
|
||||
#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */
|
||||
|
||||
/* Display pin's device list length */
|
||||
#define AC_DEV_LIST_LEN_MASK 0x3f
|
||||
#define AC_MAX_DEV_LIST_LEN 64
|
||||
|
||||
/*
|
||||
* Control Parameters
|
||||
*/
|
||||
|
@ -460,6 +473,11 @@ enum {
|
|||
#define AC_DEFCFG_PORT_CONN (0x3<<30)
|
||||
#define AC_DEFCFG_PORT_CONN_SHIFT 30
|
||||
|
||||
/* Display pin's device list entry */
|
||||
#define AC_DE_PD (1<<0)
|
||||
#define AC_DE_ELDV (1<<1)
|
||||
#define AC_DE_IA (1<<2)
|
||||
|
||||
/* device device types (0x0-0xf) */
|
||||
enum {
|
||||
AC_JACK_LINE_OUT,
|
||||
|
@ -885,6 +903,7 @@ struct hda_codec {
|
|||
unsigned int pcm_format_first:1; /* PCM format must be set first */
|
||||
unsigned int epss:1; /* supporting EPSS? */
|
||||
unsigned int cached_write:1; /* write only to caches */
|
||||
unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
|
||||
#ifdef CONFIG_PM
|
||||
unsigned int power_on :1; /* current (global) power-state */
|
||||
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
|
||||
|
@ -972,6 +991,8 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
|
|||
const hda_nid_t *list);
|
||||
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
|
||||
hda_nid_t nid, int recursive);
|
||||
int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
|
||||
u8 *dev_list, int max_devices);
|
||||
int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
|
||||
u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
|
||||
|
||||
|
|
|
@ -142,6 +142,9 @@ static void parse_user_hints(struct hda_codec *codec)
|
|||
val = snd_hda_get_bool_hint(codec, "primary_hp");
|
||||
if (val >= 0)
|
||||
spec->no_primary_hp = !val;
|
||||
val = snd_hda_get_bool_hint(codec, "multi_io");
|
||||
if (val >= 0)
|
||||
spec->no_multi_io = !val;
|
||||
val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
|
||||
if (val >= 0)
|
||||
spec->multi_cap_vol = !!val;
|
||||
|
@ -813,6 +816,8 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
|
|||
|
||||
static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
enum {
|
||||
HDA_CTL_WIDGET_VOL,
|
||||
|
@ -830,7 +835,13 @@ static const struct snd_kcontrol_new control_templates[] = {
|
|||
.put = hda_gen_mixer_mute_put, /* replaced */
|
||||
.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
|
||||
},
|
||||
HDA_BIND_MUTE(NULL, 0, 0, 0),
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.info = snd_hda_mixer_amp_switch_info,
|
||||
.get = snd_hda_mixer_bind_switch_get,
|
||||
.put = hda_gen_bind_mute_put, /* replaced */
|
||||
.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
|
||||
},
|
||||
};
|
||||
|
||||
/* add dynamic controls from template */
|
||||
|
@ -937,8 +948,8 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
|
|||
}
|
||||
|
||||
/* playback mute control with the software mute bit check */
|
||||
static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
|
@ -949,10 +960,22 @@ static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
|
|||
ucontrol->value.integer.value[0] &= enabled;
|
||||
ucontrol->value.integer.value[1] &= enabled;
|
||||
}
|
||||
}
|
||||
|
||||
static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
sync_auto_mute_bits(kcontrol, ucontrol);
|
||||
return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
|
||||
}
|
||||
|
||||
static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
sync_auto_mute_bits(kcontrol, ucontrol);
|
||||
return snd_hda_mixer_bind_switch_put(kcontrol, ucontrol);
|
||||
}
|
||||
|
||||
/* any ctl assigned to the path with the given index? */
|
||||
static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
|
||||
{
|
||||
|
@ -1541,7 +1564,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
|
|||
cfg->speaker_pins,
|
||||
spec->multiout.extra_out_nid,
|
||||
spec->speaker_paths);
|
||||
if (fill_mio_first && cfg->line_outs == 1 &&
|
||||
if (!spec->no_multi_io &&
|
||||
fill_mio_first && cfg->line_outs == 1 &&
|
||||
cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||
err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
|
||||
if (!err)
|
||||
|
@ -1554,7 +1578,7 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
|
|||
spec->private_dac_nids, spec->out_paths,
|
||||
spec->main_out_badness);
|
||||
|
||||
if (fill_mio_first &&
|
||||
if (!spec->no_multi_io && fill_mio_first &&
|
||||
cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||
/* try to fill multi-io first */
|
||||
err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
|
||||
|
@ -1582,7 +1606,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
|
|||
return err;
|
||||
badness += err;
|
||||
}
|
||||
if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||
if (!spec->no_multi_io &&
|
||||
cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
|
||||
err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -1600,7 +1625,8 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
|
|||
check_aamix_out_path(codec, spec->speaker_paths[0]);
|
||||
}
|
||||
|
||||
if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
|
||||
if (!spec->no_multi_io &&
|
||||
cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
|
||||
if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
|
||||
spec->multi_ios = 1; /* give badness */
|
||||
|
||||
|
@ -3724,7 +3750,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
|
|||
/* check each pin in the given array; returns true if any of them is plugged */
|
||||
static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
|
||||
{
|
||||
int i, present = 0;
|
||||
int i;
|
||||
bool present = false;
|
||||
|
||||
for (i = 0; i < num_pins; i++) {
|
||||
hda_nid_t nid = pins[i];
|
||||
|
@ -3733,14 +3760,15 @@ static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
|
|||
/* don't detect pins retasked as inputs */
|
||||
if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
|
||||
continue;
|
||||
present |= snd_hda_jack_detect(codec, nid);
|
||||
if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT)
|
||||
present = true;
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
/* standard HP/line-out auto-mute helper */
|
||||
static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
|
||||
bool mute)
|
||||
int *paths, bool mute)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
int i;
|
||||
|
@ -3752,10 +3780,19 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
|
|||
break;
|
||||
|
||||
if (spec->auto_mute_via_amp) {
|
||||
struct nid_path *path;
|
||||
hda_nid_t mute_nid;
|
||||
|
||||
path = snd_hda_get_path_from_idx(codec, paths[i]);
|
||||
if (!path)
|
||||
continue;
|
||||
mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]);
|
||||
if (!mute_nid)
|
||||
continue;
|
||||
if (mute)
|
||||
spec->mute_bits |= (1ULL << nid);
|
||||
spec->mute_bits |= (1ULL << mute_nid);
|
||||
else
|
||||
spec->mute_bits &= ~(1ULL << nid);
|
||||
spec->mute_bits &= ~(1ULL << mute_nid);
|
||||
set_pin_eapd(codec, nid, !mute);
|
||||
continue;
|
||||
}
|
||||
|
@ -3786,14 +3823,19 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
|
|||
void snd_hda_gen_update_outputs(struct hda_codec *codec)
|
||||
{
|
||||
struct hda_gen_spec *spec = codec->spec;
|
||||
int *paths;
|
||||
int on;
|
||||
|
||||
/* Control HP pins/amps depending on master_mute state;
|
||||
* in general, HP pins/amps control should be enabled in all cases,
|
||||
* but currently set only for master_mute, just to be safe
|
||||
*/
|
||||
if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
|
||||
paths = spec->out_paths;
|
||||
else
|
||||
paths = spec->hp_paths;
|
||||
do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
|
||||
spec->autocfg.hp_pins, spec->master_mute);
|
||||
spec->autocfg.hp_pins, paths, spec->master_mute);
|
||||
|
||||
if (!spec->automute_speaker)
|
||||
on = 0;
|
||||
|
@ -3801,8 +3843,12 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec)
|
|||
on = spec->hp_jack_present | spec->line_jack_present;
|
||||
on |= spec->master_mute;
|
||||
spec->speaker_muted = on;
|
||||
if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
|
||||
paths = spec->out_paths;
|
||||
else
|
||||
paths = spec->speaker_paths;
|
||||
do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
|
||||
spec->autocfg.speaker_pins, on);
|
||||
spec->autocfg.speaker_pins, paths, on);
|
||||
|
||||
/* toggle line-out mutes if needed, too */
|
||||
/* if LO is a copy of either HP or Speaker, don't need to handle it */
|
||||
|
@ -3815,8 +3861,9 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec)
|
|||
on = spec->hp_jack_present;
|
||||
on |= spec->master_mute;
|
||||
spec->line_out_muted = on;
|
||||
paths = spec->out_paths;
|
||||
do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
|
||||
spec->autocfg.line_out_pins, on);
|
||||
spec->autocfg.line_out_pins, paths, on);
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs);
|
||||
|
||||
|
@ -3887,7 +3934,7 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja
|
|||
/* don't detect pins retasked as outputs */
|
||||
if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
|
||||
continue;
|
||||
if (snd_hda_jack_detect(codec, pin)) {
|
||||
if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) {
|
||||
mux_select(codec, 0, spec->am_entry[i].idx);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -220,6 +220,7 @@ struct hda_gen_spec {
|
|||
unsigned int hp_mic:1; /* Allow HP as a mic-in */
|
||||
unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */
|
||||
unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
|
||||
unsigned int no_multi_io:1; /* Don't try multi I/O config */
|
||||
unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
|
||||
unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
|
||||
unsigned int own_eapd_ctl:1; /* set EAPD by own function */
|
||||
|
|
|
@ -295,7 +295,7 @@ static ssize_t type##_store(struct device *dev, \
|
|||
struct snd_hwdep *hwdep = dev_get_drvdata(dev); \
|
||||
struct hda_codec *codec = hwdep->private_data; \
|
||||
unsigned long val; \
|
||||
int err = strict_strtoul(buf, 0, &val); \
|
||||
int err = kstrtoul(buf, 0, &val); \
|
||||
if (err < 0) \
|
||||
return err; \
|
||||
codec->type = val; \
|
||||
|
@ -654,7 +654,7 @@ int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
|
|||
p = snd_hda_get_hint(codec, key);
|
||||
if (!p)
|
||||
ret = -ENOENT;
|
||||
else if (strict_strtoul(p, 0, &val))
|
||||
else if (kstrtoul(p, 0, &val))
|
||||
ret = -EINVAL;
|
||||
else {
|
||||
*valp = val;
|
||||
|
@ -751,7 +751,7 @@ static void parse_##name##_mode(char *buf, struct hda_bus *bus, \
|
|||
struct hda_codec **codecp) \
|
||||
{ \
|
||||
unsigned long val; \
|
||||
if (!strict_strtoul(buf, 0, &val)) \
|
||||
if (!kstrtoul(buf, 0, &val)) \
|
||||
(*codecp)->name = val; \
|
||||
}
|
||||
|
||||
|
|
|
@ -1160,7 +1160,7 @@ static int azx_reset(struct azx *chip, int full_reset)
|
|||
goto __skip;
|
||||
|
||||
/* clear STATESTS */
|
||||
azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
|
||||
azx_writew(chip, STATESTS, STATESTS_INT_MASK);
|
||||
|
||||
/* reset controller */
|
||||
azx_enter_link_reset(chip);
|
||||
|
@ -1242,7 +1242,7 @@ static void azx_int_clear(struct azx *chip)
|
|||
}
|
||||
|
||||
/* clear STATESTS */
|
||||
azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
|
||||
azx_writew(chip, STATESTS, STATESTS_INT_MASK);
|
||||
|
||||
/* clear rirb status */
|
||||
azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
|
||||
|
@ -1451,8 +1451,8 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
|
|||
|
||||
#if 0
|
||||
/* clear state status int */
|
||||
if (azx_readb(chip, STATESTS) & 0x04)
|
||||
azx_writeb(chip, STATESTS, 0x04);
|
||||
if (azx_readw(chip, STATESTS) & 0x04)
|
||||
azx_writew(chip, STATESTS, 0x04);
|
||||
#endif
|
||||
spin_unlock(&chip->reg_lock);
|
||||
|
||||
|
@ -2971,6 +2971,10 @@ static int azx_runtime_suspend(struct device *dev)
|
|||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip = card->private_data;
|
||||
|
||||
/* enable controller wake up event */
|
||||
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);
|
||||
|
@ -2983,11 +2987,31 @@ static int azx_runtime_resume(struct device *dev)
|
|||
{
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip = card->private_data;
|
||||
struct hda_bus *bus;
|
||||
struct hda_codec *codec;
|
||||
int status;
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
hda_display_power(true);
|
||||
|
||||
/* Read STATESTS before controller reset */
|
||||
status = azx_readw(chip, STATESTS);
|
||||
|
||||
azx_init_pci(chip);
|
||||
azx_init_chip(chip, 1);
|
||||
|
||||
bus = chip->bus;
|
||||
if (status && bus) {
|
||||
list_for_each_entry(codec, &bus->codec_list, list)
|
||||
if (status & (1 << codec->addr))
|
||||
queue_delayed_work(codec->bus->workq,
|
||||
&codec->jackpoll_work, codec->jackpoll_interval);
|
||||
}
|
||||
|
||||
/* disable controller Wake Up event*/
|
||||
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
|
||||
~STATESTS_INT_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3831,11 +3855,13 @@ static int azx_probe_continue(struct azx *chip)
|
|||
|
||||
/* Request power well for Haswell HDA controller and codec */
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
#ifdef CONFIG_SND_HDA_I915
|
||||
err = hda_i915_init();
|
||||
if (err < 0) {
|
||||
snd_printk(KERN_ERR SFX "Error request power-well from i915\n");
|
||||
goto out_free;
|
||||
}
|
||||
#endif
|
||||
hda_display_power(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -194,18 +194,24 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
|
|||
EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
|
||||
|
||||
/**
|
||||
* snd_hda_jack_detect - query pin Presence Detect status
|
||||
* snd_hda_jack_detect_state - query pin Presence Detect status
|
||||
* @codec: the CODEC to sense
|
||||
* @nid: the pin NID to sense
|
||||
*
|
||||
* Query and return the pin's Presence Detect status.
|
||||
* Query and return the pin's Presence Detect status, as either
|
||||
* HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM.
|
||||
*/
|
||||
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
|
||||
int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
u32 sense = snd_hda_pin_sense(codec, nid);
|
||||
return get_jack_plug_state(sense);
|
||||
struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
|
||||
if (jack && jack->phantom_jack)
|
||||
return HDA_JACK_PHANTOM;
|
||||
else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE)
|
||||
return HDA_JACK_PRESENT;
|
||||
else
|
||||
return HDA_JACK_NOT_PRESENT;
|
||||
}
|
||||
EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
|
||||
EXPORT_SYMBOL_HDA(snd_hda_jack_detect_state);
|
||||
|
||||
/**
|
||||
* snd_hda_jack_detect_enable - enable the jack-detection
|
||||
|
@ -247,8 +253,8 @@ EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
|
|||
int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
|
||||
hda_nid_t gating_nid)
|
||||
{
|
||||
struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid);
|
||||
struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid);
|
||||
struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid);
|
||||
struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid);
|
||||
|
||||
if (!gated || !gating)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -75,7 +75,18 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
|
|||
hda_nid_t gating_nid);
|
||||
|
||||
u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
|
||||
int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
|
||||
|
||||
/* the jack state returned from snd_hda_jack_detect_state() */
|
||||
enum {
|
||||
HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM,
|
||||
};
|
||||
|
||||
int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid);
|
||||
|
||||
static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT;
|
||||
}
|
||||
|
||||
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
|
||||
|
||||
|
|
|
@ -582,6 +582,36 @@ static void print_gpio(struct snd_info_buffer *buffer,
|
|||
print_nid_array(buffer, codec, nid, &codec->nids);
|
||||
}
|
||||
|
||||
static void print_device_list(struct snd_info_buffer *buffer,
|
||||
struct hda_codec *codec, hda_nid_t nid)
|
||||
{
|
||||
int i, curr = -1;
|
||||
u8 dev_list[AC_MAX_DEV_LIST_LEN];
|
||||
int devlist_len;
|
||||
|
||||
devlist_len = snd_hda_get_devices(codec, nid, dev_list,
|
||||
AC_MAX_DEV_LIST_LEN);
|
||||
snd_iprintf(buffer, " Devices: %d\n", devlist_len);
|
||||
if (devlist_len <= 0)
|
||||
return;
|
||||
|
||||
curr = snd_hda_codec_read(codec, nid, 0,
|
||||
AC_VERB_GET_DEVICE_SEL, 0);
|
||||
|
||||
for (i = 0; i < devlist_len; i++) {
|
||||
if (i == curr)
|
||||
snd_iprintf(buffer, " *");
|
||||
else
|
||||
snd_iprintf(buffer, " ");
|
||||
|
||||
snd_iprintf(buffer,
|
||||
"Dev %02d: PD = %d, ELDV = %d, IA = %d\n", i,
|
||||
!!(dev_list[i] & AC_DE_PD),
|
||||
!!(dev_list[i] & AC_DE_ELDV),
|
||||
!!(dev_list[i] & AC_DE_IA));
|
||||
}
|
||||
}
|
||||
|
||||
static void print_codec_info(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
|
@ -751,6 +781,9 @@ static void print_codec_info(struct snd_info_entry *entry,
|
|||
(wid_caps & AC_WCAP_DELAY) >>
|
||||
AC_WCAP_DELAY_SHIFT);
|
||||
|
||||
if (wid_type == AC_WID_PIN && codec->dp_mst)
|
||||
print_device_list(buffer, codec, nid);
|
||||
|
||||
if (wid_caps & AC_WCAP_CONN_LIST)
|
||||
print_conn_list(buffer, codec, nid, wid_type,
|
||||
conn, conn_len);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -66,6 +66,8 @@ struct conexant_spec {
|
|||
hda_nid_t eapds[4];
|
||||
bool dynamic_eapd;
|
||||
|
||||
unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
|
||||
|
||||
#ifdef ENABLE_CXT_STATIC_QUIRKS
|
||||
const struct snd_kcontrol_new *mixers[5];
|
||||
int num_mixers;
|
||||
|
@ -3200,6 +3202,9 @@ static int cx_auto_init(struct hda_codec *codec)
|
|||
snd_hda_gen_init(codec);
|
||||
if (!spec->dynamic_eapd)
|
||||
cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
|
||||
|
||||
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3224,6 +3229,8 @@ enum {
|
|||
CXT_PINCFG_LEMOTE_A1205,
|
||||
CXT_FIXUP_STEREO_DMIC,
|
||||
CXT_FIXUP_INC_MIC_BOOST,
|
||||
CXT_FIXUP_HEADPHONE_MIC_PIN,
|
||||
CXT_FIXUP_HEADPHONE_MIC,
|
||||
};
|
||||
|
||||
static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
|
||||
|
@ -3246,6 +3253,59 @@ static void cxt5066_increase_mic_boost(struct hda_codec *codec,
|
|||
(0 << AC_AMPCAP_MUTE_SHIFT));
|
||||
}
|
||||
|
||||
static void cxt_update_headset_mode(struct hda_codec *codec)
|
||||
{
|
||||
/* The verbs used in this function were tested on a Conexant CX20751/2 codec. */
|
||||
int i;
|
||||
bool mic_mode = false;
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->gen.autocfg;
|
||||
|
||||
hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++)
|
||||
if (cfg->inputs[i].pin == mux_pin) {
|
||||
mic_mode = !!cfg->inputs[i].is_headphone_mic;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mic_mode) {
|
||||
snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */
|
||||
spec->gen.hp_jack_present = false;
|
||||
} else {
|
||||
snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */
|
||||
spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]);
|
||||
}
|
||||
|
||||
snd_hda_gen_update_outputs(codec);
|
||||
}
|
||||
|
||||
static void cxt_update_headset_mode_hook(struct hda_codec *codec,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
cxt_update_headset_mode(codec);
|
||||
}
|
||||
|
||||
static void cxt_fixup_headphone_mic(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct conexant_spec *spec = codec->spec;
|
||||
|
||||
switch (action) {
|
||||
case HDA_FIXUP_ACT_PRE_PROBE:
|
||||
spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
|
||||
break;
|
||||
case HDA_FIXUP_ACT_PROBE:
|
||||
spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
|
||||
spec->gen.automute_hook = cxt_update_headset_mode;
|
||||
break;
|
||||
case HDA_FIXUP_ACT_INIT:
|
||||
cxt_update_headset_mode(codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ThinkPad X200 & co with cxt5051 */
|
||||
static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
|
||||
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
|
||||
|
@ -3302,6 +3362,19 @@ static const struct hda_fixup cxt_fixups[] = {
|
|||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = cxt5066_increase_mic_boost,
|
||||
},
|
||||
[CXT_FIXUP_HEADPHONE_MIC_PIN] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.chained = true,
|
||||
.chain_id = CXT_FIXUP_HEADPHONE_MIC,
|
||||
.v.pins = (const struct hda_pintbl[]) {
|
||||
{ 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
|
||||
{ }
|
||||
}
|
||||
},
|
||||
[CXT_FIXUP_HEADPHONE_MIC] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = cxt_fixup_headphone_mic,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk cxt5051_fixups[] = {
|
||||
|
@ -3311,6 +3384,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
|
|||
|
||||
static const struct snd_pci_quirk cxt5066_fixups[] = {
|
||||
SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
|
||||
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
|
||||
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
|
||||
SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
|
||||
|
@ -3395,7 +3469,8 @@ static int patch_conexant_auto(struct hda_codec *codec)
|
|||
|
||||
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
|
||||
|
||||
err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
|
||||
err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
|
||||
spec->parse_flags);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
|
@ -3416,6 +3491,8 @@ static int patch_conexant_auto(struct hda_codec *codec)
|
|||
codec->bus->allow_bus_reset = 1;
|
||||
}
|
||||
|
||||
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
|
|
@ -67,6 +67,8 @@ struct hdmi_spec_per_pin {
|
|||
struct delayed_work work;
|
||||
struct snd_kcontrol *eld_ctl;
|
||||
int repoll_count;
|
||||
bool setup; /* the stream has been set up by prepare callback */
|
||||
int channels; /* current number of channels */
|
||||
bool non_pcm;
|
||||
bool chmap_set; /* channel-map override by ALSA API? */
|
||||
unsigned char chmap[8]; /* ALSA API channel-map */
|
||||
|
@ -551,6 +553,17 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels)
|
|||
}
|
||||
}
|
||||
|
||||
if (!ca) {
|
||||
/* if there was no match, select the regular ALSA channel
|
||||
* allocation with the matching number of channels */
|
||||
for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
|
||||
if (channels == channel_allocations[i].channels) {
|
||||
ca = channel_allocations[i].ca_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf));
|
||||
snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
|
||||
ca, channels, buf);
|
||||
|
@ -868,18 +881,19 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
|
||||
bool non_pcm,
|
||||
struct snd_pcm_substream *substream)
|
||||
static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
|
||||
struct hdmi_spec_per_pin *per_pin,
|
||||
bool non_pcm)
|
||||
{
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
||||
hda_nid_t pin_nid = per_pin->pin_nid;
|
||||
int channels = substream->runtime->channels;
|
||||
int channels = per_pin->channels;
|
||||
struct hdmi_eld *eld;
|
||||
int ca;
|
||||
union audio_infoframe ai;
|
||||
|
||||
if (!channels)
|
||||
return;
|
||||
|
||||
eld = &per_pin->sink_eld;
|
||||
if (!eld->monitor_present)
|
||||
return;
|
||||
|
@ -959,6 +973,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
|
|||
int pin_nid;
|
||||
int pin_idx;
|
||||
struct hda_jack_tbl *jack;
|
||||
int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
|
||||
|
||||
jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
|
||||
if (!jack)
|
||||
|
@ -967,8 +982,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
|
|||
jack->jack_dirty = 1;
|
||||
|
||||
_snd_printd(SND_PR_VERBOSE,
|
||||
"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
|
||||
codec->addr, pin_nid,
|
||||
"HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
|
||||
codec->addr, pin_nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
|
||||
!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
|
||||
|
||||
pin_idx = pin_nid_to_pin_index(spec, pin_nid);
|
||||
|
@ -1329,6 +1344,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
|
|||
eld_changed = true;
|
||||
}
|
||||
if (update_eld) {
|
||||
bool old_eld_valid = pin_eld->eld_valid;
|
||||
pin_eld->eld_valid = eld->eld_valid;
|
||||
eld_changed = pin_eld->eld_size != eld->eld_size ||
|
||||
memcmp(pin_eld->eld_buffer, eld->eld_buffer,
|
||||
|
@ -1338,6 +1354,18 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
|
|||
eld->eld_size);
|
||||
pin_eld->eld_size = eld->eld_size;
|
||||
pin_eld->info = eld->info;
|
||||
|
||||
/* Haswell-specific workaround: re-setup when the transcoder is
|
||||
* changed during the stream playback
|
||||
*/
|
||||
if (codec->vendor_id == 0x80862807 &&
|
||||
eld->eld_valid && !old_eld_valid && per_pin->setup) {
|
||||
snd_hda_codec_write(codec, pin_nid, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE,
|
||||
AMP_OUT_UNMUTE);
|
||||
hdmi_setup_audio_infoframe(codec, per_pin,
|
||||
per_pin->non_pcm);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&pin_eld->lock);
|
||||
|
||||
|
@ -1510,14 +1538,17 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
|
|||
hda_nid_t cvt_nid = hinfo->nid;
|
||||
struct hdmi_spec *spec = codec->spec;
|
||||
int pin_idx = hinfo_to_pin_index(spec, hinfo);
|
||||
hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid;
|
||||
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
|
||||
hda_nid_t pin_nid = per_pin->pin_nid;
|
||||
bool non_pcm;
|
||||
|
||||
non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
|
||||
per_pin->channels = substream->runtime->channels;
|
||||
per_pin->setup = true;
|
||||
|
||||
hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
|
||||
|
||||
hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream);
|
||||
hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
|
||||
|
||||
return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
|
||||
}
|
||||
|
@ -1557,6 +1588,9 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
|
|||
snd_hda_spdif_ctls_unassign(codec, pin_idx);
|
||||
per_pin->chmap_set = false;
|
||||
memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
|
||||
|
||||
per_pin->setup = false;
|
||||
per_pin->channels = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1692,8 +1726,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
|
|||
per_pin->chmap_set = true;
|
||||
memcpy(per_pin->chmap, chmap, sizeof(chmap));
|
||||
if (prepared)
|
||||
hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm,
|
||||
substream);
|
||||
hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1992,8 +2025,10 @@ static int patch_generic_hdmi(struct hda_codec *codec)
|
|||
return -EINVAL;
|
||||
}
|
||||
codec->patch_ops = generic_hdmi_patch_ops;
|
||||
if (codec->vendor_id == 0x80862807)
|
||||
if (codec->vendor_id == 0x80862807) {
|
||||
codec->patch_ops.set_power_state = haswell_set_power_state;
|
||||
codec->dp_mst = true;
|
||||
}
|
||||
|
||||
generic_hdmi_init_per_pins(codec);
|
||||
|
||||
|
|
|
@ -282,6 +282,7 @@ static void alc_eapd_shutup(struct hda_codec *codec)
|
|||
{
|
||||
alc_auto_setup_eapd(codec, false);
|
||||
msleep(200);
|
||||
snd_hda_shutup_pins(codec);
|
||||
}
|
||||
|
||||
/* generic EAPD initialization */
|
||||
|
@ -826,7 +827,8 @@ static inline void alc_shutup(struct hda_codec *codec)
|
|||
|
||||
if (spec && spec->shutup)
|
||||
spec->shutup(codec);
|
||||
snd_hda_shutup_pins(codec);
|
||||
else
|
||||
snd_hda_shutup_pins(codec);
|
||||
}
|
||||
|
||||
#define alc_free snd_hda_gen_free
|
||||
|
@ -1853,8 +1855,10 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
|
|||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
if (action == HDA_FIXUP_ACT_PRE_PROBE)
|
||||
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
|
||||
spec->gen.no_primary_hp = 1;
|
||||
spec->gen.no_multi_io = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hda_fixup alc882_fixups[] = {
|
||||
|
@ -2533,6 +2537,7 @@ enum {
|
|||
ALC269_TYPE_ALC269VD,
|
||||
ALC269_TYPE_ALC280,
|
||||
ALC269_TYPE_ALC282,
|
||||
ALC269_TYPE_ALC283,
|
||||
ALC269_TYPE_ALC284,
|
||||
ALC269_TYPE_ALC286,
|
||||
};
|
||||
|
@ -2558,6 +2563,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
|
|||
case ALC269_TYPE_ALC269VB:
|
||||
case ALC269_TYPE_ALC269VD:
|
||||
case ALC269_TYPE_ALC282:
|
||||
case ALC269_TYPE_ALC283:
|
||||
case ALC269_TYPE_ALC286:
|
||||
ssids = alc269_ssids;
|
||||
break;
|
||||
|
@ -2583,15 +2589,81 @@ static void alc269_shutup(struct hda_codec *codec)
|
|||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
if (spec->codec_variant != ALC269_TYPE_ALC269VB)
|
||||
return;
|
||||
|
||||
if (spec->codec_variant == ALC269_TYPE_ALC269VB)
|
||||
alc269vb_toggle_power_output(codec, 0);
|
||||
if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
|
||||
(alc_get_coef0(codec) & 0x00ff) == 0x018) {
|
||||
msleep(150);
|
||||
}
|
||||
snd_hda_shutup_pins(codec);
|
||||
}
|
||||
|
||||
static void alc283_init(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
|
||||
bool hp_pin_sense;
|
||||
int val;
|
||||
|
||||
if (!hp_pin)
|
||||
return;
|
||||
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
|
||||
|
||||
/* Index 0x43 Direct Drive HP AMP LPM Control 1 */
|
||||
/* Headphone capless set to high power mode */
|
||||
alc_write_coef_idx(codec, 0x43, 0x9004);
|
||||
|
||||
snd_hda_codec_write(codec, hp_pin, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
|
||||
|
||||
if (hp_pin_sense)
|
||||
msleep(85);
|
||||
|
||||
snd_hda_codec_write(codec, hp_pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
|
||||
|
||||
if (hp_pin_sense)
|
||||
msleep(85);
|
||||
/* Index 0x46 Combo jack auto switch control 2 */
|
||||
/* 3k pull low control for Headset jack. */
|
||||
val = alc_read_coef_idx(codec, 0x46);
|
||||
alc_write_coef_idx(codec, 0x46, val & ~(3 << 12));
|
||||
/* Headphone capless set to normal mode */
|
||||
alc_write_coef_idx(codec, 0x43, 0x9614);
|
||||
}
|
||||
|
||||
static void alc283_shutup(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
|
||||
bool hp_pin_sense;
|
||||
int val;
|
||||
|
||||
if (!hp_pin) {
|
||||
alc269_shutup(codec);
|
||||
return;
|
||||
}
|
||||
|
||||
hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
|
||||
|
||||
alc_write_coef_idx(codec, 0x43, 0x9004);
|
||||
|
||||
snd_hda_codec_write(codec, hp_pin, 0,
|
||||
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
|
||||
|
||||
if (hp_pin_sense)
|
||||
msleep(85);
|
||||
|
||||
snd_hda_codec_write(codec, hp_pin, 0,
|
||||
AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
|
||||
|
||||
val = alc_read_coef_idx(codec, 0x46);
|
||||
alc_write_coef_idx(codec, 0x46, val | (3 << 12));
|
||||
|
||||
if (hp_pin_sense)
|
||||
msleep(85);
|
||||
snd_hda_shutup_pins(codec);
|
||||
alc_write_coef_idx(codec, 0x43, 0x9614);
|
||||
}
|
||||
|
||||
static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
|
||||
|
@ -2722,6 +2794,7 @@ static int alc269_resume(struct hda_codec *codec)
|
|||
hda_call_check_power_status(codec, 0x01);
|
||||
if (spec->has_alc5505_dsp)
|
||||
alc5505_dsp_resume(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
@ -3261,6 +3334,28 @@ static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
|
|||
alc_fixup_headset_mode(codec, fix, action);
|
||||
}
|
||||
|
||||
/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
|
||||
static int find_ext_mic_pin(struct hda_codec *codec)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
struct auto_pin_cfg *cfg = &spec->gen.autocfg;
|
||||
hda_nid_t nid;
|
||||
unsigned int defcfg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cfg->num_inputs; i++) {
|
||||
if (cfg->inputs[i].type != AUTO_PIN_MIC)
|
||||
continue;
|
||||
nid = cfg->inputs[i].pin;
|
||||
defcfg = snd_hda_codec_get_pincfg(codec, nid);
|
||||
if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
|
||||
continue;
|
||||
return nid;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix,
|
||||
int action)
|
||||
|
@ -3268,11 +3363,12 @@ static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
|
|||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
if (action == HDA_FIXUP_ACT_PROBE) {
|
||||
if (snd_BUG_ON(!spec->gen.am_entry[1].pin ||
|
||||
!spec->gen.autocfg.hp_pins[0]))
|
||||
int mic_pin = find_ext_mic_pin(codec);
|
||||
int hp_pin = spec->gen.autocfg.hp_pins[0];
|
||||
|
||||
if (snd_BUG_ON(!mic_pin || !hp_pin))
|
||||
return;
|
||||
snd_hda_jack_set_gating_jack(codec, spec->gen.am_entry[1].pin,
|
||||
spec->gen.autocfg.hp_pins[0]);
|
||||
snd_hda_jack_set_gating_jack(codec, mic_pin, hp_pin);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3308,6 +3404,45 @@ static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
static void alc283_hp_automute_hook(struct hda_codec *codec,
|
||||
struct hda_jack_tbl *jack)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
int vref;
|
||||
|
||||
msleep(200);
|
||||
snd_hda_gen_hp_automute(codec, jack);
|
||||
|
||||
vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
|
||||
|
||||
msleep(600);
|
||||
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
|
||||
vref);
|
||||
}
|
||||
|
||||
static void alc283_chromebook_caps(struct hda_codec *codec)
|
||||
{
|
||||
snd_hda_override_wcaps(codec, 0x03, 0);
|
||||
}
|
||||
|
||||
static void alc283_fixup_chromebook(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
int val;
|
||||
|
||||
switch (action) {
|
||||
case HDA_FIXUP_ACT_PRE_PROBE:
|
||||
alc283_chromebook_caps(codec);
|
||||
spec->gen.hp_automute_hook = alc283_hp_automute_hook;
|
||||
/* MIC2-VREF control */
|
||||
/* Set to manual mode */
|
||||
val = alc_read_coef_idx(codec, 0x06);
|
||||
alc_write_coef_idx(codec, 0x06, val & ~0x000c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
ALC269_FIXUP_SONY_VAIO,
|
||||
ALC275_FIXUP_SONY_VAIO_GPIO2,
|
||||
|
@ -3344,6 +3479,7 @@ enum {
|
|||
ALC269_FIXUP_ACER_AC700,
|
||||
ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
|
||||
ALC269VB_FIXUP_ORDISSIMO_EVE2,
|
||||
ALC283_FIXUP_CHROME_BOOK,
|
||||
};
|
||||
|
||||
static const struct hda_fixup alc269_fixups[] = {
|
||||
|
@ -3595,11 +3731,20 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
{ }
|
||||
},
|
||||
},
|
||||
[ALC283_FIXUP_CHROME_BOOK] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc283_fixup_chromebook,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
|
||||
SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
|
||||
SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
|
||||
SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
|
||||
SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
|
||||
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
|
||||
SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||
|
@ -3637,6 +3782,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
|
||||
SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
|
||||
SND_PCI_QUIRK(0x103c, 0x21ed, "HP Falco Chromebook", ALC283_FIXUP_CHROME_BOOK),
|
||||
SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
|
@ -3655,11 +3801,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
|
||||
SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
|
||||
SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
|
||||
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
|
||||
SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
|
||||
SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
|
||||
SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
|
||||
SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
|
||||
SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
|
||||
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
|
||||
SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
|
||||
|
@ -3670,8 +3811,16 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK),
|
||||
SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
|
||||
SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
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(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
|
||||
|
@ -3840,11 +3989,15 @@ static int patch_alc269(struct hda_codec *codec)
|
|||
case 0x10ec0290:
|
||||
spec->codec_variant = ALC269_TYPE_ALC280;
|
||||
break;
|
||||
case 0x10ec0233:
|
||||
case 0x10ec0282:
|
||||
case 0x10ec0283:
|
||||
spec->codec_variant = ALC269_TYPE_ALC282;
|
||||
break;
|
||||
case 0x10ec0233:
|
||||
case 0x10ec0283:
|
||||
spec->codec_variant = ALC269_TYPE_ALC283;
|
||||
spec->shutup = alc283_shutup;
|
||||
spec->init_hook = alc283_init;
|
||||
break;
|
||||
case 0x10ec0284:
|
||||
case 0x10ec0292:
|
||||
spec->codec_variant = ALC269_TYPE_ALC284;
|
||||
|
@ -3872,7 +4025,8 @@ static int patch_alc269(struct hda_codec *codec)
|
|||
codec->patch_ops.suspend = alc269_suspend;
|
||||
codec->patch_ops.resume = alc269_resume;
|
||||
#endif
|
||||
spec->shutup = alc269_shutup;
|
||||
if (!spec->shutup)
|
||||
spec->shutup = alc269_shutup;
|
||||
|
||||
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
|
||||
|
||||
|
|
|
@ -158,6 +158,7 @@ enum {
|
|||
STAC_D965_VERBS,
|
||||
STAC_DELL_3ST,
|
||||
STAC_DELL_BIOS,
|
||||
STAC_DELL_BIOS_AMIC,
|
||||
STAC_DELL_BIOS_SPDIF,
|
||||
STAC_927X_DELL_DMIC,
|
||||
STAC_927X_VOLKNOB,
|
||||
|
@ -3231,8 +3232,6 @@ static const struct hda_fixup stac927x_fixups[] = {
|
|||
[STAC_DELL_BIOS] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = (const struct hda_pintbl[]) {
|
||||
/* configure the analog microphone on some laptops */
|
||||
{ 0x0c, 0x90a79130 },
|
||||
/* correct the front output jack as a hp out */
|
||||
{ 0x0f, 0x0221101f },
|
||||
/* correct the front input jack as a mic */
|
||||
|
@ -3242,6 +3241,16 @@ static const struct hda_fixup stac927x_fixups[] = {
|
|||
.chained = true,
|
||||
.chain_id = STAC_927X_DELL_DMIC,
|
||||
},
|
||||
[STAC_DELL_BIOS_AMIC] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = (const struct hda_pintbl[]) {
|
||||
/* configure the analog microphone on some laptops */
|
||||
{ 0x0c, 0x90a79130 },
|
||||
{}
|
||||
},
|
||||
.chained = true,
|
||||
.chain_id = STAC_DELL_BIOS,
|
||||
},
|
||||
[STAC_DELL_BIOS_SPDIF] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = (const struct hda_pintbl[]) {
|
||||
|
@ -3270,6 +3279,7 @@ static const struct hda_model_fixup stac927x_models[] = {
|
|||
{ .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" },
|
||||
{ .id = STAC_DELL_3ST, .name = "dell-3stack" },
|
||||
{ .id = STAC_DELL_BIOS, .name = "dell-bios" },
|
||||
{ .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" },
|
||||
{ .id = STAC_927X_VOLKNOB, .name = "volknob" },
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -207,9 +207,9 @@ static void vt1708_stop_hp_work(struct hda_codec *codec)
|
|||
return;
|
||||
if (spec->hp_work_active) {
|
||||
snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1);
|
||||
codec->jackpoll_interval = 0;
|
||||
cancel_delayed_work_sync(&codec->jackpoll_work);
|
||||
spec->hp_work_active = false;
|
||||
codec->jackpoll_interval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/info.h>
|
||||
|
@ -198,6 +199,31 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard.");
|
|||
#define RME96_AD1852_VOL_BITS 14
|
||||
#define RME96_AD1855_VOL_BITS 10
|
||||
|
||||
/* Defines for snd_rme96_trigger */
|
||||
#define RME96_TB_START_PLAYBACK 1
|
||||
#define RME96_TB_START_CAPTURE 2
|
||||
#define RME96_TB_STOP_PLAYBACK 4
|
||||
#define RME96_TB_STOP_CAPTURE 8
|
||||
#define RME96_TB_RESET_PLAYPOS 16
|
||||
#define RME96_TB_RESET_CAPTUREPOS 32
|
||||
#define RME96_TB_CLEAR_PLAYBACK_IRQ 64
|
||||
#define RME96_TB_CLEAR_CAPTURE_IRQ 128
|
||||
#define RME96_RESUME_PLAYBACK (RME96_TB_START_PLAYBACK)
|
||||
#define RME96_RESUME_CAPTURE (RME96_TB_START_CAPTURE)
|
||||
#define RME96_RESUME_BOTH (RME96_RESUME_PLAYBACK \
|
||||
| RME96_RESUME_CAPTURE)
|
||||
#define RME96_START_PLAYBACK (RME96_TB_START_PLAYBACK \
|
||||
| RME96_TB_RESET_PLAYPOS)
|
||||
#define RME96_START_CAPTURE (RME96_TB_START_CAPTURE \
|
||||
| RME96_TB_RESET_CAPTUREPOS)
|
||||
#define RME96_START_BOTH (RME96_START_PLAYBACK \
|
||||
| RME96_START_CAPTURE)
|
||||
#define RME96_STOP_PLAYBACK (RME96_TB_STOP_PLAYBACK \
|
||||
| RME96_TB_CLEAR_PLAYBACK_IRQ)
|
||||
#define RME96_STOP_CAPTURE (RME96_TB_STOP_CAPTURE \
|
||||
| RME96_TB_CLEAR_CAPTURE_IRQ)
|
||||
#define RME96_STOP_BOTH (RME96_STOP_PLAYBACK \
|
||||
| RME96_STOP_CAPTURE)
|
||||
|
||||
struct rme96 {
|
||||
spinlock_t lock;
|
||||
|
@ -214,6 +240,13 @@ struct rme96 {
|
|||
|
||||
u8 rev; /* card revision number */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
u32 playback_pointer;
|
||||
u32 capture_pointer;
|
||||
void *playback_suspend_buffer;
|
||||
void *capture_suspend_buffer;
|
||||
#endif
|
||||
|
||||
struct snd_pcm_substream *playback_substream;
|
||||
struct snd_pcm_substream *capture_substream;
|
||||
|
||||
|
@ -344,6 +377,8 @@ static struct snd_pcm_hardware snd_rme96_playback_spdif_info =
|
|||
{
|
||||
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
|
@ -373,6 +408,8 @@ static struct snd_pcm_hardware snd_rme96_capture_spdif_info =
|
|||
{
|
||||
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
|
@ -402,6 +439,8 @@ static struct snd_pcm_hardware snd_rme96_playback_adat_info =
|
|||
{
|
||||
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
|
@ -427,6 +466,8 @@ static struct snd_pcm_hardware snd_rme96_capture_adat_info =
|
|||
{
|
||||
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_SYNC_START |
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
|
@ -1045,54 +1086,35 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream,
|
|||
}
|
||||
|
||||
static void
|
||||
snd_rme96_playback_start(struct rme96 *rme96,
|
||||
int from_pause)
|
||||
snd_rme96_trigger(struct rme96 *rme96,
|
||||
int op)
|
||||
{
|
||||
if (!from_pause) {
|
||||
if (op & RME96_TB_RESET_PLAYPOS)
|
||||
writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
|
||||
}
|
||||
|
||||
rme96->wcreg |= RME96_WCR_START;
|
||||
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
|
||||
}
|
||||
|
||||
static void
|
||||
snd_rme96_capture_start(struct rme96 *rme96,
|
||||
int from_pause)
|
||||
{
|
||||
if (!from_pause) {
|
||||
if (op & RME96_TB_RESET_CAPTUREPOS)
|
||||
writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
|
||||
if (op & RME96_TB_CLEAR_PLAYBACK_IRQ) {
|
||||
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
|
||||
if (rme96->rcreg & RME96_RCR_IRQ)
|
||||
writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
|
||||
}
|
||||
|
||||
rme96->wcreg |= RME96_WCR_START_2;
|
||||
if (op & RME96_TB_CLEAR_CAPTURE_IRQ) {
|
||||
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
|
||||
if (rme96->rcreg & RME96_RCR_IRQ_2)
|
||||
writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
|
||||
}
|
||||
if (op & RME96_TB_START_PLAYBACK)
|
||||
rme96->wcreg |= RME96_WCR_START;
|
||||
if (op & RME96_TB_STOP_PLAYBACK)
|
||||
rme96->wcreg &= ~RME96_WCR_START;
|
||||
if (op & RME96_TB_START_CAPTURE)
|
||||
rme96->wcreg |= RME96_WCR_START_2;
|
||||
if (op & RME96_TB_STOP_CAPTURE)
|
||||
rme96->wcreg &= ~RME96_WCR_START_2;
|
||||
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
|
||||
}
|
||||
|
||||
static void
|
||||
snd_rme96_playback_stop(struct rme96 *rme96)
|
||||
{
|
||||
/*
|
||||
* Check if there is an unconfirmed IRQ, if so confirm it, or else
|
||||
* the hardware will not stop generating interrupts
|
||||
*/
|
||||
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
|
||||
if (rme96->rcreg & RME96_RCR_IRQ) {
|
||||
writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
|
||||
}
|
||||
rme96->wcreg &= ~RME96_WCR_START;
|
||||
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
|
||||
}
|
||||
|
||||
static void
|
||||
snd_rme96_capture_stop(struct rme96 *rme96)
|
||||
{
|
||||
rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
|
||||
if (rme96->rcreg & RME96_RCR_IRQ_2) {
|
||||
writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
|
||||
}
|
||||
rme96->wcreg &= ~RME96_WCR_START_2;
|
||||
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
snd_rme96_interrupt(int irq,
|
||||
|
@ -1155,6 +1177,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream)
|
|||
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
snd_pcm_set_sync(substream);
|
||||
spin_lock_irq(&rme96->lock);
|
||||
if (rme96->playback_substream != NULL) {
|
||||
spin_unlock_irq(&rme96->lock);
|
||||
|
@ -1191,6 +1214,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream)
|
|||
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
snd_pcm_set_sync(substream);
|
||||
runtime->hw = snd_rme96_capture_spdif_info;
|
||||
if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG &&
|
||||
(rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0)
|
||||
|
@ -1222,6 +1246,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream)
|
|||
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
snd_pcm_set_sync(substream);
|
||||
spin_lock_irq(&rme96->lock);
|
||||
if (rme96->playback_substream != NULL) {
|
||||
spin_unlock_irq(&rme96->lock);
|
||||
|
@ -1253,6 +1278,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream)
|
|||
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
snd_pcm_set_sync(substream);
|
||||
runtime->hw = snd_rme96_capture_adat_info;
|
||||
if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) {
|
||||
/* makes no sense to use analog input. Note that analog
|
||||
|
@ -1288,7 +1314,7 @@ snd_rme96_playback_close(struct snd_pcm_substream *substream)
|
|||
|
||||
spin_lock_irq(&rme96->lock);
|
||||
if (RME96_ISPLAYING(rme96)) {
|
||||
snd_rme96_playback_stop(rme96);
|
||||
snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
|
||||
}
|
||||
rme96->playback_substream = NULL;
|
||||
rme96->playback_periodsize = 0;
|
||||
|
@ -1309,7 +1335,7 @@ snd_rme96_capture_close(struct snd_pcm_substream *substream)
|
|||
|
||||
spin_lock_irq(&rme96->lock);
|
||||
if (RME96_ISRECORDING(rme96)) {
|
||||
snd_rme96_capture_stop(rme96);
|
||||
snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
|
||||
}
|
||||
rme96->capture_substream = NULL;
|
||||
rme96->capture_periodsize = 0;
|
||||
|
@ -1324,7 +1350,7 @@ snd_rme96_playback_prepare(struct snd_pcm_substream *substream)
|
|||
|
||||
spin_lock_irq(&rme96->lock);
|
||||
if (RME96_ISPLAYING(rme96)) {
|
||||
snd_rme96_playback_stop(rme96);
|
||||
snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
|
||||
}
|
||||
writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
|
||||
spin_unlock_irq(&rme96->lock);
|
||||
|
@ -1338,7 +1364,7 @@ snd_rme96_capture_prepare(struct snd_pcm_substream *substream)
|
|||
|
||||
spin_lock_irq(&rme96->lock);
|
||||
if (RME96_ISRECORDING(rme96)) {
|
||||
snd_rme96_capture_stop(rme96);
|
||||
snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
|
||||
}
|
||||
writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
|
||||
spin_unlock_irq(&rme96->lock);
|
||||
|
@ -1350,41 +1376,55 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream,
|
|||
int cmd)
|
||||
{
|
||||
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_substream *s;
|
||||
bool sync;
|
||||
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
if (snd_pcm_substream_chip(s) == rme96)
|
||||
snd_pcm_trigger_done(s, substream);
|
||||
}
|
||||
|
||||
sync = (rme96->playback_substream && rme96->capture_substream) &&
|
||||
(rme96->playback_substream->group ==
|
||||
rme96->capture_substream->group);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (!RME96_ISPLAYING(rme96)) {
|
||||
if (substream != rme96->playback_substream) {
|
||||
if (substream != rme96->playback_substream)
|
||||
return -EBUSY;
|
||||
}
|
||||
snd_rme96_playback_start(rme96, 0);
|
||||
snd_rme96_trigger(rme96, sync ? RME96_START_BOTH
|
||||
: RME96_START_PLAYBACK);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
if (RME96_ISPLAYING(rme96)) {
|
||||
if (substream != rme96->playback_substream) {
|
||||
if (substream != rme96->playback_substream)
|
||||
return -EBUSY;
|
||||
}
|
||||
snd_rme96_playback_stop(rme96);
|
||||
snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
|
||||
: RME96_STOP_PLAYBACK);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (RME96_ISPLAYING(rme96)) {
|
||||
snd_rme96_playback_stop(rme96);
|
||||
}
|
||||
if (RME96_ISPLAYING(rme96))
|
||||
snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
|
||||
: RME96_STOP_PLAYBACK);
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (!RME96_ISPLAYING(rme96)) {
|
||||
snd_rme96_playback_start(rme96, 1);
|
||||
}
|
||||
if (!RME96_ISPLAYING(rme96))
|
||||
snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
|
||||
: RME96_RESUME_PLAYBACK);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1393,38 +1433,51 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream,
|
|||
int cmd)
|
||||
{
|
||||
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_substream *s;
|
||||
bool sync;
|
||||
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
if (snd_pcm_substream_chip(s) == rme96)
|
||||
snd_pcm_trigger_done(s, substream);
|
||||
}
|
||||
|
||||
sync = (rme96->playback_substream && rme96->capture_substream) &&
|
||||
(rme96->playback_substream->group ==
|
||||
rme96->capture_substream->group);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (!RME96_ISRECORDING(rme96)) {
|
||||
if (substream != rme96->capture_substream) {
|
||||
if (substream != rme96->capture_substream)
|
||||
return -EBUSY;
|
||||
}
|
||||
snd_rme96_capture_start(rme96, 0);
|
||||
snd_rme96_trigger(rme96, sync ? RME96_START_BOTH
|
||||
: RME96_START_CAPTURE);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
if (RME96_ISRECORDING(rme96)) {
|
||||
if (substream != rme96->capture_substream) {
|
||||
if (substream != rme96->capture_substream)
|
||||
return -EBUSY;
|
||||
}
|
||||
snd_rme96_capture_stop(rme96);
|
||||
snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
|
||||
: RME96_STOP_CAPTURE);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (RME96_ISRECORDING(rme96)) {
|
||||
snd_rme96_capture_stop(rme96);
|
||||
}
|
||||
if (RME96_ISRECORDING(rme96))
|
||||
snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
|
||||
: RME96_STOP_CAPTURE);
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (!RME96_ISRECORDING(rme96)) {
|
||||
snd_rme96_capture_start(rme96, 1);
|
||||
}
|
||||
if (!RME96_ISRECORDING(rme96))
|
||||
snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
|
||||
: RME96_RESUME_CAPTURE);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1505,8 +1558,7 @@ snd_rme96_free(void *private_data)
|
|||
return;
|
||||
}
|
||||
if (rme96->irq >= 0) {
|
||||
snd_rme96_playback_stop(rme96);
|
||||
snd_rme96_capture_stop(rme96);
|
||||
snd_rme96_trigger(rme96, RME96_STOP_BOTH);
|
||||
rme96->areg &= ~RME96_AR_DAC_EN;
|
||||
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
|
||||
free_irq(rme96->irq, (void *)rme96);
|
||||
|
@ -1520,6 +1572,10 @@ snd_rme96_free(void *private_data)
|
|||
pci_release_regions(rme96->pci);
|
||||
rme96->port = 0;
|
||||
}
|
||||
#ifdef CONFIG_PM
|
||||
vfree(rme96->playback_suspend_buffer);
|
||||
vfree(rme96->capture_suspend_buffer);
|
||||
#endif
|
||||
pci_disable_device(rme96->pci);
|
||||
}
|
||||
|
||||
|
@ -1606,8 +1662,7 @@ snd_rme96_create(struct rme96 *rme96)
|
|||
rme96->capture_periodsize = 0;
|
||||
|
||||
/* make sure playback/capture is stopped, if by some reason active */
|
||||
snd_rme96_playback_stop(rme96);
|
||||
snd_rme96_capture_stop(rme96);
|
||||
snd_rme96_trigger(rme96, RME96_STOP_BOTH);
|
||||
|
||||
/* set default values in registers */
|
||||
rme96->wcreg =
|
||||
|
@ -2319,6 +2374,87 @@ snd_rme96_create_switches(struct snd_card *card,
|
|||
* Card initialisation
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int
|
||||
snd_rme96_suspend(struct pci_dev *pci,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct snd_card *card = pci_get_drvdata(pci);
|
||||
struct rme96 *rme96 = card->private_data;
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
snd_pcm_suspend(rme96->playback_substream);
|
||||
snd_pcm_suspend(rme96->capture_substream);
|
||||
|
||||
/* save capture & playback pointers */
|
||||
rme96->playback_pointer = readl(rme96->iobase + RME96_IO_GET_PLAY_POS)
|
||||
& RME96_RCR_AUDIO_ADDR_MASK;
|
||||
rme96->capture_pointer = readl(rme96->iobase + RME96_IO_GET_REC_POS)
|
||||
& RME96_RCR_AUDIO_ADDR_MASK;
|
||||
|
||||
/* save playback and capture buffers */
|
||||
memcpy_fromio(rme96->playback_suspend_buffer,
|
||||
rme96->iobase + RME96_IO_PLAY_BUFFER, RME96_BUFFER_SIZE);
|
||||
memcpy_fromio(rme96->capture_suspend_buffer,
|
||||
rme96->iobase + RME96_IO_REC_BUFFER, RME96_BUFFER_SIZE);
|
||||
|
||||
/* disable the DAC */
|
||||
rme96->areg &= ~RME96_AR_DAC_EN;
|
||||
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
|
||||
|
||||
pci_disable_device(pci);
|
||||
pci_save_state(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
snd_rme96_resume(struct pci_dev *pci)
|
||||
{
|
||||
struct snd_card *card = pci_get_drvdata(pci);
|
||||
struct rme96 *rme96 = card->private_data;
|
||||
|
||||
pci_restore_state(pci);
|
||||
if (pci_enable_device(pci) < 0) {
|
||||
printk(KERN_ERR "rme96: pci_enable_device failed, disabling device\n");
|
||||
snd_card_disconnect(card);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* reset playback and record buffer pointers */
|
||||
writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS
|
||||
+ rme96->playback_pointer);
|
||||
writel(0, rme96->iobase + RME96_IO_SET_REC_POS
|
||||
+ rme96->capture_pointer);
|
||||
|
||||
/* restore playback and capture buffers */
|
||||
memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER,
|
||||
rme96->playback_suspend_buffer, RME96_BUFFER_SIZE);
|
||||
memcpy_toio(rme96->iobase + RME96_IO_REC_BUFFER,
|
||||
rme96->capture_suspend_buffer, RME96_BUFFER_SIZE);
|
||||
|
||||
/* reset the ADC */
|
||||
writel(rme96->areg | RME96_AR_PD2,
|
||||
rme96->iobase + RME96_IO_ADDITIONAL_REG);
|
||||
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
|
||||
|
||||
/* reset and enable DAC, restore analog volume */
|
||||
snd_rme96_reset_dac(rme96);
|
||||
rme96->areg |= RME96_AR_DAC_EN;
|
||||
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
|
||||
if (RME96_HAS_ANALOG_OUT(rme96)) {
|
||||
usleep_range(3000, 10000);
|
||||
snd_rme96_apply_dac_volume(rme96);
|
||||
}
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void snd_rme96_card_free(struct snd_card *card)
|
||||
{
|
||||
snd_rme96_free(card->private_data);
|
||||
|
@ -2355,6 +2491,23 @@ snd_rme96_probe(struct pci_dev *pci,
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
|
||||
if (!rme96->playback_suspend_buffer) {
|
||||
snd_printk(KERN_ERR
|
||||
"Failed to allocate playback suspend buffer!\n");
|
||||
snd_card_free(card);
|
||||
return -ENOMEM;
|
||||
}
|
||||
rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
|
||||
if (!rme96->capture_suspend_buffer) {
|
||||
snd_printk(KERN_ERR
|
||||
"Failed to allocate capture suspend buffer!\n");
|
||||
snd_card_free(card);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
strcpy(card->driver, "Digi96");
|
||||
switch (rme96->pci->device) {
|
||||
case PCI_DEVICE_ID_RME_DIGI96:
|
||||
|
@ -2397,6 +2550,10 @@ static struct pci_driver rme96_driver = {
|
|||
.id_table = snd_rme96_ids,
|
||||
.probe = snd_rme96_probe,
|
||||
.remove = snd_rme96_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = snd_rme96_suspend,
|
||||
.resume = snd_rme96_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
module_pci_driver(rme96_driver);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -26,12 +26,9 @@ if SND_SOC
|
|||
config SND_SOC_AC97_BUS
|
||||
bool
|
||||
|
||||
config SND_SOC_DMAENGINE_PCM
|
||||
bool
|
||||
|
||||
config SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
bool
|
||||
select SND_SOC_DMAENGINE_PCM
|
||||
select SND_DMAENGINE_PCM
|
||||
|
||||
# All the supported SoCs
|
||||
source "sound/soc/atmel/Kconfig"
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
|
||||
snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o
|
||||
|
||||
ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),)
|
||||
snd-soc-core-objs += soc-dmaengine-pcm.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
|
||||
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
|
||||
endif
|
||||
|
|
|
@ -13,6 +13,7 @@ config SND_ATMEL_SOC_PDC
|
|||
config SND_ATMEL_SOC_DMA
|
||||
tristate
|
||||
depends on SND_ATMEL_SOC
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
|
||||
config SND_ATMEL_SOC_SSC
|
||||
tristate
|
||||
|
@ -32,6 +33,26 @@ config SND_AT91_SOC_SAM9G20_WM8731
|
|||
Say Y if you want to add support for SoC audio on WM8731-based
|
||||
AT91sam9g20 evaluation board.
|
||||
|
||||
config SND_ATMEL_SOC_WM8904
|
||||
tristate "Atmel ASoC driver for boards using WM8904 codec"
|
||||
depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
|
||||
select SND_ATMEL_SOC_SSC
|
||||
select SND_ATMEL_SOC_DMA
|
||||
select SND_SOC_WM8904
|
||||
help
|
||||
Say Y if you want to add support for Atmel ASoC driver for boards using
|
||||
WM8904 codec.
|
||||
|
||||
config SND_AT91_SOC_SAM9X5_WM8731
|
||||
tristate "SoC Audio support for WM8731-based at91sam9x5 board"
|
||||
depends on ATMEL_SSC && SND_ATMEL_SOC && SOC_AT91SAM9X5
|
||||
select SND_ATMEL_SOC_SSC
|
||||
select SND_ATMEL_SOC_DMA
|
||||
select SND_SOC_WM8731
|
||||
help
|
||||
Say Y if you want to add support for audio SoC on an
|
||||
at91sam9x5 based board that is using WM8731 codec.
|
||||
|
||||
config SND_AT91_SOC_AFEB9260
|
||||
tristate "SoC Audio support for AFEB9260 board"
|
||||
depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
|
||||
|
|
|
@ -11,6 +11,10 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
|
|||
|
||||
# AT91 Machine Support
|
||||
snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
|
||||
snd-atmel-soc-wm8904-objs := atmel_wm8904.o
|
||||
snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
|
||||
|
||||
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
|
||||
obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
|
||||
obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
|
||||
|
|
|
@ -91,138 +91,52 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
|
|||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
* DMAENGINE operations
|
||||
\*--------------------------------------------------------------------------*/
|
||||
static bool filter(struct dma_chan *chan, void *slave)
|
||||
{
|
||||
struct at_dma_slave *sl = slave;
|
||||
|
||||
if (sl->dma_dev == chan->device->dev) {
|
||||
chan->private = sl;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd)
|
||||
struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct atmel_pcm_dma_params *prtd;
|
||||
struct ssc_device *ssc;
|
||||
struct dma_chan *dma_chan;
|
||||
struct dma_slave_config slave_config;
|
||||
int ret;
|
||||
|
||||
prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
ssc = prtd->ssc;
|
||||
|
||||
ret = snd_hwparams_to_dma_slave_config(substream, params,
|
||||
&slave_config);
|
||||
ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
|
||||
if (ret) {
|
||||
pr_err("atmel-pcm: hwparams to dma slave configure failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR;
|
||||
slave_config.dst_maxburst = 1;
|
||||
slave_config->dst_addr = ssc->phybase + SSC_THR;
|
||||
slave_config->dst_maxburst = 1;
|
||||
} else {
|
||||
slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR;
|
||||
slave_config.src_maxburst = 1;
|
||||
}
|
||||
|
||||
dma_chan = snd_dmaengine_pcm_get_chan(substream);
|
||||
if (dmaengine_slave_config(dma_chan, &slave_config)) {
|
||||
pr_err("atmel-pcm: failed to configure dma channel\n");
|
||||
ret = -EBUSY;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct atmel_pcm_dma_params *prtd;
|
||||
struct ssc_device *ssc;
|
||||
struct at_dma_slave *sdata = NULL;
|
||||
int ret;
|
||||
|
||||
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
||||
|
||||
prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
ssc = prtd->ssc;
|
||||
if (ssc->pdev)
|
||||
sdata = ssc->pdev->dev.platform_data;
|
||||
|
||||
ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata);
|
||||
if (ret) {
|
||||
pr_err("atmel-pcm: dmaengine pcm open failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = atmel_pcm_configure_dma(substream, params, prtd);
|
||||
if (ret) {
|
||||
pr_err("atmel-pcm: failed to configure dmai\n");
|
||||
goto err;
|
||||
slave_config->src_addr = ssc->phybase + SSC_RHR;
|
||||
slave_config->src_maxburst = 1;
|
||||
}
|
||||
|
||||
prtd->dma_intr_handler = atmel_pcm_dma_irq;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
snd_dmaengine_pcm_close_release_chan(substream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct atmel_pcm_dma_params *prtd;
|
||||
|
||||
prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error);
|
||||
ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops atmel_pcm_ops = {
|
||||
.open = atmel_pcm_open,
|
||||
.close = snd_dmaengine_pcm_close_release_chan,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = atmel_pcm_hw_params,
|
||||
.prepare = atmel_pcm_dma_prepare,
|
||||
.trigger = snd_dmaengine_pcm_trigger,
|
||||
.pointer = snd_dmaengine_pcm_pointer_no_residue,
|
||||
.mmap = atmel_pcm_mmap,
|
||||
};
|
||||
|
||||
static struct snd_soc_platform_driver atmel_soc_platform = {
|
||||
.ops = &atmel_pcm_ops,
|
||||
.pcm_new = atmel_pcm_new,
|
||||
.pcm_free = atmel_pcm_free,
|
||||
static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = {
|
||||
.prepare_slave_config = atmel_pcm_configure_dma,
|
||||
.pcm_hardware = &atmel_pcm_dma_hardware,
|
||||
.prealloc_buffer_size = ATMEL_SSC_DMABUF_SIZE,
|
||||
};
|
||||
|
||||
int atmel_pcm_dma_platform_register(struct device *dev)
|
||||
{
|
||||
return snd_soc_register_platform(dev, &atmel_soc_platform);
|
||||
return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config,
|
||||
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
|
||||
}
|
||||
EXPORT_SYMBOL(atmel_pcm_dma_platform_register);
|
||||
|
||||
void atmel_pcm_dma_platform_unregister(struct device *dev)
|
||||
{
|
||||
snd_soc_unregister_platform(dev);
|
||||
snd_dmaengine_pcm_unregister(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister);
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ static struct atmel_ssc_mask ssc_tx_mask = {
|
|||
.ssc_disable = SSC_BIT(CR_TXDIS),
|
||||
.ssc_endx = SSC_BIT(SR_ENDTX),
|
||||
.ssc_endbuf = SSC_BIT(SR_TXBUFE),
|
||||
.ssc_error = SSC_BIT(SR_OVRUN),
|
||||
.pdc_enable = ATMEL_PDC_TXTEN,
|
||||
.pdc_disable = ATMEL_PDC_TXTDIS,
|
||||
};
|
||||
|
@ -82,6 +83,7 @@ static struct atmel_ssc_mask ssc_rx_mask = {
|
|||
.ssc_disable = SSC_BIT(CR_RXDIS),
|
||||
.ssc_endx = SSC_BIT(SR_ENDRX),
|
||||
.ssc_endbuf = SSC_BIT(SR_RXBUFF),
|
||||
.ssc_error = SSC_BIT(SR_OVRUN),
|
||||
.pdc_enable = ATMEL_PDC_RXTEN,
|
||||
.pdc_disable = ATMEL_PDC_RXTDIS,
|
||||
};
|
||||
|
@ -196,15 +198,27 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
|
||||
int dir_mask;
|
||||
struct atmel_pcm_dma_params *dma_params;
|
||||
int dir, dir_mask;
|
||||
|
||||
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
|
||||
ssc_readl(ssc_p->ssc->regs, SR));
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
dir = 0;
|
||||
dir_mask = SSC_DIR_MASK_PLAYBACK;
|
||||
else
|
||||
} else {
|
||||
dir = 1;
|
||||
dir_mask = SSC_DIR_MASK_CAPTURE;
|
||||
}
|
||||
|
||||
dma_params = &ssc_dma_params[dai->id][dir];
|
||||
dma_params->ssc = ssc_p->ssc;
|
||||
dma_params->substream = substream;
|
||||
|
||||
ssc_p->dma_params[dir] = dma_params;
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream, dma_params);
|
||||
|
||||
spin_lock_irq(&ssc_p->lock);
|
||||
if (ssc_p->dir_mask & dir_mask) {
|
||||
|
@ -325,7 +339,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
|
||||
int id = dai->id;
|
||||
struct atmel_ssc_info *ssc_p = &ssc_info[id];
|
||||
struct atmel_pcm_dma_params *dma_params;
|
||||
|
@ -344,19 +357,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
|||
else
|
||||
dir = 1;
|
||||
|
||||
dma_params = &ssc_dma_params[id][dir];
|
||||
dma_params->ssc = ssc_p->ssc;
|
||||
dma_params->substream = substream;
|
||||
|
||||
ssc_p->dma_params[dir] = dma_params;
|
||||
|
||||
/*
|
||||
* The snd_soc_pcm_stream->dma_data field is only used to communicate
|
||||
* the appropriate DMA parameters to the pcm driver hw_params()
|
||||
* function. It should not be used for other purposes
|
||||
* as it is common to all substreams.
|
||||
*/
|
||||
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
|
||||
dma_params = ssc_p->dma_params[dir];
|
||||
|
||||
channels = params_channels(params);
|
||||
|
||||
|
@ -648,6 +649,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
|
|||
dma_params = ssc_p->dma_params[dir];
|
||||
|
||||
ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
|
||||
ssc_writel(ssc_p->ssc->regs, IER, dma_params->mask->ssc_error);
|
||||
|
||||
pr_debug("%s enabled SSC_SR=0x%08x\n",
|
||||
dir ? "receive" : "transmit",
|
||||
|
|
254
sound/soc/atmel/atmel_wm8904.c
Normal file
254
sound/soc/atmel/atmel_wm8904.c
Normal file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* atmel_wm8904 - Atmel ASoC driver for boards with WM8904 codec.
|
||||
*
|
||||
* Copyright (C) 2012 Atmel
|
||||
*
|
||||
* Author: Bo Shen <voice.shen@atmel.com>
|
||||
*
|
||||
* GPLv2 or later
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "../codecs/wm8904.h"
|
||||
#include "atmel_ssc_dai.h"
|
||||
|
||||
#define MCLK_RATE 32768
|
||||
|
||||
static struct clk *mclk;
|
||||
|
||||
static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("Mic", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In Jack", NULL),
|
||||
};
|
||||
|
||||
static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, WM8904_FLL_MCLK, WM8904_FLL_MCLK,
|
||||
32768, params_rate(params) * 256);
|
||||
if (ret < 0) {
|
||||
pr_err("%s - failed to set wm8904 codec PLL.", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* As here wm8904 use FLL output as its system clock
|
||||
* so calling set_sysclk won't care freq parameter
|
||||
* then we pass 0
|
||||
*/
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, WM8904_CLK_FLL,
|
||||
0, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
pr_err("%s -failed to set wm8904 SYSCLK\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops atmel_asoc_wm8904_ops = {
|
||||
.hw_params = atmel_asoc_wm8904_hw_params,
|
||||
};
|
||||
|
||||
static int atmel_set_bias_level(struct snd_soc_card *card,
|
||||
struct snd_soc_dapm_context *dapm,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
clk_prepare_enable(mclk);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
clk_disable_unprepare(mclk);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = {
|
||||
.name = "WM8904",
|
||||
.stream_name = "WM8904 PCM",
|
||||
.codec_dai_name = "wm8904-hifi",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S
|
||||
| SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.ops = &atmel_asoc_wm8904_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_card atmel_asoc_wm8904_card = {
|
||||
.name = "atmel_asoc_wm8904",
|
||||
.owner = THIS_MODULE,
|
||||
.set_bias_level = atmel_set_bias_level,
|
||||
.dai_link = &atmel_asoc_wm8904_dailink,
|
||||
.num_links = 1,
|
||||
.dapm_widgets = atmel_asoc_wm8904_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(atmel_asoc_wm8904_dapm_widgets),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *codec_np, *cpu_np;
|
||||
struct snd_soc_card *card = &atmel_asoc_wm8904_card;
|
||||
struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
|
||||
int ret;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "only device tree supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_of_parse_card_name(card, "atmel,model");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to parse card name\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to parse audio routing\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
|
||||
if (!cpu_np) {
|
||||
dev_err(&pdev->dev, "failed to get dai and pcm info\n");
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
dailink->cpu_of_node = cpu_np;
|
||||
dailink->platform_of_node = cpu_np;
|
||||
of_node_put(cpu_np);
|
||||
|
||||
codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
|
||||
if (!codec_np) {
|
||||
dev_err(&pdev->dev, "failed to get codec info\n");
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
dailink->codec_of_node = codec_np;
|
||||
of_node_put(codec_np);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_asoc_wm8904_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &atmel_asoc_wm8904_card;
|
||||
struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
|
||||
struct clk *clk_src;
|
||||
struct pinctrl *pinctrl;
|
||||
int id, ret;
|
||||
|
||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl)) {
|
||||
dev_err(&pdev->dev, "failed to request pinctrl\n");
|
||||
return PTR_ERR(pinctrl);
|
||||
}
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
ret = atmel_asoc_wm8904_dt_init(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to init dt info\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc");
|
||||
ret = atmel_ssc_set_audio(id);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "failed to set SSC %d for audio\n", id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mclk = clk_get(NULL, "pck0");
|
||||
if (IS_ERR(mclk)) {
|
||||
dev_err(&pdev->dev, "failed to get pck0\n");
|
||||
ret = PTR_ERR(mclk);
|
||||
goto err_set_audio;
|
||||
}
|
||||
|
||||
clk_src = clk_get(NULL, "clk32k");
|
||||
if (IS_ERR(clk_src)) {
|
||||
dev_err(&pdev->dev, "failed to get clk32k\n");
|
||||
ret = PTR_ERR(clk_src);
|
||||
goto err_set_audio;
|
||||
}
|
||||
|
||||
ret = clk_set_parent(mclk, clk_src);
|
||||
clk_put(clk_src);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "failed to set MCLK parent\n");
|
||||
goto err_set_audio;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "setting pck0 to %dHz\n", MCLK_RATE);
|
||||
clk_set_rate(mclk, MCLK_RATE);
|
||||
|
||||
ret = snd_soc_register_card(card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed\n");
|
||||
goto err_set_audio;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_set_audio:
|
||||
atmel_ssc_put_audio(id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_asoc_wm8904_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
|
||||
int id;
|
||||
|
||||
id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc");
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
atmel_ssc_put_audio(id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id atmel_asoc_wm8904_dt_ids[] = {
|
||||
{ .compatible = "atmel,asoc-wm8904", },
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_driver atmel_asoc_wm8904_driver = {
|
||||
.driver = {
|
||||
.name = "atmel-wm8904-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids),
|
||||
},
|
||||
.probe = atmel_asoc_wm8904_probe,
|
||||
.remove = atmel_asoc_wm8904_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(atmel_asoc_wm8904_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
|
||||
MODULE_DESCRIPTION("ALSA SoC machine driver for Atmel EK with WM8904 codec");
|
||||
MODULE_LICENSE("GPL");
|
208
sound/soc/atmel/sam9x5_wm8731.c
Normal file
208
sound/soc/atmel/sam9x5_wm8731.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* sam9x5_wm8731 -- SoC audio for AT91SAM9X5-based boards
|
||||
* that are using WM8731 as codec.
|
||||
*
|
||||
* Copyright (C) 2011 Atmel,
|
||||
* Nicolas Ferre <nicolas.ferre@atmel.com>
|
||||
*
|
||||
* Copyright (C) 2013 Paratronic,
|
||||
* Richard Genoud <richard.genoud@gmail.com>
|
||||
*
|
||||
* Based on sam9g20_wm8731.c by:
|
||||
* Sedji Gaouaou <sedji.gaouaou@atmel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
#include <linux/of.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dai.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
|
||||
#include "../codecs/wm8731.h"
|
||||
#include "atmel_ssc_dai.h"
|
||||
|
||||
|
||||
#define MCLK_RATE 12288000
|
||||
|
||||
#define DRV_NAME "sam9x5-snd-wm8731"
|
||||
|
||||
struct sam9x5_drvdata {
|
||||
int ssc_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* Logic for a wm8731 as connected on a at91sam9x5ek based board.
|
||||
*/
|
||||
static int sam9x5_wm8731_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct device *dev = rtd->dev;
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev, "ASoC: %s called\n", __func__);
|
||||
|
||||
/* set the codec system clock for DAC and ADC */
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
|
||||
MCLK_RATE, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "ASoC: Failed to set WM8731 SYSCLK: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Audio paths on at91sam9x5ek board:
|
||||
*
|
||||
* |A| ------------> | | ---R----> Headphone Jack
|
||||
* |T| <----\ | WM | ---L--/
|
||||
* |9| ---> CLK <--> | 8731 | <--R----- Line In Jack
|
||||
* |1| <------------ | | <--L--/
|
||||
*/
|
||||
static const struct snd_soc_dapm_widget sam9x5_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In Jack", NULL),
|
||||
};
|
||||
|
||||
static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *codec_np, *cpu_np;
|
||||
struct snd_soc_card *card;
|
||||
struct snd_soc_dai_link *dai;
|
||||
struct sam9x5_drvdata *priv;
|
||||
int ret;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "No device node supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);
|
||||
if (!dai || !card || !priv) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
card->owner = THIS_MODULE;
|
||||
card->dai_link = dai;
|
||||
card->num_links = 1;
|
||||
card->dapm_widgets = sam9x5_dapm_widgets;
|
||||
card->num_dapm_widgets = ARRAY_SIZE(sam9x5_dapm_widgets);
|
||||
dai->name = "WM8731";
|
||||
dai->stream_name = "WM8731 PCM";
|
||||
dai->codec_dai_name = "wm8731-hifi";
|
||||
dai->init = sam9x5_wm8731_init;
|
||||
dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM;
|
||||
|
||||
ret = snd_soc_of_parse_card_name(card, "atmel,model");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "atmel,model node missing\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "atmel,audio-routing node missing\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
|
||||
if (!codec_np) {
|
||||
dev_err(&pdev->dev, "atmel,audio-codec node missing\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dai->codec_of_node = codec_np;
|
||||
|
||||
cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
|
||||
if (!cpu_np) {
|
||||
dev_err(&pdev->dev, "atmel,ssc-controller node missing\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
dai->cpu_of_node = cpu_np;
|
||||
dai->platform_of_node = cpu_np;
|
||||
|
||||
priv->ssc_id = of_alias_get_id(cpu_np, "ssc");
|
||||
|
||||
ret = atmel_ssc_set_audio(priv->ssc_id);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"ASoC: Failed to set SSC %d for audio: %d\n",
|
||||
ret, priv->ssc_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
of_node_put(codec_np);
|
||||
of_node_put(cpu_np);
|
||||
|
||||
platform_set_drvdata(pdev, card);
|
||||
|
||||
ret = snd_soc_register_card(card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"ASoC: Platform device allocation failed\n");
|
||||
goto out_put_audio;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "ASoC: %s ok\n", __func__);
|
||||
|
||||
return ret;
|
||||
|
||||
out_put_audio:
|
||||
atmel_ssc_put_audio(priv->ssc_id);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sam9x5_wm8731_driver_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct sam9x5_drvdata *priv = card->drvdata;
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
atmel_ssc_put_audio(priv->ssc_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sam9x5_wm8731_of_match[] = {
|
||||
{ .compatible = "atmel,sam9x5-wm8731-audio", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sam9x5_wm8731_of_match);
|
||||
|
||||
static struct platform_driver sam9x5_wm8731_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(sam9x5_wm8731_of_match),
|
||||
},
|
||||
.probe = sam9x5_wm8731_driver_probe,
|
||||
.remove = sam9x5_wm8731_driver_remove,
|
||||
};
|
||||
module_platform_driver(sam9x5_wm8731_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
|
||||
MODULE_AUTHOR("Richard Genoud <richard.genoud@gmail.com>");
|
||||
MODULE_DESCRIPTION("ALSA SoC machine driver for AT91SAM9x5 - WM8731");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
|
@ -73,12 +73,14 @@ static struct snd_soc_dai_link db1300_ac97_dai = {
|
|||
|
||||
static struct snd_soc_card db1300_ac97_machine = {
|
||||
.name = "DB1300_AC97",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &db1300_ac97_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static struct snd_soc_card db1550_ac97_machine = {
|
||||
.name = "DB1550_AC97",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &db1200_ac97_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
@ -145,6 +147,7 @@ static struct snd_soc_dai_link db1300_i2s_dai = {
|
|||
|
||||
static struct snd_soc_card db1300_i2s_machine = {
|
||||
.name = "DB1300_I2S",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &db1300_i2s_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
@ -161,6 +164,7 @@ static struct snd_soc_dai_link db1550_i2s_dai = {
|
|||
|
||||
static struct snd_soc_card db1550_i2s_machine = {
|
||||
.name = "DB1550_I2S",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &db1550_i2s_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
|
|
@ -379,9 +379,6 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
|||
mutex_init(&wd->lock);
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iores)
|
||||
return -ENODEV;
|
||||
|
||||
wd->mmio = devm_ioremap_resource(&pdev->dev, iores);
|
||||
if (IS_ERR(wd->mmio))
|
||||
return PTR_ERR(wd->mmio);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#ifndef _BF5XX_AC97_H
|
||||
#define _BF5XX_AC97_H
|
||||
|
||||
extern struct snd_ac97 *ac97;
|
||||
/* Frame format in memory, only support stereo currently */
|
||||
struct ac97_frame {
|
||||
u16 ac97_tag; /* slot 0 */
|
||||
|
|
|
@ -363,9 +363,6 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
info->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(info->regs))
|
||||
return PTR_ERR(info->regs);
|
||||
|
|
|
@ -376,9 +376,6 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
info->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(info->regs))
|
||||
return PTR_ERR(info->regs);
|
||||
|
@ -411,7 +408,6 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
fail_put_lrclk:
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
clk_put(info->lrclk);
|
||||
fail_put_sclk:
|
||||
clk_put(info->sclk);
|
||||
|
@ -426,7 +422,6 @@ static int ep93xx_i2s_remove(struct platform_device *pdev)
|
|||
struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
clk_put(info->lrclk);
|
||||
clk_put(info->sclk);
|
||||
clk_put(info->mclk);
|
||||
|
|
|
@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI
|
|||
|
||||
config SND_SOC_ALL_CODECS
|
||||
tristate "Build all ASoC CODEC drivers"
|
||||
depends on COMPILE_TEST
|
||||
select SND_SOC_88PM860X if MFD_88PM860X
|
||||
select SND_SOC_L3
|
||||
select SND_SOC_AB8500_CODEC if ABX500_CORE
|
||||
|
@ -20,6 +21,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_AD73311
|
||||
select SND_SOC_ADAU1373 if I2C
|
||||
select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_ADAU1701 if I2C
|
||||
select SND_SOC_ADS117X
|
||||
select SND_SOC_AK4104 if SPI_MASTER
|
||||
select SND_SOC_AK4535 if I2C
|
||||
|
@ -54,6 +56,8 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_MC13783 if MFD_MC13XXX
|
||||
select SND_SOC_ML26124 if I2C
|
||||
select SND_SOC_HDMI_CODEC
|
||||
select SND_SOC_PCM1681 if I2C
|
||||
select SND_SOC_PCM1792A if SPI_MASTER
|
||||
select SND_SOC_PCM3008
|
||||
select SND_SOC_RT5631 if I2C
|
||||
select SND_SOC_RT5640 if I2C
|
||||
|
@ -122,6 +126,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_WM8994 if MFD_WM8994
|
||||
select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8996 if I2C
|
||||
select SND_SOC_WM8997 if MFD_WM8997
|
||||
select SND_SOC_WM9081 if I2C
|
||||
select SND_SOC_WM9090 if I2C
|
||||
select SND_SOC_WM9705 if SND_SOC_AC97_BUS
|
||||
|
@ -145,8 +150,10 @@ config SND_SOC_ARIZONA
|
|||
tristate
|
||||
default y if SND_SOC_WM5102=y
|
||||
default y if SND_SOC_WM5110=y
|
||||
default y if SND_SOC_WM8997=y
|
||||
default m if SND_SOC_WM5102=m
|
||||
default m if SND_SOC_WM5110=m
|
||||
default m if SND_SOC_WM8997=m
|
||||
|
||||
config SND_SOC_WM_HUBS
|
||||
tristate
|
||||
|
@ -198,6 +205,9 @@ config SND_SOC_AK4104
|
|||
config SND_SOC_AK4535
|
||||
tristate
|
||||
|
||||
config SND_SOC_AK4554
|
||||
tristate
|
||||
|
||||
config SND_SOC_AK4641
|
||||
tristate
|
||||
|
||||
|
@ -292,6 +302,12 @@ config SND_SOC_MAX9850
|
|||
config SND_SOC_HDMI_CODEC
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM1681
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM1792A
|
||||
tristate
|
||||
|
||||
config SND_SOC_PCM3008
|
||||
tristate
|
||||
|
||||
|
@ -500,6 +516,9 @@ config SND_SOC_WM8995
|
|||
config SND_SOC_WM8996
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM8997
|
||||
tristate
|
||||
|
||||
config SND_SOC_WM9081
|
||||
tristate
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ snd-soc-adav80x-objs := adav80x.o
|
|||
snd-soc-ads117x-objs := ads117x.o
|
||||
snd-soc-ak4104-objs := ak4104.o
|
||||
snd-soc-ak4535-objs := ak4535.o
|
||||
snd-soc-ak4554-objs := ak4554.o
|
||||
snd-soc-ak4641-objs := ak4641.o
|
||||
snd-soc-ak4642-objs := ak4642.o
|
||||
snd-soc-ak4671-objs := ak4671.o
|
||||
|
@ -42,6 +43,8 @@ snd-soc-max9850-objs := max9850.o
|
|||
snd-soc-mc13783-objs := mc13783.o
|
||||
snd-soc-ml26124-objs := ml26124.o
|
||||
snd-soc-hdmi-codec-objs := hdmi.o
|
||||
snd-soc-pcm1681-objs := pcm1681.o
|
||||
snd-soc-pcm1792a-codec-objs := pcm1792a.o
|
||||
snd-soc-pcm3008-objs := pcm3008.o
|
||||
snd-soc-rt5631-objs := rt5631.o
|
||||
snd-soc-rt5640-objs := rt5640.o
|
||||
|
@ -114,6 +117,7 @@ snd-soc-wm8991-objs := wm8991.o
|
|||
snd-soc-wm8993-objs := wm8993.o
|
||||
snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o
|
||||
snd-soc-wm8995-objs := wm8995.o
|
||||
snd-soc-wm8997-objs := wm8997.o
|
||||
snd-soc-wm9081-objs := wm9081.o
|
||||
snd-soc-wm9090-objs := wm9090.o
|
||||
snd-soc-wm9705-objs := wm9705.o
|
||||
|
@ -138,6 +142,7 @@ obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
|
|||
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
|
||||
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
|
||||
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
|
||||
obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o
|
||||
obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o
|
||||
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
|
||||
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
|
||||
|
@ -171,6 +176,8 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
|
|||
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
|
||||
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
|
||||
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
|
||||
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
|
||||
obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
|
||||
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
|
||||
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
|
||||
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
|
||||
|
@ -239,6 +246,7 @@ obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o
|
|||
obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
|
||||
obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o
|
||||
obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o
|
||||
obj-$(CONFIG_SND_SOC_WM8997) += snd-soc-wm8997.o
|
||||
obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o
|
||||
obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o
|
||||
obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
|
||||
|
|
|
@ -23,6 +23,16 @@
|
|||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
static const struct snd_soc_dapm_widget ac97_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("RX"),
|
||||
SND_SOC_DAPM_OUTPUT("TX"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ac97_routes[] = {
|
||||
{ "AC97 Capture", NULL, "RX" },
|
||||
{ "TX", NULL, "AC97 Playback" },
|
||||
};
|
||||
|
||||
static int ac97_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
|
@ -117,6 +127,11 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
|
|||
.probe = ac97_soc_probe,
|
||||
.suspend = ac97_soc_suspend,
|
||||
.resume = ac97_soc_resume,
|
||||
|
||||
.dapm_widgets = ac97_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ac97_widgets),
|
||||
.dapm_routes = ac97_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ac97_routes),
|
||||
};
|
||||
|
||||
static int ac97_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -96,6 +96,44 @@ SOC_ENUM("Capture Source", ad1980_cap_src),
|
|||
SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ad1980_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("MIC1"),
|
||||
SND_SOC_DAPM_INPUT("MIC2"),
|
||||
SND_SOC_DAPM_INPUT("CD_L"),
|
||||
SND_SOC_DAPM_INPUT("CD_R"),
|
||||
SND_SOC_DAPM_INPUT("AUX_L"),
|
||||
SND_SOC_DAPM_INPUT("AUX_R"),
|
||||
SND_SOC_DAPM_INPUT("LINE_IN_L"),
|
||||
SND_SOC_DAPM_INPUT("LINE_IN_R"),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("LFE_OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("CENTER_OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("LINE_OUT_L"),
|
||||
SND_SOC_DAPM_OUTPUT("LINE_OUT_R"),
|
||||
SND_SOC_DAPM_OUTPUT("MONO_OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("HP_OUT_L"),
|
||||
SND_SOC_DAPM_OUTPUT("HP_OUT_R"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ad1980_dapm_routes[] = {
|
||||
{ "Capture", NULL, "MIC1" },
|
||||
{ "Capture", NULL, "MIC2" },
|
||||
{ "Capture", NULL, "CD_L" },
|
||||
{ "Capture", NULL, "CD_R" },
|
||||
{ "Capture", NULL, "AUX_L" },
|
||||
{ "Capture", NULL, "AUX_R" },
|
||||
{ "Capture", NULL, "LINE_IN_L" },
|
||||
{ "Capture", NULL, "LINE_IN_R" },
|
||||
|
||||
{ "LFE_OUT", NULL, "Playback" },
|
||||
{ "CENTER_OUT", NULL, "Playback" },
|
||||
{ "LINE_OUT_L", NULL, "Playback" },
|
||||
{ "LINE_OUT_R", NULL, "Playback" },
|
||||
{ "MONO_OUT", NULL, "Playback" },
|
||||
{ "HP_OUT_L", NULL, "Playback" },
|
||||
{ "HP_OUT_R", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static unsigned int ac97_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
|
@ -253,6 +291,11 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
|
|||
.reg_cache_step = 2,
|
||||
.write = ac97_write,
|
||||
.read = ac97_read,
|
||||
|
||||
.dapm_widgets = ad1980_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
|
||||
.dapm_routes = ad1980_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes),
|
||||
};
|
||||
|
||||
static int ad1980_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -23,6 +23,21 @@
|
|||
|
||||
#include "ad73311.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget ad73311_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("VINP"),
|
||||
SND_SOC_DAPM_INPUT("VINN"),
|
||||
SND_SOC_DAPM_OUTPUT("VOUTN"),
|
||||
SND_SOC_DAPM_OUTPUT("VOUTP"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ad73311_dapm_routes[] = {
|
||||
{ "Capture", NULL, "VINP" },
|
||||
{ "Capture", NULL, "VINN" },
|
||||
|
||||
{ "VOUTN", NULL, "Playback" },
|
||||
{ "VOUTP", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ad73311_dai = {
|
||||
.name = "ad73311-hifi",
|
||||
.playback = {
|
||||
|
@ -39,7 +54,12 @@ static struct snd_soc_dai_driver ad73311_dai = {
|
|||
.formats = SNDRV_PCM_FMTBIT_S16_LE, },
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad73311;
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
|
||||
.dapm_widgets = ad73311_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets),
|
||||
.dapm_routes = ad73311_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ad73311_dapm_routes),
|
||||
};
|
||||
|
||||
static int ad73311_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
#define ADAU1701_OSCIPOW_OPD 0x04
|
||||
#define ADAU1701_DACSET_DACINIT 1
|
||||
|
||||
#define ADAU1707_CLKDIV_UNSET (-1UL)
|
||||
#define ADAU1707_CLKDIV_UNSET (-1U)
|
||||
|
||||
#define ADAU1701_FIRMWARE "adau1701.bin"
|
||||
|
||||
|
@ -247,21 +247,21 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
|
|||
gpio_is_valid(adau1701->gpio_pll_mode[1])) {
|
||||
switch (clkdiv) {
|
||||
case 64:
|
||||
gpio_set_value(adau1701->gpio_pll_mode[0], 0);
|
||||
gpio_set_value(adau1701->gpio_pll_mode[1], 0);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
|
||||
break;
|
||||
case 256:
|
||||
gpio_set_value(adau1701->gpio_pll_mode[0], 0);
|
||||
gpio_set_value(adau1701->gpio_pll_mode[1], 1);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1);
|
||||
break;
|
||||
case 384:
|
||||
gpio_set_value(adau1701->gpio_pll_mode[0], 1);
|
||||
gpio_set_value(adau1701->gpio_pll_mode[1], 0);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
|
||||
break;
|
||||
case 0: /* fallback */
|
||||
case 512:
|
||||
gpio_set_value(adau1701->gpio_pll_mode[0], 1);
|
||||
gpio_set_value(adau1701->gpio_pll_mode[1], 1);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1);
|
||||
gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -269,10 +269,10 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
|
|||
adau1701->pll_clkdiv = clkdiv;
|
||||
|
||||
if (gpio_is_valid(adau1701->gpio_nreset)) {
|
||||
gpio_set_value(adau1701->gpio_nreset, 0);
|
||||
gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
|
||||
/* minimum reset time is 20ns */
|
||||
udelay(1);
|
||||
gpio_set_value(adau1701->gpio_nreset, 1);
|
||||
gpio_set_value_cansleep(adau1701->gpio_nreset, 1);
|
||||
/* power-up time may be as long as 85ms */
|
||||
mdelay(85);
|
||||
}
|
||||
|
@ -734,7 +734,10 @@ static int adau1701_i2c_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id adau1701_i2c_id[] = {
|
||||
{ "adau1401", 0 },
|
||||
{ "adau1401a", 0 },
|
||||
{ "adau1701", 0 },
|
||||
{ "adau1702", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
|
||||
|
|
|
@ -868,6 +868,12 @@ static int adav80x_bus_remove(struct device *dev)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static const struct spi_device_id adav80x_spi_id[] = {
|
||||
{ "adav801", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
|
||||
|
||||
static int adav80x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
return adav80x_bus_probe(&spi->dev, SND_SOC_SPI);
|
||||
|
@ -885,15 +891,16 @@ static struct spi_driver adav80x_spi_driver = {
|
|||
},
|
||||
.probe = adav80x_spi_probe,
|
||||
.remove = adav80x_spi_remove,
|
||||
.id_table = adav80x_spi_id,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static const struct i2c_device_id adav80x_id[] = {
|
||||
static const struct i2c_device_id adav80x_i2c_id[] = {
|
||||
{ "adav803", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adav80x_id);
|
||||
MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id);
|
||||
|
||||
static int adav80x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
|
@ -913,7 +920,7 @@ static struct i2c_driver adav80x_i2c_driver = {
|
|||
},
|
||||
.probe = adav80x_i2c_probe,
|
||||
.remove = adav80x_i2c_remove,
|
||||
.id_table = adav80x_id,
|
||||
.id_table = adav80x_i2c_id,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -23,6 +23,28 @@
|
|||
#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
|
||||
#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
|
||||
|
||||
static const struct snd_soc_dapm_widget ads117x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("Input1"),
|
||||
SND_SOC_DAPM_INPUT("Input2"),
|
||||
SND_SOC_DAPM_INPUT("Input3"),
|
||||
SND_SOC_DAPM_INPUT("Input4"),
|
||||
SND_SOC_DAPM_INPUT("Input5"),
|
||||
SND_SOC_DAPM_INPUT("Input6"),
|
||||
SND_SOC_DAPM_INPUT("Input7"),
|
||||
SND_SOC_DAPM_INPUT("Input8"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ads117x_dapm_routes[] = {
|
||||
{ "Capture", NULL, "Input1" },
|
||||
{ "Capture", NULL, "Input2" },
|
||||
{ "Capture", NULL, "Input3" },
|
||||
{ "Capture", NULL, "Input4" },
|
||||
{ "Capture", NULL, "Input5" },
|
||||
{ "Capture", NULL, "Input6" },
|
||||
{ "Capture", NULL, "Input7" },
|
||||
{ "Capture", NULL, "Input8" },
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver ads117x_dai = {
|
||||
/* ADC */
|
||||
.name = "ads117x-hifi",
|
||||
|
@ -34,7 +56,12 @@ static struct snd_soc_dai_driver ads117x_dai = {
|
|||
.formats = ADS117X_FORMATS,},
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ads117x;
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ads117x = {
|
||||
.dapm_widgets = ads117x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets),
|
||||
.dapm_routes = ads117x_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ads117x_dapm_routes),
|
||||
};
|
||||
|
||||
static int ads117x_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,17 @@ struct ak4104_private {
|
|||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_PGA("TXE", AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("TX"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route ak4104_dapm_routes[] = {
|
||||
{ "TXE", NULL, "Playback" },
|
||||
{ "TX", NULL, "TXE" },
|
||||
};
|
||||
|
||||
static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int format)
|
||||
{
|
||||
|
@ -138,29 +149,11 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* enable transmitter */
|
||||
ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
|
||||
AK4104_TX_TXE, AK4104_TX_TXE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4104_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* disable transmitter */
|
||||
return regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
|
||||
AK4104_TX_TXE, 0);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops ak4101_dai_ops = {
|
||||
.hw_params = ak4104_hw_params,
|
||||
.hw_free = ak4104_hw_free,
|
||||
.set_fmt = ak4104_set_dai_fmt,
|
||||
};
|
||||
|
||||
|
@ -214,6 +207,11 @@ static int ak4104_remove(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
|
||||
.probe = ak4104_probe,
|
||||
.remove = ak4104_remove,
|
||||
|
||||
.dapm_widgets = ak4104_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
|
||||
.dapm_routes = ak4104_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes),
|
||||
};
|
||||
|
||||
static const struct regmap_config ak4104_regmap = {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue