Merge branch 'asoc-4.21' into asoc-next

This commit is contained in:
Mark Brown 2018-12-18 12:23:59 +00:00
commit a7a850dba8
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
188 changed files with 9580 additions and 4005 deletions

View File

@ -12,8 +12,8 @@ Required properties:
Optional properties:
- reset-gpio : a GPIO spec for the reset pin. If specified, it will be
deasserted before communication to the device starts.
- reset-gpios : a GPIO spec for the reset pin. If specified, it will be
deasserted before communication to the device starts.
Example:

View File

@ -0,0 +1,22 @@
AK4118 S/PDIF transceiver
This device supports I2C mode.
Required properties:
- compatible : "asahi-kasei,ak4118"
- reg : The I2C address of the device for I2C
- reset-gpios: A GPIO specifier for the reset pin
- irq-gpios: A GPIO specifier for the IRQ pin
Example:
&i2c {
ak4118: ak4118@13 {
#sound-dai-cells = <0>;
compatible = "asahi-kasei,ak4118";
reg = <0x13>;
reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>
irq-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -0,0 +1,22 @@
* Amlogic Audio SPDIF Input
Required properties:
- compatible: 'amlogic,axg-spdifin'
- interrupts: interrupt specifier for the spdif input.
- clocks: list of clock phandle, one for each entry clock-names.
- clock-names: should contain the following:
* "pclk" : peripheral clock.
* "refclk" : spdif input reference clock
- #sound-dai-cells: must be 0.
Example on the A113 SoC:
spdifin: audio-controller@400 {
compatible = "amlogic,axg-spdifin";
reg = <0x0 0x400 0x0 0x30>;
#sound-dai-cells = <0>;
interrupts = <GIC_SPI 87 IRQ_TYPE_EDGE_RISING>;
clocks = <&clkc_audio AUD_CLKID_SPDIFIN>,
<&clkc_audio AUD_CLKID_SPDIFIN_CLK>;
clock-names = "pclk", "refclk";
};

View File

@ -32,7 +32,9 @@ Required properties:
Optional properties:
- pa-gpios: GPIO used to control external amplifier.
-----------------------
Example: Single DAI case
-----------------------
sound_card {
compatible = "audio-graph-card";
@ -61,7 +63,9 @@ Example: Single DAI case
};
};
-----------------------
Example: Multi DAI case
-----------------------
sound-card {
compatible = "audio-graph-card";
@ -130,3 +134,204 @@ Example: Multi DAI case
};
};
-----------------------
Example: Sampling Rate Conversion
-----------------------
sound_card {
compatible = "audio-graph-card";
label = "sound-card";
prefix = "codec";
routing = "codec Playback", "DAI0 Playback",
"DAI0 Capture", "codec Capture";
convert-rate = <48000>;
dais = <&cpu_port>;
};
audio-codec {
...
port {
codec_endpoint: endpoint {
remote-endpoint = <&cpu_endpoint>;
};
};
};
dai-controller {
...
cpu_port: port {
cpu_endpoint: endpoint {
remote-endpoint = <&codec_endpoint>;
dai-format = "left_j";
...
};
};
};
-----------------------
Example: 2 CPU 1 Codec (Mixing)
-----------------------
sound_card {
compatible = "audio-graph-card";
label = "sound-card";
routing = "codec Playback", "DAI0 Playback",
"codec Playback", "DAI1 Playback",
"DAI0 Capture", "codec Capture";
dais = <&cpu_port>;
};
audio-codec {
...
audio-graph-card,prefix = "codec";
audio-graph-card,convert-rate = <48000>;
port {
reg = <0>;
codec_endpoint0: endpoint@0 {
remote-endpoint = <&cpu_endpoint0>;
};
codec_endpoint1: endpoint@1 {
remote-endpoint = <&cpu_endpoint1>;
};
};
};
dai-controller {
...
cpu_port: port {
cpu_endpoint0: endpoint@0 {
remote-endpoint = <&codec_endpoint0>;
dai-format = "left_j";
...
};
cpu_endpoint1: endpoint@1 {
remote-endpoint = <&codec_endpoint1>;
dai-format = "left_j";
...
};
};
};
-----------------------
Example: Multi DAI with DPCM
-----------------------
CPU0 ------ ak4613
CPU1 ------ HDMI
CPU2 ------ PCM3168A-p /* DPCM 1ch/2ch */
CPU3 --/ /* DPCM 3ch/4ch */
CPU4 --/ /* DPCM 5ch/6ch */
CPU5 --/ /* DPCM 7ch/8ch */
CPU6 ------ PCM3168A-c
sound_card: sound {
compatible = "audio-graph-card";
label = "sound-card";
routing = "pcm3168a Playback", "DAI2 Playback",
"pcm3168a Playback", "DAI3 Playback",
"pcm3168a Playback", "DAI4 Playback",
"pcm3168a Playback", "DAI5 Playback";
dais = <&snd_port0 /* ak4613 */
&snd_port1 /* HDMI0 */
&snd_port2 /* pcm3168a playback */
&snd_port3 /* pcm3168a capture */
>;
};
ak4613: codec@10 {
...
port {
ak4613_endpoint: endpoint {
remote-endpoint = <&rsnd_endpoint0>;
};
};
};
pcm3168a: audio-codec@44 {
...
audio-graph-card,prefix = "pcm3168a";
audio-graph-card,convert-channels = <8>; /* TDM Split */
ports {
port@0 {
reg = <0>;
pcm3168a_endpoint_p1: endpoint@1 {
remote-endpoint = <&rsnd_endpoint2>;
...
};
pcm3168a_endpoint_p2: endpoint@2 {
remote-endpoint = <&rsnd_endpoint3>;
...
};
pcm3168a_endpoint_p3: endpoint@3 {
remote-endpoint = <&rsnd_endpoint4>;
...
};
pcm3168a_endpoint_p4: endpoint@4 {
remote-endpoint = <&rsnd_endpoint5>;
...
};
};
port@1 {
reg = <1>;
pcm3168a_endpoint_c: endpoint {
remote-endpoint = <&rsnd_endpoint6>;
...
};
};
};
};
&sound {
ports {
snd_port0: port@0 {
rsnd_endpoint0: endpoint {
remote-endpoint = <&ak4613_endpoint>;
...
};
};
snd_port1: port@1 {
rsnd_endpoint1: endpoint {
remote-endpoint = <&dw_hdmi0_snd_in>;
...
};
};
snd_port2: port@2 {
#address-cells = <1>;
#size-cells = <0>;
rsnd_endpoint2: endpoint@2 {
remote-endpoint = <&pcm3168a_endpoint_p1>;
...
};
rsnd_endpoint3: endpoint@3 {
remote-endpoint = <&pcm3168a_endpoint_p2>;
...
};
rsnd_endpoint4: endpoint@4 {
remote-endpoint = <&pcm3168a_endpoint_p3>;
...
};
rsnd_endpoint5: endpoint@5 {
remote-endpoint = <&pcm3168a_endpoint_p4>;
...
};
};
snd_port3: port@6 {
rsnd_endpoint6: endpoint {
remote-endpoint = <&pcm3168a_endpoint_c>;
...
};
};
};
};

View File

@ -77,11 +77,9 @@ Example 2. 2 CPU 1 Codec (Mixing)
compatible = "audio-graph-scu-card";
label = "sound-card";
prefix = "codec";
routing = "codec Playback", "DAI0 Playback",
"codec Playback", "DAI1 Playback",
"DAI0 Capture", "codec Capture";
convert-rate = <48000>;
dais = <&cpu_port0
&cpu_port1>;
@ -90,6 +88,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
audio-codec {
...
audio-graph-card,prefix = "codec";
audio-graph-card,convert-rate = <48000>;
port {
codec_endpoint0: endpoint {
remote-endpoint = <&cpu_endpoint0>;

View File

@ -10,8 +10,8 @@ Required properties:
Optional properties:
- reset-gpio : a GPIO spec for the reset pin. If specified, it will be
deasserted before communication to the codec starts.
- reset-gpios : a GPIO spec for the reset pin. If specified, it will be
deasserted before communication to the codec starts.
Example:

View File

@ -30,6 +30,11 @@ Optional properties:
- ti,hwmods : Must be "mcasp<n>", n is controller instance starting 0
- tx-num-evt : FIFO levels.
- rx-num-evt : FIFO levels.
- dismod : Specify the drive on TX pin during inactive slots
0 : 3-state
2 : logic low
3 : logic high
Defaults to 'logic low' when the property is not present
- sram-size-playback : size of sram to be allocated during playback
- sram-size-capture : size of sram to be allocated during capture
- interrupts : Interrupt numbers for McASP

View File

@ -9,6 +9,7 @@ Optional properties:
- dmicen-gpios: GPIO specifier for dmic to control start and stop
- num-channels: Number of microphones on this DAI
- wakeup-delay-ms: Delay (in ms) after enabling the DMIC
- modeswitch-delay-ms: Delay (in ms) to complete DMIC mode switch
Example node:
@ -17,4 +18,5 @@ Example node:
dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
num-channels = <1>;
wakeup-delay-ms <50>;
modeswitch-delay-ms <35>;
};

View File

@ -35,13 +35,13 @@ Required properties:
- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
that SAI will work in the synchronous mode (sync Tx
with Rx) which means both the transimitter and the
with Rx) which means both the transmitter and the
receiver will send and receive data by following
receiver's bit clocks and frame sync clocks.
- fsl,sai-asynchronous: This is a boolean property. If present, indicating
that SAI will work in the asynchronous mode, which
means both transimitter and receiver will send and
means both transmitter and receiver will send and
receive data by following their own bit clocks and
frame sync clocks separately.
@ -58,8 +58,8 @@ Optional properties (for mx6ul):
Note:
- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
default synchronous mode (sync Rx with Tx) will be used, which means both
transimitter and receiver will send and receive data by following clocks
of transimitter.
transmitter and receiver will send and receive data by following clocks
of transmitter.
- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive.
Example:

View File

@ -7,6 +7,8 @@ Required properties:
<L3 interconnect address, size>;
- interrupts: Interrupt number for McPDM
- ti,hwmods: Name of the hwmod associated to the McPDM
- clocks: phandle for the pdmclk provider, likely <&twl6040>
- clock-names: Must be "pdmclk"
Example:
@ -18,3 +20,11 @@ mcpdm: mcpdm@40132000 {
interrupt-parent = <&gic>;
ti,hwmods = "mcpdm";
};
In board DTS file the pdmclk needs to be added:
&mcpdm {
clocks = <&twl6040>;
clock-names = "pdmclk";
status = "okay";
};

View File

@ -9,9 +9,15 @@ Required properties:
- reg : the I2C address of the device for I2C, the chip select
number for SPI.
Optional properties:
- ti,out-single-ended: "true" if output is single-ended;
"false" or not specified if output is differential.
Examples:
pcm3060: pcm3060@46 {
compatible = "ti,pcm3060";
reg = <0x46>;
ti,out-single-ended = "true";
};

View File

@ -27,6 +27,28 @@ used by the apr service device.
Value type: <u32>
Definition: Must be 1
== ASM DAI is subnode of "dais" and represent a dai, it includes board specific
configuration of each dai. Must contain the following properties.
- reg
Usage: required
Value type: <u32>
Definition: Must be dai id
- direction:
Usage: Required for Compress offload dais
Value type: <u32>
Definition: Specifies the direction of the dai stream
0 for both tx and rx
1 for only tx (Capture/Encode)
2 for only rx (Playback/Decode)
- is-compress-dai:
Usage: Required for Compress offload dais
Value type: <boolean>
Definition: present for Compress offload dais
= EXAMPLE
q6asm@7 {
@ -35,5 +57,10 @@ q6asm@7 {
q6asmdai: dais {
compatible = "qcom,q6asm-dais";
#sound-dai-cells = <1>;
mm@0 {
reg = <0>;
direction = <2>;
is-compress-dai;
};
};
};

View File

@ -39,15 +39,7 @@ This is example of
Playback: [MEM] -> [SRC2] -> [DVC0] -> [SSIU0/SSI0] -> [codec]
Capture: [MEM] <- [DVC1] <- [SRC3] <- [SSIU1/SSI1] <- [codec]
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&ssi0 &src2 &dvc0>;
capture = <&ssi1 &src3 &dvc1>;
};
};
};
see "Example: simple sound card"
You can use below.
${LINUX}/arch/arm/boot/dts/r8a7790.dts can be good example.
@ -83,29 +75,8 @@ SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
** Asynchronous mode
------------------
You need to use "simple-scu-audio-card" sound card for it.
example)
sound {
compatible = "simple-scu-audio-card";
...
/*
* SRC Asynchronous mode setting
* Playback:
* All input data will be converted to 48kHz
* Capture:
* Inputed 48kHz data will be converted to
* system specified Hz
*/
simple-audio-card,convert-rate = <48000>;
...
simple-audio-card,cpu {
sound-dai = <&rcar_sound>;
};
simple-audio-card,codec {
...
};
};
You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
see "Example: simple sound card for Asynchronous mode"
------------------
** Synchronous mode
@ -141,26 +112,8 @@ For more detail information, see below
${LINUX}/sound/soc/sh/rcar/ctu.c
- comment of header
You need to use "simple-scu-audio-card" sound card for it.
example)
sound {
compatible = "simple-scu-audio-card";
...
/*
* CTU setting
* All input data will be converted to 2ch
* as output data
*/
simple-audio-card,convert-channels = <2>;
...
simple-audio-card,cpu {
sound-dai = <&rcar_sound>;
};
simple-audio-card,codec {
...
};
};
You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
see "Example: simple sound card for channel convert"
Ex) Exchange output channel
Input -> Output
@ -190,42 +143,13 @@ and these sounds will be merged by MIX.
aplay -D plughw:0,0 xxxx.wav &
aplay -D plughw:0,1 yyyy.wav
You need to use "simple-scu-audio-card" sound card for it.
You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
Ex)
[MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
|
[MEM] -> [SRC2] -> [CTU03] -+
sound {
#address-cells = <1>;
#size-cells = <0>;
compatible = "simple-scu-audio-card";
...
simple-audio-card,cpu@0 {
reg = <0>;
sound-dai = <&rcar_sound 0>;
};
simple-audio-card,cpu@1 {
reg = <1>;
sound-dai = <&rcar_sound 1>;
};
simple-audio-card,codec {
...
};
};
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
};
dai1 {
playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
};
};
};
see "Example: simple sound card for MIXer"
=============================================
* DVC (Digital Volume and Mute Function)
@ -257,15 +181,31 @@ Volume Ramp
* SSIU (Serial Sound Interface Unit)
=============================================
There is no DT settings for SSIU, because SSIU will be automatically
selected via SSI.
SSIU can avoid some under/over run error, because it has some buffer.
But you can't use it if SSI was PIO mode.
In DMA mode, you can select not to use SSIU by using "no-busif" on DT.
In DMA mode, you can select not to use SSIU by using "no-busif" via SSI.
&ssi0 {
no-busif;
};
SSIU handles BUSIF which will be used for TDM Split mode.
This driver is assuming that audio-graph card will be used.
TDM Split mode merges 4 sounds. You can see 4 sound interface on system,
and these sounds will be merged SSIU/SSI.
aplay -D plughw:0,0 xxxx.wav &
aplay -D plughw:0,1 xxxx.wav &
aplay -D plughw:0,2 xxxx.wav &
aplay -D plughw:0,3 xxxx.wav
2ch 8ch
[MEM] -> [SSIU 30] -+-> [SSIU 3] --> [Codec]
2ch |
[MEM] -> [SSIU 31] -+
2ch |
[MEM] -> [SSIU 32] -+
2ch |
[MEM] -> [SSIU 33] -+
see "Example: simple sound card for TDM Split"
=============================================
* SSI (Serial Sound Interface)
@ -304,14 +244,7 @@ This is example if SSI1 want to share WS pin with SSI0
You can use Multi-SSI.
This is example of SSI0/SSI1/SSI2 (= for 6ch)
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
};
};
};
see "Example: simple sound card for Multi channel"
** TDM-SSI
@ -319,19 +252,7 @@ You can use TDM with SSI.
This is example of TDM 6ch.
Driver can automatically switches TDM <-> stereo mode in this case.
rsnd_tdm: sound {
compatible = "simple-audio-card";
...
simple-audio-card,cpu {
/* system can use TDM 6ch */
dai-tdm-slot-num = <6>;
sound-dai = <&rcar_sound>;
};
simple-audio-card,codec {
...
};
};
see "Example: simple sound card for TDM"
=============================================
Required properties:
@ -346,6 +267,7 @@ Required properties:
- "renesas,rcar_sound-r8a7744" (RZ/G1N)
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
- "renesas,rcar_sound-r8a774a1" (RZ/G2M)
- "renesas,rcar_sound-r8a774c0" (RZ/G2E)
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
- "renesas,rcar_sound-r8a7779" (R-Car H1)
- "renesas,rcar_sound-r8a7790" (R-Car H2)
@ -356,6 +278,7 @@ Required properties:
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
- "renesas,rcar_sound-r8a77965" (R-Car M3-N)
- "renesas,rcar_sound-r8a77990" (R-Car E3)
- "renesas,rcar_sound-r8a77995" (R-Car D3)
- reg : Should contain the register physical address.
required register is
SRU/ADG/SSI if generation1
@ -363,6 +286,9 @@ Required properties:
- rcar_sound,ssi : Should contain SSI feature.
The number of SSI subnode should be same as HW.
see below for detail.
- rcar_sound,ssiu : Should contain SSIU feature.
The number of SSIU subnode should be same as HW.
see below for detail.
- rcar_sound,src : Should contain SRC feature.
The number of SRC subnode should be same as HW.
see below for detail.
@ -402,8 +328,13 @@ SSI subnode properties:
- no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case
- dma : Should contain Audio DMAC entry
- dma-names : SSI case "rx" (=playback), "tx" (=capture)
Deprecated: see SSIU subnode properties
SSIU case "rxu" (=playback), "txu" (=capture)
SSIU subnode properties:
- dma : Should contain Audio DMAC entry
- dma-names : "rx" (=playback), "tx" (=capture)
SRC subnode properties:
- dma : Should contain Audio DMAC entry
- dma-names : "rx" (=playback), "tx" (=capture)
@ -532,56 +463,55 @@ rcar_sound: sound@ec500000 {
};
};
rcar_sound,ssiu {
ssiu00: ssiu-0 {
dmas = <&audma0 0x15>, <&audma1 0x16>;
dma-names = "rx", "tx";
};
ssiu01: ssiu-1 {
dmas = <&audma0 0x35>, <&audma1 0x36>;
dma-names = "rx", "tx";
};
...
ssiu95: ssiu-49 {
dmas = <&audma0 0xA5>, <&audma1 0xA6>;
dma-names = "rx", "tx";
};
ssiu96: ssiu-50 {
dmas = <&audma0 0xA7>, <&audma1 0xA8>;
dma-names = "rx", "tx";
};
ssiu97: ssiu-51 {
dmas = <&audma0 0xA9>, <&audma1 0xAA>;
dma-names = "rx", "tx";
};
};
rcar_sound,ssi {
ssi0: ssi-0 {
interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
dma-names = "rx", "tx", "rxu", "txu";
dmas = <&audma0 0x01>, <&audma1 0x02>;
dma-names = "rx", "tx";
};
ssi1: ssi-1 {
interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi2: ssi-2 {
interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi3: ssi-3 {
interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi4: ssi-4 {
interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi5: ssi-5 {
interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi6: ssi-6 {
interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
dma-names = "rx", "tx", "rxu", "txu";
};
ssi7: ssi-7 {
interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
dma-names = "rx", "tx", "rxu", "txu";
dmas = <&audma0 0x03>, <&audma1 0x04>;
dma-names = "rx", "tx";
};
...
ssi8: ssi-8 {
interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
dma-names = "rx", "tx", "rxu", "txu";
dmas = <&audma0 0x11>, <&audma1 0x12>;
dma-names = "rx", "tx";
};
ssi9: ssi-9 {
interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
dma-names = "rx", "tx", "rxu", "txu";
dmas = <&audma0 0x13>, <&audma1 0x14>;
dma-names = "rx", "tx";
};
};
@ -646,26 +576,175 @@ Example: simple sound card
shared-pin;
};
=============================================
Example: simple sound card for Asynchronous mode
=============================================
sound {
compatible = "simple-scu-audio-card";
...
/*
* SRC Asynchronous mode setting
* Playback:
* All input data will be converted to 48kHz
* Capture:
* Inputed 48kHz data will be converted to
* system specified Hz
*/
simple-audio-card,convert-rate = <48000>;
...
simple-audio-card,cpu {
sound-dai = <&rcar_sound>;
};
simple-audio-card,codec {
...
};
};
=============================================
Example: simple sound card for channel convert
=============================================
sound {
compatible = "simple-scu-audio-card";
...
/*
* CTU setting
* All input data will be converted to 2ch
* as output data
*/
simple-audio-card,convert-channels = <2>;
...
simple-audio-card,cpu {
sound-dai = <&rcar_sound>;
};
simple-audio-card,codec {
...
};
};
=============================================
Example: simple sound card for MIXer
=============================================
sound {
compatible = "simple-scu-audio-card";
...
simple-audio-card,cpu@0 {
sound-dai = <&rcar_sound 0>;
};
simple-audio-card,cpu@1 {
sound-dai = <&rcar_sound 1>;
};
simple-audio-card,codec {
...
};
};
&rcar_sound {
...
rcar_sound,dai {
dai0 {
playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
};
dai1 {
playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
};
};
};
=============================================
Example: simple sound card for TDM
=============================================
rsnd_tdm: sound {
compatible = "simple-audio-card";
rsnd_tdm: sound {
compatible = "simple-audio-card";
simple-audio-card,format = "left_j";
simple-audio-card,bitclock-master = <&sndcodec>;
simple-audio-card,frame-master = <&sndcodec>;
simple-audio-card,format = "left_j";
simple-audio-card,bitclock-master = <&sndcodec>;
simple-audio-card,frame-master = <&sndcodec>;
sndcpu: simple-audio-card,cpu {
sound-dai = <&rcar_sound>;
dai-tdm-slot-num = <6>;
sndcpu: simple-audio-card,cpu {
sound-dai = <&rcar_sound>;
dai-tdm-slot-num = <6>;
};
sndcodec: simple-audio-card,codec {
sound-dai = <&xxx>;
};
};
=============================================
Example: simple sound card for TDM Split
=============================================
sound_card: sound {
compatible = "audio-graph-scu-card";
prefix = "xxxx";
routing = "xxxx Playback", "DAI0 Playback",
"xxxx Playback", "DAI1 Playback",
"xxxx Playback", "DAI2 Playback",
"xxxx Playback", "DAI3 Playback";
convert-channels = <8>; /* TDM Split */
dais = <&rsnd_port0 /* playback ch1/ch2 */
&rsnd_port1 /* playback ch3/ch4 */
&rsnd_port2 /* playback ch5/ch6 */
&rsnd_port3 /* playback ch7/ch8 */
>;
};
audio-codec {
...
port {
codec_0: endpoint@1 {
remote-endpoint = <&rsnd_ep0>;
};
sndcodec: simple-audio-card,codec {
sound-dai = <&xxx>;
codec_1: endpoint@2 {
remote-endpoint = <&rsnd_ep1>;
};
codec_2: endpoint@3 {
remote-endpoint = <&rsnd_ep2>;
};
codec_3: endpoint@4 {
remote-endpoint = <&rsnd_ep3>;
};
};
};
&rcar_sound {
...
ports {
rsnd_port0: port@0 {
rsnd_ep0: endpoint {
remote-endpoint = <&codec_0>;
...
playback = <&ssiu30 &ssi3>;
};
};
rsnd_port1: port@1 {
rsnd_ep1: endpoint {
remote-endpoint = <&codec_1>;
...
playback = <&ssiu31 &ssi3>;
};
};
rsnd_port2: port@2 {
rsnd_ep2: endpoint {
remote-endpoint = <&codec_2>;
...
playback = <&ssiu32 &ssi3>;
};
};
rsnd_port3: port@3 {
rsnd_ep3: endpoint {
remote-endpoint = <&codec_3>;
...
playback = <&ssiu33 &ssi3>;
};
};
};
};
=============================================
Example: simple sound card for Multi channel

View File

@ -35,14 +35,14 @@ Pins on the device (for linking into audio routes):
Example:
alc5631: alc5631@1a {
alc5631: audio-codec@1a {
compatible = "realtek,alc5631";
reg = <0x1a>;
};
or
rt5631: rt5631@1a {
rt5631: audio-codec@1a {
compatible = "realtek,rt5631";
reg = <0x1a>;
};

View File

@ -10,6 +10,10 @@ Required properties:
- interrupts : The CODEC's interrupt output.
- avdd-supply: Power supply for AVDD, providing 1.8V.
- cpvdd-supply: Power supply for CPVDD, providing 3.5V.
Optional properties:
- "realtek,dc_offset_l_manual"
@ -51,4 +55,6 @@ rt5663: codec@12 {
compatible = "realtek,rt5663";
reg = <0x12>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
avdd-supply = <&pp1800_a_alc5662>;
cpvdd-supply = <&pp3500_a_alc5662>;
};

View File

@ -4,9 +4,14 @@ Required properties:
- compatible : "dioo,dio2125" or "simple-audio-amplifier"
- enable-gpios : the gpio connected to the enable pin of the simple amplifier
Optional properties:
- VCC-supply : power supply for the device, as covered
in Documentation/devicetree/bindings/regulator/regulator.txt
Example:
amp: analog-amplifier {
compatible = "simple-audio-amplifier";
VCC-supply = <&regulator>;
enable-gpios = <&gpio GPIOH_3 0>;
};

View File

@ -95,7 +95,9 @@ Optional CPU/CODEC subnodes properties:
initialization. It is useful for some aCPUs with
fixed clocks.
-------------------------------------------
Example 1 - single DAI link:
-------------------------------------------
sound {
compatible = "simple-audio-card";
@ -138,7 +140,9 @@ sh_fsi2: sh_fsi2@ec230000 {
interrupts = <0 146 0x4>;
};
-------------------------------------------
Example 2 - many DAI links:
-------------------------------------------
sound {
compatible = "simple-audio-card";
@ -176,8 +180,10 @@ sound {
};
};
-------------------------------------------
Example 3 - route audio from IMX6 SSI2 through TLV320DAC3100 codec
through TPA6130A2 amplifier to headphones:
-------------------------------------------
&i2c0 {
codec: tlv320dac3100@18 {
@ -210,3 +216,134 @@ sound {
clocks = ...
};
};
-------------------------------------------
Example 4. Sampling Rate Conversion
-------------------------------------------
sound {
compatible = "simple-audio-card";
simple-audio-card,name = "rsnd-ak4643";
simple-audio-card,format = "left_j";
simple-audio-card,bitclock-master = <&sndcodec>;
simple-audio-card,frame-master = <&sndcodec>;
simple-audio-card,convert-rate = <48000>;
simple-audio-card,prefix = "ak4642";
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
"DAI0 Capture", "ak4642 Capture";
sndcpu: simple-audio-card,cpu {
sound-dai = <&rcar_sound>;
};
sndcodec: simple-audio-card,codec {
sound-dai = <&ak4643>;
system-clock-frequency = <11289600>;
};
};
-------------------------------------------
Example 5. 2 CPU 1 Codec (Mixing)
-------------------------------------------
sound {
compatible = "simple-audio-card";
simple-audio-card,name = "rsnd-ak4643";
simple-audio-card,format = "left_j";
simple-audio-card,bitclock-master = <&dpcmcpu>;
simple-audio-card,frame-master = <&dpcmcpu>;
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
"ak4642 Playback", "DAI1 Playback";
dpcmcpu: cpu@0 {
sound-dai = <&rcar_sound 0>;
};
cpu@1 {
sound-dai = <&rcar_sound 1>;
};
codec {
prefix = "ak4642";
sound-dai = <&ak4643>;
clocks = <&audio_clock>;
};
};
-------------------------------------------
Example 6 - many DAI links with DPCM:
-------------------------------------------
CPU0 ------ ak4613
CPU1 ------ PCM3168A-p /* DPCM 1ch/2ch */
CPU2 --/ /* DPCM 3ch/4ch */
CPU3 --/ /* DPCM 5ch/6ch */
CPU4 --/ /* DPCM 7ch/8ch */
CPU5 ------ PCM3168A-c
sound {
compatible = "simple-audio-card";
simple-audio-card,routing =
"pcm3168a Playback", "DAI1 Playback",
"pcm3168a Playback", "DAI2 Playback",
"pcm3168a Playback", "DAI3 Playback",
"pcm3168a Playback", "DAI4 Playback";
simple-audio-card,dai-link@0 {
format = "left_j";
bitclock-master = <&sndcpu0>;
frame-master = <&sndcpu0>;
sndcpu0: cpu {
sound-dai = <&rcar_sound 0>;
};
codec {
sound-dai = <&ak4613>;
};
};
simple-audio-card,dai-link@1 {
format = "i2s";
bitclock-master = <&sndcpu1>;
frame-master = <&sndcpu1>;
convert-channels = <8>; /* TDM Split */
sndcpu1: cpu@0 {
sound-dai = <&rcar_sound 1>;
};
cpu@1 {
sound-dai = <&rcar_sound 2>;
};
cpu@2 {
sound-dai = <&rcar_sound 3>;
};
cpu@3 {
sound-dai = <&rcar_sound 4>;
};
codec {
mclk-fs = <512>;
prefix = "pcm3168a";
dai-tdm-slot-num = <8>;
sound-dai = <&pcm3168a 0>;
};
};
simple-audio-card,dai-link@2 {
format = "i2s";
bitclock-master = <&sndcpu2>;
frame-master = <&sndcpu2>;
sndcpu2: cpu {
sound-dai = <&rcar_sound 5>;
};
codec {
mclk-fs = <512>;
prefix = "pcm3168a";
sound-dai = <&pcm3168a 1>;
};
};
};

View File

@ -75,7 +75,6 @@ sound {
simple-audio-card,bitclock-master = <&dpcmcpu>;
simple-audio-card,frame-master = <&dpcmcpu>;
simple-audio-card,prefix = "ak4642";
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
"ak4642 Playback", "DAI1 Playback";
@ -88,6 +87,7 @@ sound {
};
codec {
prefix = "ak4642";
sound-dai = <&ak4643>;
clocks = <&audio_clock>;
};

View File

@ -4,9 +4,11 @@ Required properties:
- compatible: must be one of the following compatibles:
- "allwinner,sun50i-a64-codec-analog"
- reg: must contain the registers location and length
- cpvdd-supply: Regulator supply for the headphone amplifier
Example:
codec_analog: codec-analog@1f015c0 {
compatible = "allwinner,sun50i-a64-codec-analog";
reg = <0x01f015c0 0x4>;
cpvdd-supply = <&reg_eldo1>;
};

View File

@ -0,0 +1,28 @@
Device-Tree bindings for Xilinx I2S PL block
The IP supports I2S based playback/capture audio
Required property:
- compatible: "xlnx,i2s-transmitter-1.0" for playback and
"xlnx,i2s-receiver-1.0" for capture
Required property common to both I2S playback and capture:
- reg: Base address and size of the IP core instance.
- xlnx,dwidth: sample data width. Can be any of 16, 24.
- xlnx,num-channels: Number of I2S streams. Can be any of 1, 2, 3, 4.
supported channels = 2 * xlnx,num-channels
Example:
i2s_receiver@a0080000 {
compatible = "xlnx,i2s-receiver-1.0";
reg = <0x0 0xa0080000 0x0 0x10000>;
xlnx,dwidth = <0x18>;
xlnx,num-channels = <1>;
};
i2s_transmitter@a0090000 {
compatible = "xlnx,i2s-transmitter-1.0";
reg = <0x0 0xa0090000 0x0 0x10000>;
xlnx,dwidth = <0x18>;
xlnx,num-channels = <1>;
};

View File

@ -1310,6 +1310,13 @@ F: drivers/pinctrl/meson/
F: drivers/mmc/host/meson*
N: meson
ARM/Amlogic Meson SoC Sound Drivers
M: Jerome Brunet <jbrunet@baylibre.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/soc/meson/
F: Documentation/devicetree/bindings/sound/amlogic*
ARM/Annapurna Labs ALPINE ARCHITECTURE
M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
M: Antoine Tenart <antoine.tenart@bootlin.com>
@ -10795,7 +10802,10 @@ M: Jarkko Nikula <jarkko.nikula@bitmer.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
L: linux-omap@vger.kernel.org
S: Maintained
F: sound/soc/omap/
F: sound/soc/ti/omap*
F: sound/soc/ti/rx51.c
F: sound/soc/ti/n810.c
F: sound/soc/ti/sdma-pcm.*
OMAP CLOCK FRAMEWORK SUPPORT
M: Paul Walmsley <paul@pwsan.com>
@ -14839,6 +14849,12 @@ F: Documentation/devicetree/bindings/clock/ti,sci-clk.txt
F: drivers/clk/keystone/sci-clk.c
F: drivers/reset/reset-ti-sci.c
Texas Instruments ASoC drivers
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/soc/ti/
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org

View File

@ -167,8 +167,9 @@ CONFIG_SOUND=m
CONFIG_SND=m
CONFIG_SND_USB_AUDIO=m
CONFIG_SND_SOC=m
CONFIG_SND_EDMA_SOC=m
CONFIG_SND_DA850_SOC_EVM=m
CONFIG_SND_SOC_TLV320AIC3X=m
CONFIG_SND_SOC_DAVINCI_MCASP=m
CONFIG_SND_SOC_DAVINCI_EVM=m
CONFIG_SND_SIMPLE_CARD=m
CONFIG_HID=m
CONFIG_HID_A4TECH=m

View File

@ -175,8 +175,6 @@ CONFIG_SND_PCM_OSS=y
# CONFIG_SND_VERBOSE_PROCFS is not set
CONFIG_SND_DUMMY=y
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_OMAP_SOC=y
# CONFIG_USB_HID is not set
CONFIG_USB=y
CONFIG_USB_PHY=y

View File

@ -381,13 +381,13 @@ CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_DEBUG=y
CONFIG_SND_USB_AUDIO=m
CONFIG_SND_SOC=m
CONFIG_SND_EDMA_SOC=m
CONFIG_SND_AM33XX_SOC_EVM=m
CONFIG_SND_OMAP_SOC=m
CONFIG_SND_OMAP_SOC_HDMI_AUDIO=m
CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m
CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m
CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
CONFIG_SND_SOC_TLV320AIC3X=m
CONFIG_SND_SOC_DAVINCI_MCASP=m
CONFIG_SND_SOC_NOKIA_RX51=m
CONFIG_SND_SOC_OMAP_HDMI=m
CONFIG_SND_SOC_OMAP_ABE_TWL6040=m
CONFIG_SND_SOC_OMAP3_PANDORA=m
CONFIG_SND_SOC_OMAP3_TWL4030=m
CONFIG_SND_SOC_CPCAP=m
CONFIG_SND_SIMPLE_CARD=m
CONFIG_SND_AUDIO_GRAPH_CARD=m

View File

@ -794,9 +794,9 @@ static __init void dm365_evm_init(void)
/* maybe setup mmc1/etc ... _after_ mmc0 */
evm_init_cpld();
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
dm365_init_asp();
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
dm365_init_vc();
#endif
dm365_init_rtc();

View File

@ -8,7 +8,7 @@ obj-y := io.o id.o sram-init.o sram.o time.o irq.o mux.o flash.o \
serial.o devices.o dma.o fb.o
obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
obj-y += mcbsp.o
endif

View File

@ -24,7 +24,7 @@ obj-$(CONFIG_SOC_OMAP5) += $(hwmod-common) $(secure-common)
obj-$(CONFIG_SOC_AM43XX) += $(hwmod-common) $(secure-common)
obj-$(CONFIG_SOC_DRA7XX) += $(hwmod-common) $(secure-common)
ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
obj-y += mcbsp.o
endif

View File

@ -524,7 +524,7 @@ void omap_auxdata_legacy_init(struct device *dev)
dev->platform_data = &twl_gpio_auxdata;
}
#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
static struct omap_mcbsp_platform_data mcbsp_pdata;
static void __init omap3_mcbsp_init(void)
{
@ -572,7 +572,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] = {
OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
&am35xx_emac_pdata),
/* McBSP modules with sidetone core */
#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49022000, "49022000.mcbsp", &mcbsp_pdata),
OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49024000, "49024000.mcbsp", &mcbsp_pdata),
#endif

View File

@ -106,6 +106,7 @@
#define QUINARY_TDM_TX_6 101
#define QUINARY_TDM_RX_7 102
#define QUINARY_TDM_TX_7 103
#define DISPLAY_PORT_RX 104
#endif /* __DT_BINDINGS_Q6_AFE_H__ */

View File

@ -79,6 +79,7 @@ struct davinci_mcasp_pdata {
/* McASP specific fields */
int tdm_slots;
u8 op_mode;
u8 dismod;
u8 num_serializer;
u8 *serial_dir;
u8 version;

View File

@ -23,6 +23,7 @@ struct snd_compr_ops;
* struct snd_compr_runtime: runtime stream description
* @state: stream state
* @ops: pointer to DSP callbacks
* @dma_buffer_p: runtime dma buffer pointer
* @buffer: pointer to kernel buffer, valid only when not in mmap mode or
* DSP doesn't implement copy
* @buffer_size: size of the above buffer
@ -37,6 +38,7 @@ struct snd_compr_ops;
struct snd_compr_runtime {
snd_pcm_state_t state;
struct snd_compr_ops *ops;
struct snd_dma_buffer *dma_buffer_p;
void *buffer;
u64 buffer_size;
u32 fragment_size;
@ -175,6 +177,23 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
wake_up(&stream->runtime->sleep);
}
/**
* snd_compr_set_runtime_buffer - Set the Compress runtime buffer
* @substream: compress substream to set
* @bufp: the buffer information, NULL to clear
*
* Copy the buffer information to runtime buffer when @bufp is non-NULL.
* Otherwise it clears the current buffer information.
*/
static inline void snd_compr_set_runtime_buffer(
struct snd_compr_stream *substream,
struct snd_dma_buffer *bufp)
{
struct snd_compr_runtime *runtime = substream->runtime;
runtime->dma_buffer_p = bufp;
}
int snd_compr_stop_error(struct snd_compr_stream *stream,
snd_pcm_state_t state);

View File

@ -116,12 +116,12 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card);
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
struct snd_pcm_hw_params *params);
void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
void asoc_simple_card_parse_convert(struct device *dev,
struct device_node *np, char *prefix,
struct asoc_simple_card_data *data);
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
char *prefix,
int optional);
char *prefix);
int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
char *prefix);

View File

@ -24,6 +24,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[];
/*
* generic table used for HDA codec-based platforms, possibly with

View File

@ -37,6 +37,20 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
struct snd_soc_acpi_mach *
snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines);
/**
* snd_soc_acpi_mach_params: interface for machine driver configuration
*
* @acpi_ipc_irq_index: used for BYT-CR detection
* @platform: string used for HDaudio codec support
* @codec_mask: used for HDAudio support
*/
struct snd_soc_acpi_mach_params {
u32 acpi_ipc_irq_index;
const char *platform;
u32 codec_mask;
u32 dmic_num;
};
/**
* snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are
* related to the hardware, except for the firmware and topology file names.
@ -68,6 +82,7 @@ struct snd_soc_acpi_mach {
struct snd_soc_acpi_mach * (*machine_quirk)(void *arg);
const void *quirk_data;
void *pdata;
struct snd_soc_acpi_mach_params mach_params;
const char *sof_fw_filename;
const char *sof_tplg_filename;
const char *asoc_plat_name;

View File

@ -553,12 +553,12 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
}
#endif
#ifdef CONFIG_SND_SOC_AC97_BUS
struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component);
struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
unsigned int id, unsigned int id_mask);
void snd_soc_free_ac97_component(struct snd_ac97 *ac97);
#ifdef CONFIG_SND_SOC_AC97_BUS
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
struct platform_device *pdev);
@ -1477,10 +1477,20 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
unsigned int *rx_mask,
unsigned int *slots,
unsigned int *slot_width);
void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
void snd_soc_of_parse_node_prefix(struct device_node *np,
struct snd_soc_codec_conf *codec_conf,
struct device_node *of_node,
const char *propname);
static inline
void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
struct snd_soc_codec_conf *codec_conf,
struct device_node *of_node,
const char *propname)
{
snd_soc_of_parse_node_prefix(card->dev->of_node,
codec_conf, of_node, propname);
}
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,

View File

@ -171,7 +171,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
}
data->stream.ops->free(&data->stream);
kfree(data->stream.runtime->buffer);
if (!data->stream.runtime->dma_buffer_p)
kfree(data->stream.runtime->buffer);
kfree(data->stream.runtime);
kfree(data);
return 0;
@ -505,7 +506,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
struct snd_compr_params *params)
{
unsigned int buffer_size;
void *buffer;
void *buffer = NULL;
buffer_size = params->buffer.fragment_size * params->buffer.fragments;
if (stream->ops->copy) {
@ -514,7 +515,18 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
* the data from core
*/
} else {
buffer = kmalloc(buffer_size, GFP_KERNEL);
if (stream->runtime->dma_buffer_p) {
if (buffer_size > stream->runtime->dma_buffer_p->bytes)
dev_err(&stream->device->dev,
"Not enough DMA buffer");
else
buffer = stream->runtime->dma_buffer_p->area;
} else {
buffer = kmalloc(buffer_size, GFP_KERNEL);
}
if (!buffer)
return -ENOMEM;
}

View File

@ -46,13 +46,11 @@ source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
source "sound/soc/bcm/Kconfig"
source "sound/soc/cirrus/Kconfig"
source "sound/soc/davinci/Kconfig"
source "sound/soc/dwc/Kconfig"
source "sound/soc/fsl/Kconfig"
source "sound/soc/hisilicon/Kconfig"
source "sound/soc/jz4740/Kconfig"
source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
source "sound/soc/img/Kconfig"
source "sound/soc/intel/Kconfig"
@ -70,9 +68,11 @@ source "sound/soc/sti/Kconfig"
source "sound/soc/stm/Kconfig"
source "sound/soc/sunxi/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/ti/Kconfig"
source "sound/soc/txx9/Kconfig"
source "sound/soc/uniphier/Kconfig"
source "sound/soc/ux500/Kconfig"
source "sound/soc/xilinx/Kconfig"
source "sound/soc/xtensa/Kconfig"
source "sound/soc/zte/Kconfig"

View File

@ -30,7 +30,6 @@ obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += bcm/
obj-$(CONFIG_SND_SOC) += cirrus/
obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += hisilicon/
@ -41,7 +40,6 @@ obj-$(CONFIG_SND_SOC) += mediatek/
obj-$(CONFIG_SND_SOC) += meson/
obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += qcom/
@ -54,8 +52,10 @@ obj-$(CONFIG_SND_SOC) += sti/
obj-$(CONFIG_SND_SOC) += stm/
obj-$(CONFIG_SND_SOC) += sunxi/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += ti/
obj-$(CONFIG_SND_SOC) += txx9/
obj-$(CONFIG_SND_SOC) += uniphier/
obj-$(CONFIG_SND_SOC) += ux500/
obj-$(CONFIG_SND_SOC) += xilinx/
obj-$(CONFIG_SND_SOC) += xtensa/
obj-$(CONFIG_SND_SOC) += zte/

View File

@ -19,3 +19,9 @@ config SND_SOC_AMD_CZ_RT5645_MACH
depends on SND_SOC_AMD_ACP && I2C
help
This option enables machine driver for rt5645.
config SND_SOC_AMD_ACP3x
tristate "AMD Audio Coprocessor-v3.x support"
depends on X86 && PCI
help
This option enables ACP v3.x I2S support on AMD platform

View File

@ -5,3 +5,4 @@ snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/

View File

@ -403,7 +403,7 @@ static struct regulator_config acp_da7219_cfg = {
static struct regulator_ops acp_da7219_ops = {
};
static struct regulator_desc acp_da7219_desc = {
static const struct regulator_desc acp_da7219_desc = {
.name = "reg-fixed-1.8V",
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,

View File

@ -303,11 +303,10 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, u32 size,
}
/* Create page table entries in ACP SRAM for the allocated memory */
static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
static void acp_pte_config(void __iomem *acp_mmio, dma_addr_t addr,
u16 num_of_pages, u32 pte_offset)
{
u16 page_idx;
u64 addr;
u32 low;
u32 high;
u32 offset;
@ -317,7 +316,6 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
/* Load the low address of page int ACP SRAM through SRBM */
acp_reg_write((offset + (page_idx * 8)),
acp_mmio, mmACP_SRBM_Targ_Idx_Addr);
addr = page_to_phys(pg);
low = lower_32_bits(addr);
high = upper_32_bits(addr);
@ -333,7 +331,7 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data);
/* Move to next physically contiguos page */
pg++;
addr += PAGE_SIZE;
}
}
@ -343,7 +341,7 @@ static void config_acp_dma(void __iomem *acp_mmio,
{
u16 ch_acp_sysmem, ch_acp_i2s;
acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
acp_pte_config(acp_mmio, rtd->dma_addr, rtd->num_of_pages,
rtd->pte_offset);
if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
@ -850,7 +848,6 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
int status;
uint64_t size;
u32 val = 0;
struct page *pg;
struct snd_pcm_runtime *runtime;
struct audio_substream_data *rtd;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
@ -986,16 +983,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
return status;
memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
pg = virt_to_page(substream->dma_buffer.area);
if (pg) {
if (substream->dma_buffer.area) {
acp_set_sram_bank_state(rtd->acp_mmio, 0, true);
/* Save for runtime private data */
rtd->pg = pg;
rtd->dma_addr = substream->dma_buffer.addr;
rtd->order = get_order(size);
/* Fill the page table entries in ACP SRAM */
rtd->pg = pg;
rtd->size = size;
rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
rtd->direction = substream->stream;
@ -1151,18 +1146,21 @@ static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd,
DRV_NAME);
struct audio_drv_data *adata = dev_get_drvdata(component->dev);
struct device *parent = component->dev->parent;
switch (adata->asic_type) {
case CHIP_STONEY:
ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
NULL, ST_MIN_BUFFER,
parent,
ST_MIN_BUFFER,
ST_MAX_BUFFER);
break;
default:
ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
NULL, MIN_BUFFER,
parent,
MIN_BUFFER,
MAX_BUFFER);
break;
}

View File

@ -123,7 +123,7 @@ enum acp_dma_priority_level {
};
struct audio_substream_data {
struct page *pg;
dma_addr_t dma_addr;
unsigned int order;
u16 num_of_pages;
u16 i2s_instance;

View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
# Raven Ridge platform Support
snd-pci-acp3x-objs := pci-acp3x.o
snd-acp3x-pcm-dma-objs := acp3x-pcm-dma.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-pci-acp3x.o
obj-$(CONFIG_SND_SOC_AMD_ACP3x) += snd-acp3x-pcm-dma.o

View File

@ -0,0 +1,777 @@
// SPDX-License-Identifier: GPL-2.0+
//
// AMD ALSA SoC PCM Driver
//
//Copyright 2016 Advanced Micro Devices, Inc.
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include "acp3x.h"
#define DRV_NAME "acp3x-i2s-audio"
struct i2s_dev_data {
bool tdm_mode;
unsigned int i2s_irq;
u32 tdm_fmt;
void __iomem *acp3x_base;
struct snd_pcm_substream *play_stream;
struct snd_pcm_substream *capture_stream;
};
struct i2s_stream_instance {
u16 num_pages;
u16 channels;
u32 xfer_resolution;
struct page *pg;
void __iomem *acp3x_base;
};
static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_96000,
.rate_min = 8000,
.rate_max = 96000,
.buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
.period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
.period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
.periods_min = PLAYBACK_MIN_NUM_PERIODS,
.periods_max = PLAYBACK_MAX_NUM_PERIODS,
};
static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.rate_min = 8000,
.rate_max = 48000,
.buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
.period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
.period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
.periods_min = CAPTURE_MIN_NUM_PERIODS,
.periods_max = CAPTURE_MAX_NUM_PERIODS,
};
static int acp3x_power_on(void __iomem *acp3x_base, bool on)
{
u16 val, mask;
u32 timeout;
if (on == true) {
val = 1;
mask = ACP3x_POWER_ON;
} else {
val = 0;
mask = ACP3x_POWER_OFF;
}
rv_writel(val, acp3x_base + mmACP_PGFSM_CONTROL);
timeout = 0;
while (true) {
val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
if ((val & ACP3x_POWER_OFF_IN_PROGRESS) == mask)
break;
if (timeout > 100) {
pr_err("ACP3x power state change failure\n");
return -ENODEV;
}
timeout++;
cpu_relax();
}
return 0;
}
static int acp3x_reset(void __iomem *acp3x_base)
{
u32 val, timeout;
rv_writel(1, acp3x_base + mmACP_SOFT_RESET);
timeout = 0;
while (true) {
val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
if ((val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK) ||
timeout > 100) {
if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK)
break;
return -ENODEV;
}
timeout++;
cpu_relax();
}
rv_writel(0, acp3x_base + mmACP_SOFT_RESET);
timeout = 0;
while (true) {
val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
if (!val || timeout > 100) {
if (!val)
break;
return -ENODEV;
}
timeout++;
cpu_relax();
}
return 0;
}
static int acp3x_init(void __iomem *acp3x_base)
{
int ret;
/* power on */
ret = acp3x_power_on(acp3x_base, true);
if (ret) {
pr_err("ACP3x power on failed\n");
return ret;
}
/* Reset */
ret = acp3x_reset(acp3x_base);
if (ret) {
pr_err("ACP3x reset failed\n");
return ret;
}
return 0;
}
static int acp3x_deinit(void __iomem *acp3x_base)
{
int ret;
/* Reset */
ret = acp3x_reset(acp3x_base);
if (ret) {
pr_err("ACP3x reset failed\n");
return ret;
}
/* power off */
ret = acp3x_power_on(acp3x_base, false);
if (ret) {
pr_err("ACP3x power off failed\n");
return ret;
}
return 0;
}
static irqreturn_t i2s_irq_handler(int irq, void *dev_id)
{
u16 play_flag, cap_flag;
u32 val;
struct i2s_dev_data *rv_i2s_data = dev_id;
if (!rv_i2s_data)
return IRQ_NONE;
play_flag = 0;
cap_flag = 0;
val = rv_readl(rv_i2s_data->acp3x_base + mmACP_EXTERNAL_INTR_STAT);
if ((val & BIT(BT_TX_THRESHOLD)) && rv_i2s_data->play_stream) {
rv_writel(BIT(BT_TX_THRESHOLD), rv_i2s_data->acp3x_base +
mmACP_EXTERNAL_INTR_STAT);
snd_pcm_period_elapsed(rv_i2s_data->play_stream);
play_flag = 1;
}
if ((val & BIT(BT_RX_THRESHOLD)) && rv_i2s_data->capture_stream) {
rv_writel(BIT(BT_RX_THRESHOLD), rv_i2s_data->acp3x_base +
mmACP_EXTERNAL_INTR_STAT);
snd_pcm_period_elapsed(rv_i2s_data->capture_stream);
cap_flag = 1;
}
if (play_flag | cap_flag)
return IRQ_HANDLED;
else
return IRQ_NONE;
}
static void config_acp3x_dma(struct i2s_stream_instance *rtd, int direction)
{
u16 page_idx;
u64 addr;
u32 low, high, val, acp_fifo_addr;
struct page *pg = rtd->pg;
/* 8 scratch registers used to map one 64 bit address */
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
val = 0;
else
val = rtd->num_pages * 8;
/* Group Enable */
rv_writel(ACP_SRAM_PTE_OFFSET | BIT(31), rtd->acp3x_base +
mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
rv_writel(PAGE_SIZE_4K_ENABLE, rtd->acp3x_base +
mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
for (page_idx = 0; page_idx < rtd->num_pages; page_idx++) {
/* Load the low address of page int ACP SRAM through SRBM */
addr = page_to_phys(pg);
low = lower_32_bits(addr);
high = upper_32_bits(addr);
rv_writel(low, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val);
high |= BIT(31);
rv_writel(high, rtd->acp3x_base + mmACP_SCRATCH_REG_0 + val
+ 4);
/* Move to next physically contiguos page */
val += 8;
pg++;
}
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
/* Config ringbuffer */
rv_writel(MEM_WINDOW_START, rtd->acp3x_base +
mmACP_BT_TX_RINGBUFADDR);
rv_writel(MAX_BUFFER, rtd->acp3x_base +
mmACP_BT_TX_RINGBUFSIZE);
rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_TX_DMA_SIZE);
/* Config audio fifo */
acp_fifo_addr = ACP_SRAM_PTE_OFFSET + (rtd->num_pages * 8)
+ PLAYBACK_FIFO_ADDR_OFFSET;
rv_writel(acp_fifo_addr, rtd->acp3x_base +
mmACP_BT_TX_FIFOADDR);
rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_TX_FIFOSIZE);
} else {
/* Config ringbuffer */
rv_writel(MEM_WINDOW_START + MAX_BUFFER, rtd->acp3x_base +
mmACP_BT_RX_RINGBUFADDR);
rv_writel(MAX_BUFFER, rtd->acp3x_base +
mmACP_BT_RX_RINGBUFSIZE);
rv_writel(DMA_SIZE, rtd->acp3x_base + mmACP_BT_RX_DMA_SIZE);
/* Config audio fifo */
acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
(rtd->num_pages * 8) + CAPTURE_FIFO_ADDR_OFFSET;
rv_writel(acp_fifo_addr, rtd->acp3x_base +
mmACP_BT_RX_FIFOADDR);
rv_writel(FIFO_SIZE, rtd->acp3x_base + mmACP_BT_RX_FIFOSIZE);
}
/* Enable watermark/period interrupt to host */
rv_writel(BIT(BT_TX_THRESHOLD) | BIT(BT_RX_THRESHOLD),
rtd->acp3x_base + mmACP_EXTERNAL_INTR_CNTL);
}
static int acp3x_dma_open(struct snd_pcm_substream *substream)
{
int ret = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *prtd = substream->private_data;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
DRV_NAME);
struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
struct i2s_stream_instance *i2s_data = kzalloc(sizeof(struct i2s_stream_instance),
GFP_KERNEL);
if (!i2s_data)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
runtime->hw = acp3x_pcm_hardware_playback;
else
runtime->hw = acp3x_pcm_hardware_capture;
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
dev_err(component->dev, "set integer constraint failed\n");
kfree(i2s_data);
return ret;
}
if (!adata->play_stream && !adata->capture_stream)
rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
adata->play_stream = substream;
else
adata->capture_stream = substream;
i2s_data->acp3x_base = adata->acp3x_base;
runtime->private_data = i2s_data;
return 0;
}
static int acp3x_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
int status;
u64 size;
struct page *pg;
struct snd_pcm_runtime *runtime = substream->runtime;
struct i2s_stream_instance *rtd = runtime->private_data;
if (!rtd)
return -EINVAL;
size = params_buffer_bytes(params);
status = snd_pcm_lib_malloc_pages(substream, size);
if (status < 0)
return status;
memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
pg = virt_to_page(substream->dma_buffer.area);
if (pg) {
rtd->pg = pg;
rtd->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
config_acp3x_dma(rtd, substream->stream);
status = 0;
} else {
status = -ENOMEM;
}
return status;
}
static snd_pcm_uframes_t acp3x_dma_pointer(struct snd_pcm_substream *substream)
{
u32 pos = 0;
struct i2s_stream_instance *rtd = substream->runtime->private_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
pos = rv_readl(rtd->acp3x_base +
mmACP_BT_TX_LINKPOSITIONCNTR);
else
pos = rv_readl(rtd->acp3x_base +
mmACP_BT_RX_LINKPOSITIONCNTR);
if (pos >= MAX_BUFFER)
pos = 0;
return bytes_to_frames(substream->runtime, pos);
}
static int acp3x_dma_new(struct snd_soc_pcm_runtime *rtd)
{
return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV,
NULL, MIN_BUFFER,
MAX_BUFFER);
}
static int acp3x_dma_hw_free(struct snd_pcm_substream *substream)
{
return snd_pcm_lib_free_pages(substream);
}
static int acp3x_dma_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
return snd_pcm_lib_default_mmap(substream, vma);
}
static int acp3x_dma_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *prtd = substream->private_data;
struct i2s_stream_instance *rtd = substream->runtime->private_data;
struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd,
DRV_NAME);
struct i2s_dev_data *adata = dev_get_drvdata(component->dev);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
adata->play_stream = NULL;
else
adata->capture_stream = NULL;
/* Disable ACP irq, when the current stream is being closed and
* another stream is also not active.
*/
if (!adata->play_stream && !adata->capture_stream)
rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
kfree(rtd);
return 0;
}
static struct snd_pcm_ops acp3x_dma_ops = {
.open = acp3x_dma_open,
.close = acp3x_dma_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = acp3x_dma_hw_params,
.hw_free = acp3x_dma_hw_free,
.pointer = acp3x_dma_pointer,
.mmap = acp3x_dma_mmap,
};
static int acp3x_dai_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
adata->tdm_mode = false;
break;
case SND_SOC_DAIFMT_DSP_A:
adata->tdm_mode = true;
break;
default:
return -EINVAL;
}
return 0;
}
static int acp3x_dai_set_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
u32 rx_mask, int slots, int slot_width)
{
u32 val = 0;
u16 slot_len;
struct i2s_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
switch (slot_width) {
case SLOT_WIDTH_8:
slot_len = 8;
break;
case SLOT_WIDTH_16:
slot_len = 16;
break;
case SLOT_WIDTH_24:
slot_len = 24;
break;
case SLOT_WIDTH_32:
slot_len = 0;
break;
default:
return -EINVAL;
}
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_ITER);
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
rv_writel((val | 0x2), adata->acp3x_base + mmACP_BTTDM_IRER);
val = (FRM_LEN | (slots << 15) | (slot_len << 18));
rv_writel(val, adata->acp3x_base + mmACP_BTTDM_TXFRMT);
rv_writel(val, adata->acp3x_base + mmACP_BTTDM_RXFRMT);
adata->tdm_fmt = val;
return 0;
}
static int acp3x_dai_i2s_hwparams(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
u32 val = 0;
struct i2s_stream_instance *rtd = substream->runtime->private_data;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_U8:
case SNDRV_PCM_FORMAT_S8:
rtd->xfer_resolution = 0x0;
break;
case SNDRV_PCM_FORMAT_S16_LE:
rtd->xfer_resolution = 0x02;
break;
case SNDRV_PCM_FORMAT_S24_LE:
rtd->xfer_resolution = 0x04;
break;
case SNDRV_PCM_FORMAT_S32_LE:
rtd->xfer_resolution = 0x05;
break;
default:
return -EINVAL;
}
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
val = val | (rtd->xfer_resolution << 3);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
else
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
return 0;
}
static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
int ret = 0;
struct i2s_stream_instance *rtd = substream->runtime->private_data;
u32 val, period_bytes;
period_bytes = frames_to_bytes(substream->runtime,
substream->runtime->period_size);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
rv_writel(period_bytes, rtd->acp3x_base +
mmACP_BT_TX_INTR_WATERMARK_SIZE);
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
val = val | BIT(0);
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
} else {
rv_writel(period_bytes, rtd->acp3x_base +
mmACP_BT_RX_INTR_WATERMARK_SIZE);
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
val = val | BIT(0);
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
}
rv_writel(1, rtd->acp3x_base + mmACP_BTTDM_IER);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_ITER);
val = val & ~BIT(0);
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_ITER);
} else {
val = rv_readl(rtd->acp3x_base + mmACP_BTTDM_IRER);
val = val & ~BIT(0);
rv_writel(val, rtd->acp3x_base + mmACP_BTTDM_IRER);
}
rv_writel(0, rtd->acp3x_base + mmACP_BTTDM_IER);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
struct snd_soc_dai_ops acp3x_dai_i2s_ops = {
.hw_params = acp3x_dai_i2s_hwparams,
.trigger = acp3x_dai_i2s_trigger,
.set_fmt = acp3x_dai_i2s_set_fmt,
.set_tdm_slot = acp3x_dai_set_tdm_slot,
};
static struct snd_soc_dai_driver acp3x_i2s_dai_driver = {
.playback = {
.rates = SNDRV_PCM_RATE_8000_96000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 8,
.rate_min = 8000,
.rate_max = 96000,
},
.capture = {
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 2,
.channels_max = 2,
.rate_min = 8000,
.rate_max = 48000,
},
.ops = &acp3x_dai_i2s_ops,
};
static const struct snd_soc_component_driver acp3x_i2s_component = {
.name = DRV_NAME,
.ops = &acp3x_dma_ops,
.pcm_new = acp3x_dma_new,
};
static int acp3x_audio_probe(struct platform_device *pdev)
{
int status;
struct resource *res;
struct i2s_dev_data *adata;
unsigned int irqflags;
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "platform_data not retrieved\n");
return -ENODEV;
}
irqflags = *((unsigned int *)(pdev->dev.platform_data));
adata = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dev_data),
GFP_KERNEL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
return -ENODEV;
}
adata->acp3x_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
return -ENODEV;
}
adata->i2s_irq = res->start;
adata->play_stream = NULL;
adata->capture_stream = NULL;
dev_set_drvdata(&pdev->dev, adata);
/* Initialize ACP */
status = acp3x_init(adata->acp3x_base);
if (status)
return -ENODEV;
status = devm_snd_soc_register_component(&pdev->dev,
&acp3x_i2s_component,
&acp3x_i2s_dai_driver, 1);
if (status) {
dev_err(&pdev->dev, "Fail to register acp i2s dai\n");
goto dev_err;
}
status = devm_request_irq(&pdev->dev, adata->i2s_irq, i2s_irq_handler,
irqflags, "ACP3x_I2S_IRQ", adata);
if (status) {
dev_err(&pdev->dev, "ACP3x I2S IRQ request failed\n");
goto dev_err;
}
pm_runtime_set_autosuspend_delay(&pdev->dev, 10000);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
dev_err:
status = acp3x_deinit(adata->acp3x_base);
if (status)
dev_err(&pdev->dev, "ACP de-init failed\n");
else
dev_info(&pdev->dev, "ACP de-initialized\n");
/*ignore device status and return driver probe error*/
return -ENODEV;
}
static int acp3x_audio_remove(struct platform_device *pdev)
{
int ret;
struct i2s_dev_data *adata = dev_get_drvdata(&pdev->dev);
ret = acp3x_deinit(adata->acp3x_base);
if (ret)
dev_err(&pdev->dev, "ACP de-init failed\n");
else
dev_info(&pdev->dev, "ACP de-initialized\n");
pm_runtime_disable(&pdev->dev);
return 0;
}
static int acp3x_resume(struct device *dev)
{
int status;
u32 val;
struct i2s_dev_data *adata = dev_get_drvdata(dev);
status = acp3x_init(adata->acp3x_base);
if (status)
return -ENODEV;
if (adata->play_stream && adata->play_stream->runtime) {
struct i2s_stream_instance *rtd =
adata->play_stream->runtime->private_data;
config_acp3x_dma(rtd, SNDRV_PCM_STREAM_PLAYBACK);
rv_writel((rtd->xfer_resolution << 3),
rtd->acp3x_base + mmACP_BTTDM_ITER);
if (adata->tdm_mode == true) {
rv_writel(adata->tdm_fmt, adata->acp3x_base +
mmACP_BTTDM_TXFRMT);
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_ITER);
rv_writel((val | 0x2), adata->acp3x_base +
mmACP_BTTDM_ITER);
}
}
if (adata->capture_stream && adata->capture_stream->runtime) {
struct i2s_stream_instance *rtd =
adata->capture_stream->runtime->private_data;
config_acp3x_dma(rtd, SNDRV_PCM_STREAM_CAPTURE);
rv_writel((rtd->xfer_resolution << 3),
rtd->acp3x_base + mmACP_BTTDM_IRER);
if (adata->tdm_mode == true) {
rv_writel(adata->tdm_fmt, adata->acp3x_base +
mmACP_BTTDM_RXFRMT);
val = rv_readl(adata->acp3x_base + mmACP_BTTDM_IRER);
rv_writel((val | 0x2), adata->acp3x_base +
mmACP_BTTDM_IRER);
}
}
rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
return 0;
}
static int acp3x_pcm_runtime_suspend(struct device *dev)
{
int status;
struct i2s_dev_data *adata = dev_get_drvdata(dev);
status = acp3x_deinit(adata->acp3x_base);
if (status)
dev_err(dev, "ACP de-init failed\n");
else
dev_info(dev, "ACP de-initialized\n");
rv_writel(0, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
return 0;
}
static int acp3x_pcm_runtime_resume(struct device *dev)
{
int status;
struct i2s_dev_data *adata = dev_get_drvdata(dev);
status = acp3x_init(adata->acp3x_base);
if (status)
return -ENODEV;
rv_writel(1, adata->acp3x_base + mmACP_EXTERNAL_INTR_ENB);
return 0;
}
static const struct dev_pm_ops acp3x_pm_ops = {
.runtime_suspend = acp3x_pcm_runtime_suspend,
.runtime_resume = acp3x_pcm_runtime_resume,
.resume = acp3x_resume,
};
static struct platform_driver acp3x_dma_driver = {
.probe = acp3x_audio_probe,
.remove = acp3x_audio_remove,
.driver = {
.name = "acp3x_rv_i2s",
.pm = &acp3x_pm_ops,
},
};
module_platform_driver(acp3x_dma_driver);
MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_DESCRIPTION("AMD ACP 3.x PCM Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* AMD ALSA SoC PCM Driver
*
* Copyright 2016 Advanced Micro Devices, Inc.
*/
#include "chip_offset_byte.h"
#define ACP3x_PHY_BASE_ADDRESS 0x1240000
#define ACP3x_I2S_MODE 0
#define ACP3x_REG_START 0x1240000
#define ACP3x_REG_END 0x1250200
#define I2S_MODE 0x04
#define BT_TX_THRESHOLD 26
#define BT_RX_THRESHOLD 25
#define ACP3x_POWER_ON 0x00
#define ACP3x_POWER_ON_IN_PROGRESS 0x01
#define ACP3x_POWER_OFF 0x02
#define ACP3x_POWER_OFF_IN_PROGRESS 0x03
#define ACP3x_SOFT_RESET__SoftResetAudDone_MASK 0x00010001
#define ACP_SRAM_PTE_OFFSET 0x02050000
#define PAGE_SIZE_4K_ENABLE 0x2
#define MEM_WINDOW_START 0x4000000
#define PLAYBACK_FIFO_ADDR_OFFSET 0x400
#define CAPTURE_FIFO_ADDR_OFFSET 0x500
#define PLAYBACK_MIN_NUM_PERIODS 2
#define PLAYBACK_MAX_NUM_PERIODS 8
#define PLAYBACK_MAX_PERIOD_SIZE 16384
#define PLAYBACK_MIN_PERIOD_SIZE 4096
#define CAPTURE_MIN_NUM_PERIODS 2
#define CAPTURE_MAX_NUM_PERIODS 8
#define CAPTURE_MAX_PERIOD_SIZE 16384
#define CAPTURE_MIN_PERIOD_SIZE 4096
#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
#define MIN_BUFFER MAX_BUFFER
#define FIFO_SIZE 0x100
#define DMA_SIZE 0x40
#define FRM_LEN 0x100
#define SLOT_WIDTH_8 0x08
#define SLOT_WIDTH_16 0x10
#define SLOT_WIDTH_24 0x18
#define SLOT_WIDTH_32 0x20
static inline u32 rv_readl(void __iomem *base_addr)
{
return readl(base_addr - ACP3x_PHY_BASE_ADDRESS);
}
static inline void rv_writel(u32 val, void __iomem *base_addr)
{
writel(val, base_addr - ACP3x_PHY_BASE_ADDRESS);
}

View File

@ -0,0 +1,639 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* AMD ACP 3.0 Register Documentation
*
* Copyright 2016 Advanced Micro Devices, Inc.
*/
#ifndef _acp_ip_OFFSET_HEADER
#define _acp_ip_OFFSET_HEADER
// Registers from ACP_DMA block
#define mmACP_DMA_CNTL_0 0x1240000
#define mmACP_DMA_CNTL_1 0x1240004
#define mmACP_DMA_CNTL_2 0x1240008
#define mmACP_DMA_CNTL_3 0x124000C
#define mmACP_DMA_CNTL_4 0x1240010
#define mmACP_DMA_CNTL_5 0x1240014
#define mmACP_DMA_CNTL_6 0x1240018
#define mmACP_DMA_CNTL_7 0x124001C
#define mmACP_DMA_DSCR_STRT_IDX_0 0x1240020
#define mmACP_DMA_DSCR_STRT_IDX_1 0x1240024
#define mmACP_DMA_DSCR_STRT_IDX_2 0x1240028
#define mmACP_DMA_DSCR_STRT_IDX_3 0x124002C
#define mmACP_DMA_DSCR_STRT_IDX_4 0x1240030
#define mmACP_DMA_DSCR_STRT_IDX_5 0x1240034
#define mmACP_DMA_DSCR_STRT_IDX_6 0x1240038
#define mmACP_DMA_DSCR_STRT_IDX_7 0x124003C
#define mmACP_DMA_DSCR_CNT_0 0x1240040
#define mmACP_DMA_DSCR_CNT_1 0x1240044
#define mmACP_DMA_DSCR_CNT_2 0x1240048
#define mmACP_DMA_DSCR_CNT_3 0x124004C
#define mmACP_DMA_DSCR_CNT_4 0x1240050
#define mmACP_DMA_DSCR_CNT_5 0x1240054
#define mmACP_DMA_DSCR_CNT_6 0x1240058
#define mmACP_DMA_DSCR_CNT_7 0x124005C
#define mmACP_DMA_PRIO_0 0x1240060
#define mmACP_DMA_PRIO_1 0x1240064
#define mmACP_DMA_PRIO_2 0x1240068
#define mmACP_DMA_PRIO_3 0x124006C
#define mmACP_DMA_PRIO_4 0x1240070
#define mmACP_DMA_PRIO_5 0x1240074
#define mmACP_DMA_PRIO_6 0x1240078
#define mmACP_DMA_PRIO_7 0x124007C
#define mmACP_DMA_CUR_DSCR_0 0x1240080
#define mmACP_DMA_CUR_DSCR_1 0x1240084
#define mmACP_DMA_CUR_DSCR_2 0x1240088
#define mmACP_DMA_CUR_DSCR_3 0x124008C
#define mmACP_DMA_CUR_DSCR_4 0x1240090
#define mmACP_DMA_CUR_DSCR_5 0x1240094
#define mmACP_DMA_CUR_DSCR_6 0x1240098
#define mmACP_DMA_CUR_DSCR_7 0x124009C
#define mmACP_DMA_CUR_TRANS_CNT_0 0x12400A0
#define mmACP_DMA_CUR_TRANS_CNT_1 0x12400A4
#define mmACP_DMA_CUR_TRANS_CNT_2 0x12400A8
#define mmACP_DMA_CUR_TRANS_CNT_3 0x12400AC
#define mmACP_DMA_CUR_TRANS_CNT_4 0x12400B0
#define mmACP_DMA_CUR_TRANS_CNT_5 0x12400B4
#define mmACP_DMA_CUR_TRANS_CNT_6 0x12400B8
#define mmACP_DMA_CUR_TRANS_CNT_7 0x12400BC
#define mmACP_DMA_ERR_STS_0 0x12400C0
#define mmACP_DMA_ERR_STS_1 0x12400C4
#define mmACP_DMA_ERR_STS_2 0x12400C8
#define mmACP_DMA_ERR_STS_3 0x12400CC
#define mmACP_DMA_ERR_STS_4 0x12400D0
#define mmACP_DMA_ERR_STS_5 0x12400D4
#define mmACP_DMA_ERR_STS_6 0x12400D8
#define mmACP_DMA_ERR_STS_7 0x12400DC
#define mmACP_DMA_DESC_BASE_ADDR 0x12400E0
#define mmACP_DMA_DESC_MAX_NUM_DSCR 0x12400E4
#define mmACP_DMA_CH_STS 0x12400E8
#define mmACP_DMA_CH_GROUP 0x12400EC
#define mmACP_DMA_CH_RST_STS 0x12400F0
// Registers from ACP_AXI2AXIATU block
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_1 0x1240C00
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_1 0x1240C04
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_2 0x1240C08
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_2 0x1240C0C
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_3 0x1240C10
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_3 0x1240C14
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_4 0x1240C18
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_4 0x1240C1C
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_5 0x1240C20
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_5 0x1240C24
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_6 0x1240C28
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_6 0x1240C2C
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_7 0x1240C30
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_7 0x1240C34
#define mmACPAXI2AXI_ATU_PAGE_SIZE_GRP_8 0x1240C38
#define mmACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0x1240C3C
#define mmACPAXI2AXI_ATU_CTRL 0x1240C40
// Registers from ACP_CLKRST block
#define mmACP_SOFT_RESET 0x1241000
#define mmACP_CONTROL 0x1241004
#define mmACP_STATUS 0x1241008
#define mmACP_DSP0_OCD_HALT_ON_RST 0x124100C
#define mmACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010
// Registers from ACP_MISC block
#define mmACP_EXTERNAL_INTR_ENB 0x1241800
#define mmACP_EXTERNAL_INTR_CNTL 0x1241804
#define mmACP_EXTERNAL_INTR_STAT 0x1241808
#define mmACP_DSP0_INTR_CNTL 0x124180C
#define mmACP_DSP0_INTR_STAT 0x1241810
#define mmACP_DSP_SW_INTR_CNTL 0x1241814
#define mmACP_DSP_SW_INTR_STAT 0x1241818
#define mmACP_SW_INTR_TRIG 0x124181C
#define mmACP_SMU_MAILBOX 0x1241820
#define mmDSP_INTERRUPT_ROUTING_CTRL 0x1241824
#define mmACP_DSP0_WATCHDOG_TIMER_CNTL 0x1241828
#define mmACP_DSP0_EXT_TIMER1_CNTL 0x124182C
#define mmACP_DSP0_EXT_TIMER2_CNTL 0x1241830
#define mmACP_DSP0_EXT_TIMER3_CNTL 0x1241834
#define mmACP_DSP0_EXT_TIMER4_CNTL 0x1241838
#define mmACP_DSP0_EXT_TIMER5_CNTL 0x124183C
#define mmACP_DSP0_EXT_TIMER6_CNTL 0x1241840
#define mmACP_DSP0_EXT_TIMER1_CURR_VALUE 0x1241844
#define mmACP_DSP0_EXT_TIMER2_CURR_VALUE 0x1241848
#define mmACP_DSP0_EXT_TIMER3_CURR_VALUE 0x124184C
#define mmACP_DSP0_EXT_TIMER4_CURR_VALUE 0x1241850
#define mmACP_DSP0_EXT_TIMER5_CURR_VALUE 0x1241854
#define mmACP_DSP0_EXT_TIMER6_CURR_VALUE 0x1241858
#define mmACP_FW_STATUS 0x124185C
#define mmACP_TIMER 0x1241874
#define mmACP_TIMER_CNTL 0x1241878
#define mmACP_PGMEM_CTRL 0x12418C0
#define mmACP_ERROR_STATUS 0x12418C4
#define mmACP_SW_I2S_ERROR_REASON 0x12418C8
#define mmACP_MEM_PG_STS 0x12418CC
// Registers from ACP_PGFSM block
#define mmACP_I2S_PIN_CONFIG 0x1241400
#define mmACP_PAD_PULLUP_PULLDOWN_CTRL 0x1241404
#define mmACP_PAD_DRIVE_STRENGTH_CTRL 0x1241408
#define mmACP_SW_PAD_KEEPER_EN 0x124140C
#define mmACP_SW_WAKE_EN 0x1241410
#define mmACP_I2S_WAKE_EN 0x1241414
#define mmACP_PME_EN 0x1241418
#define mmACP_PGFSM_CONTROL 0x124141C
#define mmACP_PGFSM_STATUS 0x1241420
// Registers from ACP_SCRATCH block
#define mmACP_SCRATCH_REG_0 0x1250000
#define mmACP_SCRATCH_REG_1 0x1250004
#define mmACP_SCRATCH_REG_2 0x1250008
#define mmACP_SCRATCH_REG_3 0x125000C
#define mmACP_SCRATCH_REG_4 0x1250010
#define mmACP_SCRATCH_REG_5 0x1250014
#define mmACP_SCRATCH_REG_6 0x1250018
#define mmACP_SCRATCH_REG_7 0x125001C
#define mmACP_SCRATCH_REG_8 0x1250020
#define mmACP_SCRATCH_REG_9 0x1250024
#define mmACP_SCRATCH_REG_10 0x1250028
#define mmACP_SCRATCH_REG_11 0x125002C
#define mmACP_SCRATCH_REG_12 0x1250030
#define mmACP_SCRATCH_REG_13 0x1250034
#define mmACP_SCRATCH_REG_14 0x1250038
#define mmACP_SCRATCH_REG_15 0x125003C
#define mmACP_SCRATCH_REG_16 0x1250040
#define mmACP_SCRATCH_REG_17 0x1250044
#define mmACP_SCRATCH_REG_18 0x1250048
#define mmACP_SCRATCH_REG_19 0x125004C
#define mmACP_SCRATCH_REG_20 0x1250050
#define mmACP_SCRATCH_REG_21 0x1250054
#define mmACP_SCRATCH_REG_22 0x1250058
#define mmACP_SCRATCH_REG_23 0x125005C
#define mmACP_SCRATCH_REG_24 0x1250060
#define mmACP_SCRATCH_REG_25 0x1250064
#define mmACP_SCRATCH_REG_26 0x1250068
#define mmACP_SCRATCH_REG_27 0x125006C
#define mmACP_SCRATCH_REG_28 0x1250070
#define mmACP_SCRATCH_REG_29 0x1250074
#define mmACP_SCRATCH_REG_30 0x1250078
#define mmACP_SCRATCH_REG_31 0x125007C
#define mmACP_SCRATCH_REG_32 0x1250080
#define mmACP_SCRATCH_REG_33 0x1250084
#define mmACP_SCRATCH_REG_34 0x1250088
#define mmACP_SCRATCH_REG_35 0x125008C
#define mmACP_SCRATCH_REG_36 0x1250090
#define mmACP_SCRATCH_REG_37 0x1250094
#define mmACP_SCRATCH_REG_38 0x1250098
#define mmACP_SCRATCH_REG_39 0x125009C
#define mmACP_SCRATCH_REG_40 0x12500A0
#define mmACP_SCRATCH_REG_41 0x12500A4
#define mmACP_SCRATCH_REG_42 0x12500A8
#define mmACP_SCRATCH_REG_43 0x12500AC
#define mmACP_SCRATCH_REG_44 0x12500B0
#define mmACP_SCRATCH_REG_45 0x12500B4
#define mmACP_SCRATCH_REG_46 0x12500B8
#define mmACP_SCRATCH_REG_47 0x12500BC
#define mmACP_SCRATCH_REG_48 0x12500C0
#define mmACP_SCRATCH_REG_49 0x12500C4
#define mmACP_SCRATCH_REG_50 0x12500C8
#define mmACP_SCRATCH_REG_51 0x12500CC
#define mmACP_SCRATCH_REG_52 0x12500D0
#define mmACP_SCRATCH_REG_53 0x12500D4
#define mmACP_SCRATCH_REG_54 0x12500D8
#define mmACP_SCRATCH_REG_55 0x12500DC
#define mmACP_SCRATCH_REG_56 0x12500E0
#define mmACP_SCRATCH_REG_57 0x12500E4
#define mmACP_SCRATCH_REG_58 0x12500E8
#define mmACP_SCRATCH_REG_59 0x12500EC
#define mmACP_SCRATCH_REG_60 0x12500F0
#define mmACP_SCRATCH_REG_61 0x12500F4
#define mmACP_SCRATCH_REG_62 0x12500F8
#define mmACP_SCRATCH_REG_63 0x12500FC
#define mmACP_SCRATCH_REG_64 0x1250100
#define mmACP_SCRATCH_REG_65 0x1250104
#define mmACP_SCRATCH_REG_66 0x1250108
#define mmACP_SCRATCH_REG_67 0x125010C
#define mmACP_SCRATCH_REG_68 0x1250110
#define mmACP_SCRATCH_REG_69 0x1250114
#define mmACP_SCRATCH_REG_70 0x1250118
#define mmACP_SCRATCH_REG_71 0x125011C
#define mmACP_SCRATCH_REG_72 0x1250120
#define mmACP_SCRATCH_REG_73 0x1250124
#define mmACP_SCRATCH_REG_74 0x1250128
#define mmACP_SCRATCH_REG_75 0x125012C
#define mmACP_SCRATCH_REG_76 0x1250130
#define mmACP_SCRATCH_REG_77 0x1250134
#define mmACP_SCRATCH_REG_78 0x1250138
#define mmACP_SCRATCH_REG_79 0x125013C
#define mmACP_SCRATCH_REG_80 0x1250140
#define mmACP_SCRATCH_REG_81 0x1250144
#define mmACP_SCRATCH_REG_82 0x1250148
#define mmACP_SCRATCH_REG_83 0x125014C
#define mmACP_SCRATCH_REG_84 0x1250150
#define mmACP_SCRATCH_REG_85 0x1250154
#define mmACP_SCRATCH_REG_86 0x1250158
#define mmACP_SCRATCH_REG_87 0x125015C
#define mmACP_SCRATCH_REG_88 0x1250160
#define mmACP_SCRATCH_REG_89 0x1250164
#define mmACP_SCRATCH_REG_90 0x1250168
#define mmACP_SCRATCH_REG_91 0x125016C
#define mmACP_SCRATCH_REG_92 0x1250170
#define mmACP_SCRATCH_REG_93 0x1250174
#define mmACP_SCRATCH_REG_94 0x1250178
#define mmACP_SCRATCH_REG_95 0x125017C
#define mmACP_SCRATCH_REG_96 0x1250180
#define mmACP_SCRATCH_REG_97 0x1250184
#define mmACP_SCRATCH_REG_98 0x1250188
#define mmACP_SCRATCH_REG_99 0x125018C
#define mmACP_SCRATCH_REG_100 0x1250190
#define mmACP_SCRATCH_REG_101 0x1250194
#define mmACP_SCRATCH_REG_102 0x1250198
#define mmACP_SCRATCH_REG_103 0x125019C
#define mmACP_SCRATCH_REG_104 0x12501A0
#define mmACP_SCRATCH_REG_105 0x12501A4
#define mmACP_SCRATCH_REG_106 0x12501A8
#define mmACP_SCRATCH_REG_107 0x12501AC
#define mmACP_SCRATCH_REG_108 0x12501B0
#define mmACP_SCRATCH_REG_109 0x12501B4
#define mmACP_SCRATCH_REG_110 0x12501B8
#define mmACP_SCRATCH_REG_111 0x12501BC
#define mmACP_SCRATCH_REG_112 0x12501C0
#define mmACP_SCRATCH_REG_113 0x12501C4
#define mmACP_SCRATCH_REG_114 0x12501C8
#define mmACP_SCRATCH_REG_115 0x12501CC
#define mmACP_SCRATCH_REG_116 0x12501D0
#define mmACP_SCRATCH_REG_117 0x12501D4
#define mmACP_SCRATCH_REG_118 0x12501D8
#define mmACP_SCRATCH_REG_119 0x12501DC
#define mmACP_SCRATCH_REG_120 0x12501E0
#define mmACP_SCRATCH_REG_121 0x12501E4
#define mmACP_SCRATCH_REG_122 0x12501E8
#define mmACP_SCRATCH_REG_123 0x12501EC
#define mmACP_SCRATCH_REG_124 0x12501F0
#define mmACP_SCRATCH_REG_125 0x12501F4
#define mmACP_SCRATCH_REG_126 0x12501F8
#define mmACP_SCRATCH_REG_127 0x12501FC
#define mmACP_SCRATCH_REG_128 0x1250200
// Registers from ACP_SW_ACLK block
#define mmSW_CORB_Base_Address 0x1243200
#define mmSW_CORB_Write_Pointer 0x1243204
#define mmSW_CORB_Read_Pointer 0x1243208
#define mmSW_CORB_Control 0x124320C
#define mmSW_CORB_Size 0x1243214
#define mmSW_RIRB_Base_Address 0x1243218
#define mmSW_RIRB_Write_Pointer 0x124321C
#define mmSW_RIRB_Response_Interrupt_Count 0x1243220
#define mmSW_RIRB_Control 0x1243224
#define mmSW_RIRB_Size 0x1243228
#define mmSW_RIRB_FIFO_MIN_THDL 0x124322C
#define mmSW_imm_cmd_UPPER_WORD 0x1243230
#define mmSW_imm_cmd_LOWER_QWORD 0x1243234
#define mmSW_imm_resp_UPPER_WORD 0x1243238
#define mmSW_imm_resp_LOWER_QWORD 0x124323C
#define mmSW_imm_cmd_sts 0x1243240
#define mmSW_BRA_BASE_ADDRESS 0x1243244
#define mmSW_BRA_TRANSFER_SIZE 0x1243248
#define mmSW_BRA_DMA_BUSY 0x124324C
#define mmSW_BRA_RESP 0x1243250
#define mmSW_BRA_RESP_FRAME_ADDR 0x1243254
#define mmSW_BRA_CURRENT_TRANSFER_SIZE 0x1243258
#define mmSW_STATE_CHANGE_STATUS_0TO7 0x124325C
#define mmSW_STATE_CHANGE_STATUS_8TO11 0x1243260
#define mmSW_STATE_CHANGE_STATUS_MASK_0to7 0x1243264
#define mmSW_STATE_CHANGE_STATUS_MASK_8to11 0x1243268
#define mmSW_CLK_FREQUENCY_CTRL 0x124326C
#define mmSW_ERROR_INTR_MASK 0x1243270
#define mmSW_PHY_TEST_MODE_DATA_OFF 0x1243274
// Registers from ACP_SW_SWCLK block
#define mmACP_SW_EN 0x1243000
#define mmACP_SW_EN_STATUS 0x1243004
#define mmACP_SW_FRAMESIZE 0x1243008
#define mmACP_SW_SSP_Counter 0x124300C
#define mmACP_SW_Audio_TX_EN 0x1243010
#define mmACP_SW_Audio_TX_EN_STATUS 0x1243014
#define mmACP_SW_Audio_TX_Frame_Format 0x1243018
#define mmACP_SW_Audio_TX_SampleInterval 0x124301C
#define mmACP_SW_Audio_TX_Hctrl_DP0 0x1243020
#define mmACP_SW_Audio_TX_Hctrl_DP1 0x1243024
#define mmACP_SW_Audio_TX_Hctrl_DP2 0x1243028
#define mmACP_SW_Audio_TX_Hctrl_DP3 0x124302C
#define mmACP_SW_Audio_TX_offset_DP0 0x1243030
#define mmACP_SW_Audio_TX_offset_DP1 0x1243034
#define mmACP_SW_Audio_TX_offset_DP2 0x1243038
#define mmACP_SW_Audio_TX_offset_DP3 0x124303C
#define mmACP_SW_Audio_TX_Channel_Enable_DP0 0x1243040
#define mmACP_SW_Audio_TX_Channel_Enable_DP1 0x1243044
#define mmACP_SW_Audio_TX_Channel_Enable_DP2 0x1243048
#define mmACP_SW_Audio_TX_Channel_Enable_DP3 0x124304C
#define mmACP_SW_BT_TX_EN 0x1243050
#define mmACP_SW_BT_TX_EN_STATUS 0x1243054
#define mmACP_SW_BT_TX_Frame_Format 0x1243058
#define mmACP_SW_BT_TX_SampleInterval 0x124305C
#define mmACP_SW_BT_TX_Hctrl 0x1243060
#define mmACP_SW_BT_TX_offset 0x1243064
#define mmACP_SW_BT_TX_Channel_Enable_DP0 0x1243068
#define mmACP_SW_Headset_TX_EN 0x124306C
#define mmACP_SW_Headset_TX_EN_STATUS 0x1243070
#define mmACP_SW_Headset_TX_Frame_Format 0x1243074
#define mmACP_SW_Headset_TX_SampleInterval 0x1243078
#define mmACP_SW_Headset_TX_Hctrl 0x124307C
#define mmACP_SW_Headset_TX_offset 0x1243080
#define mmACP_SW_Headset_TX_Channel_Enable_DP0 0x1243084
#define mmACP_SW_Audio_RX_EN 0x1243088
#define mmACP_SW_Audio_RX_EN_STATUS 0x124308C
#define mmACP_SW_Audio_RX_Frame_Format 0x1243090
#define mmACP_SW_Audio_RX_SampleInterval 0x1243094
#define mmACP_SW_Audio_RX_Hctrl_DP0 0x1243098
#define mmACP_SW_Audio_RX_Hctrl_DP1 0x124309C
#define mmACP_SW_Audio_RX_Hctrl_DP2 0x1243100
#define mmACP_SW_Audio_RX_Hctrl_DP3 0x1243104
#define mmACP_SW_Audio_RX_offset_DP0 0x1243108
#define mmACP_SW_Audio_RX_offset_DP1 0x124310C
#define mmACP_SW_Audio_RX_offset_DP2 0x1243110
#define mmACP_SW_Audio_RX_offset_DP3 0x1243114
#define mmACP_SW_Audio_RX_Channel_Enable_DP0 0x1243118
#define mmACP_SW_Audio_RX_Channel_Enable_DP1 0x124311C
#define mmACP_SW_Audio_RX_Channel_Enable_DP2 0x1243120
#define mmACP_SW_Audio_RX_Channel_Enable_DP3 0x1243124
#define mmACP_SW_BT_RX_EN 0x1243128
#define mmACP_SW_BT_RX_EN_STATUS 0x124312C
#define mmACP_SW_BT_RX_Frame_Format 0x1243130
#define mmACP_SW_BT_RX_SampleInterval 0x1243134
#define mmACP_SW_BT_RX_Hctrl 0x1243138
#define mmACP_SW_BT_RX_offset 0x124313C
#define mmACP_SW_BT_RX_Channel_Enable_DP0 0x1243140
#define mmACP_SW_Headset_RX_EN 0x1243144
#define mmACP_SW_Headset_RX_EN_STATUS 0x1243148
#define mmACP_SW_Headset_RX_Frame_Format 0x124314C
#define mmACP_SW_Headset_RX_SampleInterval 0x1243150
#define mmACP_SW_Headset_RX_Hctrl 0x1243154
#define mmACP_SW_Headset_RX_offset 0x1243158
#define mmACP_SW_Headset_RX_Channel_Enable_DP0 0x124315C
#define mmACP_SW_BPT_PORT_EN 0x1243160
#define mmACP_SW_BPT_PORT_EN_STATUS 0x1243164
#define mmACP_SW_BPT_PORT_Frame_Format 0x1243168
#define mmACP_SW_BPT_PORT_SampleInterval 0x124316C
#define mmACP_SW_BPT_PORT_Hctrl 0x1243170
#define mmACP_SW_BPT_PORT_offset 0x1243174
#define mmACP_SW_BPT_PORT_Channel_Enable 0x1243178
#define mmACP_SW_BPT_PORT_First_byte_addr 0x124317C
#define mmACP_SW_CLK_RESUME_CTRL 0x1243180
#define mmACP_SW_CLK_RESUME_Delay_Cntr 0x1243184
#define mmACP_SW_BUS_RESET_CTRL 0x1243188
#define mmACP_SW_PRBS_ERR_STATUS 0x124318C
// Registers from ACP_AUDIO_BUFFERS block
#define mmACP_I2S_RX_RINGBUFADDR 0x1242000
#define mmACP_I2S_RX_RINGBUFSIZE 0x1242004
#define mmACP_I2S_RX_LINKPOSITIONCNTR 0x1242008
#define mmACP_I2S_RX_FIFOADDR 0x124200C
#define mmACP_I2S_RX_FIFOSIZE 0x1242010
#define mmACP_I2S_RX_DMA_SIZE 0x1242014
#define mmACP_I2S_RX_LINEARPOSITIONCNTR_HIGH 0x1242018
#define mmACP_I2S_RX_LINEARPOSITIONCNTR_LOW 0x124201C
#define mmACP_I2S_RX_INTR_WATERMARK_SIZE 0x1242020
#define mmACP_I2S_TX_RINGBUFADDR 0x1242024
#define mmACP_I2S_TX_RINGBUFSIZE 0x1242028
#define mmACP_I2S_TX_LINKPOSITIONCNTR 0x124202C
#define mmACP_I2S_TX_FIFOADDR 0x1242030
#define mmACP_I2S_TX_FIFOSIZE 0x1242034
#define mmACP_I2S_TX_DMA_SIZE 0x1242038
#define mmACP_I2S_TX_LINEARPOSITIONCNTR_HIGH 0x124203C
#define mmACP_I2S_TX_LINEARPOSITIONCNTR_LOW 0x1242040
#define mmACP_I2S_TX_INTR_WATERMARK_SIZE 0x1242044
#define mmACP_BT_RX_RINGBUFADDR 0x1242048
#define mmACP_BT_RX_RINGBUFSIZE 0x124204C
#define mmACP_BT_RX_LINKPOSITIONCNTR 0x1242050
#define mmACP_BT_RX_FIFOADDR 0x1242054
#define mmACP_BT_RX_FIFOSIZE 0x1242058
#define mmACP_BT_RX_DMA_SIZE 0x124205C
#define mmACP_BT_RX_LINEARPOSITIONCNTR_HIGH 0x1242060
#define mmACP_BT_RX_LINEARPOSITIONCNTR_LOW 0x1242064
#define mmACP_BT_RX_INTR_WATERMARK_SIZE 0x1242068
#define mmACP_BT_TX_RINGBUFADDR 0x124206C
#define mmACP_BT_TX_RINGBUFSIZE 0x1242070
#define mmACP_BT_TX_LINKPOSITIONCNTR 0x1242074
#define mmACP_BT_TX_FIFOADDR 0x1242078
#define mmACP_BT_TX_FIFOSIZE 0x124207C
#define mmACP_BT_TX_DMA_SIZE 0x1242080
#define mmACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x1242084
#define mmACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x1242088
#define mmACP_BT_TX_INTR_WATERMARK_SIZE 0x124208C
#define mmACP_HS_RX_RINGBUFADDR 0x1242090
#define mmACP_HS_RX_RINGBUFSIZE 0x1242094
#define mmACP_HS_RX_LINKPOSITIONCNTR 0x1242098
#define mmACP_HS_RX_FIFOADDR 0x124209C
#define mmACP_HS_RX_FIFOSIZE 0x12420A0
#define mmACP_HS_RX_DMA_SIZE 0x12420A4
#define mmACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x12420A8
#define mmACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x12420AC
#define mmACP_HS_RX_INTR_WATERMARK_SIZE 0x12420B0
#define mmACP_HS_TX_RINGBUFADDR 0x12420B4
#define mmACP_HS_TX_RINGBUFSIZE 0x12420B8
#define mmACP_HS_TX_LINKPOSITIONCNTR 0x12420BC
#define mmACP_HS_TX_FIFOADDR 0x12420C0
#define mmACP_HS_TX_FIFOSIZE 0x12420C4
#define mmACP_HS_TX_DMA_SIZE 0x12420C8
#define mmACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x12420CC
#define mmACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x12420D0
#define mmACP_HS_TX_INTR_WATERMARK_SIZE 0x12420D4
// Registers from ACP_I2S_TDM block
#define mmACP_I2STDM_IER 0x1242400
#define mmACP_I2STDM_IRER 0x1242404
#define mmACP_I2STDM_RXFRMT 0x1242408
#define mmACP_I2STDM_ITER 0x124240C
#define mmACP_I2STDM_TXFRMT 0x1242410
// Registers from ACP_BT_TDM block
#define mmACP_BTTDM_IER 0x1242800
#define mmACP_BTTDM_IRER 0x1242804
#define mmACP_BTTDM_RXFRMT 0x1242808
#define mmACP_BTTDM_ITER 0x124280C
#define mmACP_BTTDM_TXFRMT 0x1242810
// Registers from AZALIA_IP block
#define mmAudio_Az_Global_Capabilities 0x1200000
#define mmAudio_Az_Minor_Version 0x1200002
#define mmAudio_Az_Major_Version 0x1200003
#define mmAudio_Az_Output_Payload_Capability 0x1200004
#define mmAudio_Az_Input_Payload_Capability 0x1200006
#define mmAudio_Az_Global_Control 0x1200008
#define mmAudio_Az_Wake_Enable 0x120000C
#define mmAudio_Az_State_Change_Status 0x120000E
#define mmAudio_Az_Global_Status 0x1200010
#define mmAudio_Az_Linked_List_Capability_Header 0x1200014
#define mmAudio_Az_Output_Stream_Payload_Capability 0x1200018
#define mmAudio_Az_Input_Stream_Payload_Capability 0x120001A
#define mmAudio_Az_Interrupt_Control 0x1200020
#define mmAudio_Az_Interrupt_Status 0x1200024
#define mmAudio_Az_Wall_Clock_Counter 0x1200030
#define mmAudio_Az_Stream_Synchronization 0x1200038
#define mmAudio_Az_CORB_Lower_Base_Address 0x1200040
#define mmAudio_Az_CORB_Upper_Base_Address 0x1200044
#define mmAudio_Az_CORB_Write_Pointer 0x1200048
#define mmAudio_Az_CORB_Read_Pointer 0x120004A
#define mmAudio_Az_CORB_Control 0x120004C
#define mmAudio_Az_CORB_Status 0x120004D
#define mmAudio_Az_CORB_Size 0x120004E
#define mmAudio_Az_RIRB_Lower_Base_Address 0x1200050
#define mmAudio_Az_RIRB_Upper_Base_Address 0x1200054
#define mmAudio_Az_RIRB_Write_Pointer 0x1200058
#define mmAudio_Az_RIRB_Response_Interrupt_Count 0x120005A
#define mmAudio_Az_RIRB_Control 0x120005C
#define mmAudio_Az_RIRB_Status 0x120005D
#define mmAudio_Az_RIRB_Size 0x120005E
#define mmAudio_Az_Immediate_Command_Output_Interface 0x1200060
#define mmAudio_Az_Immediate_Response_Input_Interface 0x1200064
#define mmAudio_Az_Immediate_Command_Status 0x1200068
#define mmAudio_Az_DPLBASE 0x1200070
#define mmAudio_Az_DPUBASE 0x1200074
#define mmAudio_Az_Input_SD0CTL_and_STS 0x1200080
#define mmAudio_Az_Input_SD0LPIB 0x1200084
#define mmAudio_Az_Input_SD0CBL 0x1200088
#define mmAudio_Az_Input_SD0LVI 0x120008C
#define mmAudio_Az_Input_SD0FIFOS 0x1200090
#define mmAudio_Az_Input_SD0FMT 0x1200092
#define mmAudio_Az_Input_SD0BDPL 0x1200098
#define mmAudio_Az_Input_SD0BDPU 0x120009C
#define mmAudio_Az_Input_SD1CTL_and_STS 0x12000A0
#define mmAudio_Az_Input_SD1LPIB 0x12000A4
#define mmAudio_Az_Input_SD1CBL 0x12000A8
#define mmAudio_Az_Input_SD1LVI 0x12000AC
#define mmAudio_Az_Input_SD1FIFOS 0x12000B0
#define mmAudio_Az_Input_SD1FMT 0x12000B2
#define mmAudio_Az_Input_SD1BDPL 0x12000B8
#define mmAudio_Az_Input_SD1BDPU 0x12000BC
#define mmAudio_Az_Input_SD2CTL_and_STS 0x12000C0
#define mmAudio_Az_Input_SD2LPIB 0x12000C4
#define mmAudio_Az_Input_SD2CBL 0x12000C8
#define mmAudio_Az_Input_SD2LVI 0x12000CC
#define mmAudio_Az_Input_SD2FIFOS 0x12000D0
#define mmAudio_Az_Input_SD2FMT 0x12000D2
#define mmAudio_Az_Input_SD2BDPL 0x12000D8
#define mmAudio_Az_Input_SD2BDPU 0x12000DC
#define mmAudio_Az_Input_SD3CTL_and_STS 0x12000E0
#define mmAudio_Az_Input_SD3LPIB 0x12000E4
#define mmAudio_Az_Input_SD3CBL 0x12000E8
#define mmAudio_Az_Input_SD3LVI 0x12000EC
#define mmAudio_Az_Input_SD3FIFOS 0x12000F0
#define mmAudio_Az_Input_SD3FMT 0x12000F2
#define mmAudio_Az_Input_SD3BDPL 0x12000F8
#define mmAudio_Az_Input_SD3BDPU 0x12000FC
#define mmAudio_Az_Output_SD0CTL_and_STS 0x1200100
#define mmAudio_Az_Output_SD0LPIB 0x1200104
#define mmAudio_Az_Output_SD0CBL 0x1200108
#define mmAudio_Az_Output_SD0LVI 0x120010C
#define mmAudio_Az_Output_SD0FIFOS 0x1200110
#define mmAudio_Az_Output_SD0FMT 0x1200112
#define mmAudio_Az_Output_SD0BDPL 0x1200118
#define mmAudio_Az_Output_SD0BDPU 0x120011C
#define mmAudio_Az_Output_SD1CTL_and_STS 0x1200120
#define mmAudio_Az_Output_SD1LPIB 0x1200124
#define mmAudio_Az_Output_SD1CBL 0x1200128
#define mmAudio_Az_Output_SD1LVI 0x120012C
#define mmAudio_Az_Output_SD1FIFOS 0x1200130
#define mmAudio_Az_Output_SD1FMT 0x1200132
#define mmAudio_Az_Output_SD1BDPL 0x1200138
#define mmAudio_Az_Output_SD1BDPU 0x120013C
#define mmAudio_Az_Output_SD2CTL_and_STS 0x1200140
#define mmAudio_Az_Output_SD2LPIB 0x1200144
#define mmAudio_Az_Output_SD2CBL 0x1200148
#define mmAudio_Az_Output_SD2LVI 0x120014C
#define mmAudio_Az_Output_SD2FIFOS 0x1200150
#define mmAudio_Az_Output_SD2FMT 0x1200152
#define mmAudio_Az_Output_SD2BDPL 0x1200158
#define mmAudio_Az_Output_SD2BDPU 0x120015C
#define mmAudio_Az_Output_SD3CTL_and_STS 0x1200160
#define mmAudio_Az_Output_SD3LPIB 0x1200164
#define mmAudio_Az_Output_SD3CBL 0x1200168
#define mmAudio_Az_Output_SD3LVI 0x120016C
#define mmAudio_Az_Output_SD3FIFOS 0x1200170
#define mmAudio_Az_Output_SD3FMT 0x1200172
#define mmAudio_Az_Output_SD3BDPL 0x1200178
#define mmAudio_Az_Output_SD3BDPU 0x120017C
#define mmAudioAZ_Misc_Control_Register_1 0x1200180
#define mmAudioAZ_Misc_Control_Register_2 0x1200182
#define mmAudioAZ_Misc_Control_Register_3 0x1200183
#define mmAudio_AZ_Multiple_Links_Capability_Header 0x1200200
#define mmAudio_AZ_Multiple_Links_Capability_Declaration 0x1200204
#define mmAudio_AZ_Link0_Capabilities 0x1200240
#define mmAudio_AZ_Link0_Control 0x1200244
#define mmAudio_AZ_Link0_Output_Stream_ID 0x1200248
#define mmAudio_AZ_Link0_SDI_Identifier 0x120024C
#define mmAudio_AZ_Link0_Per_Stream_Overhead 0x1200250
#define mmAudio_AZ_Link0_Wall_Frame_Counter 0x1200258
#define mmAudio_AZ_Link0_Output_Payload_Capability_L 0x1200260
#define mmAudio_AZ_Link0_Output_Payload_Capability_U 0x1200264
#define mmAudio_AZ_Link0_Input_Payload_Capability_L 0x1200270
#define mmAudio_AZ_Link0_Input_Payload_Capability_U 0x1200274
#define mmAudio_Az_Input_SD0LICBA 0x1202084
#define mmAudio_Az_Input_SD1LICBA 0x12020A4
#define mmAudio_Az_Input_SD2LICBA 0x12020C4
#define mmAudio_Az_Input_SD3LICBA 0x12020E4
#define mmAudio_Az_Output_SD0LICBA 0x1202104
#define mmAudio_Az_Output_SD1LICBA 0x1202124
#define mmAudio_Az_Output_SD2LICBA 0x1202144
#define mmAudio_Az_Output_SD3LICBA 0x1202164
#define mmAUDIO_AZ_POWER_MANAGEMENT_CONTROL 0x1204000
#define mmAUDIO_AZ_IOC_SOFTRST_CONTROL 0x1204004
#define mmAUDIO_AZ_IOC_CLKGATE_CONTROL 0x1204008
// Registers from ACP_AZALIA block
#define mmACP_AZ_PAGE0_LBASE_ADDR 0x1243800
#define mmACP_AZ_PAGE0_UBASE_ADDR 0x1243804
#define mmACP_AZ_PAGE0_PGEN_SIZE 0x1243808
#define mmACP_AZ_PAGE0_OFFSET 0x124380C
#define mmACP_AZ_PAGE1_LBASE_ADDR 0x1243810
#define mmACP_AZ_PAGE1_UBASE_ADDR 0x1243814
#define mmACP_AZ_PAGE1_PGEN_SIZE 0x1243818
#define mmACP_AZ_PAGE1_OFFSET 0x124381C
#define mmACP_AZ_PAGE2_LBASE_ADDR 0x1243820
#define mmACP_AZ_PAGE2_UBASE_ADDR 0x1243824
#define mmACP_AZ_PAGE2_PGEN_SIZE 0x1243828
#define mmACP_AZ_PAGE2_OFFSET 0x124382C
#define mmACP_AZ_PAGE3_LBASE_ADDR 0x1243830
#define mmACP_AZ_PAGE3_UBASE_ADDR 0x1243834
#define mmACP_AZ_PAGE3_PGEN_SIZE 0x1243838
#define mmACP_AZ_PAGE3_OFFSET 0x124383C
#define mmACP_AZ_PAGE4_LBASE_ADDR 0x1243840
#define mmACP_AZ_PAGE4_UBASE_ADDR 0x1243844
#define mmACP_AZ_PAGE4_PGEN_SIZE 0x1243848
#define mmACP_AZ_PAGE4_OFFSET 0x124384C
#define mmACP_AZ_PAGE5_LBASE_ADDR 0x1243850
#define mmACP_AZ_PAGE5_UBASE_ADDR 0x1243854
#define mmACP_AZ_PAGE5_PGEN_SIZE 0x1243858
#define mmACP_AZ_PAGE5_OFFSET 0x124385C
#define mmACP_AZ_PAGE6_LBASE_ADDR 0x1243860
#define mmACP_AZ_PAGE6_UBASE_ADDR 0x1243864
#define mmACP_AZ_PAGE6_PGEN_SIZE 0x1243868
#define mmACP_AZ_PAGE6_OFFSET 0x124386C
#define mmACP_AZ_PAGE7_LBASE_ADDR 0x1243870
#define mmACP_AZ_PAGE7_UBASE_ADDR 0x1243874
#define mmACP_AZ_PAGE7_PGEN_SIZE 0x1243878
#define mmACP_AZ_PAGE7_OFFSET 0x124387C
#endif

View File

@ -0,0 +1,156 @@
// SPDX-License-Identifier: GPL-2.0+
//
// AMD ACP PCI Driver
//
//Copyright 2016 Advanced Micro Devices, Inc.
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include "acp3x.h"
struct acp3x_dev_data {
void __iomem *acp3x_base;
bool acp3x_audio_mode;
struct resource *res;
struct platform_device *pdev;
};
static int snd_acp3x_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
int ret;
u32 addr, val;
struct acp3x_dev_data *adata;
struct platform_device_info pdevinfo;
unsigned int irqflags;
if (pci_enable_device(pci)) {
dev_err(&pci->dev, "pci_enable_device failed\n");
return -ENODEV;
}
ret = pci_request_regions(pci, "AMD ACP3x audio");
if (ret < 0) {
dev_err(&pci->dev, "pci_request_regions failed\n");
goto disable_pci;
}
adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data),
GFP_KERNEL);
if (!adata) {
ret = -ENOMEM;
goto release_regions;
}
/* check for msi interrupt support */
ret = pci_enable_msi(pci);
if (ret)
/* msi is not enabled */
irqflags = IRQF_SHARED;
else
/* msi is enabled */
irqflags = 0;
addr = pci_resource_start(pci, 0);
adata->acp3x_base = ioremap(addr, pci_resource_len(pci, 0));
if (!adata->acp3x_base) {
ret = -ENOMEM;
goto release_regions;
}
pci_set_master(pci);
pci_set_drvdata(pci, adata);
val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
switch (val) {
case I2S_MODE:
adata->res = devm_kzalloc(&pci->dev,
sizeof(struct resource) * 2,
GFP_KERNEL);
if (!adata->res) {
ret = -ENOMEM;
goto unmap_mmio;
}
adata->res[0].name = "acp3x_i2s_iomem";
adata->res[0].flags = IORESOURCE_MEM;
adata->res[0].start = addr;
adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START);
adata->res[1].name = "acp3x_i2s_irq";
adata->res[1].flags = IORESOURCE_IRQ;
adata->res[1].start = pci->irq;
adata->res[1].end = pci->irq;
adata->acp3x_audio_mode = ACP3x_I2S_MODE;
memset(&pdevinfo, 0, sizeof(pdevinfo));
pdevinfo.name = "acp3x_rv_i2s";
pdevinfo.id = 0;
pdevinfo.parent = &pci->dev;
pdevinfo.num_res = 2;
pdevinfo.res = adata->res;
pdevinfo.data = &irqflags;
pdevinfo.size_data = sizeof(irqflags);
adata->pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(adata->pdev)) {
dev_err(&pci->dev, "cannot register %s device\n",
pdevinfo.name);
ret = PTR_ERR(adata->pdev);
goto unmap_mmio;
}
break;
default:
dev_err(&pci->dev, "Invalid ACP audio mode : %d\n", val);
ret = -ENODEV;
goto unmap_mmio;
}
return 0;
unmap_mmio:
pci_disable_msi(pci);
iounmap(adata->acp3x_base);
release_regions:
pci_release_regions(pci);
disable_pci:
pci_disable_device(pci);
return ret;
}
static void snd_acp3x_remove(struct pci_dev *pci)
{
struct acp3x_dev_data *adata = pci_get_drvdata(pci);
platform_device_unregister(adata->pdev);
iounmap(adata->acp3x_base);
pci_disable_msi(pci);
pci_release_regions(pci);
pci_disable_device(pci);
}
static const struct pci_device_id snd_acp3x_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2),
.class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
.class_mask = 0xffffff },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, snd_acp3x_ids);
static struct pci_driver acp3x_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_acp3x_ids,
.probe = snd_acp3x_probe,
.remove = snd_acp3x_remove,
};
module_pci_driver(acp3x_driver);
MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
MODULE_DESCRIPTION("AMD ACP3x PCI driver");
MODULE_LICENSE("GPL v2");

View File

@ -35,6 +35,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ADAU7002
select SND_SOC_ADS117X
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4118 if I2C
select SND_SOC_AK4458 if I2C
select SND_SOC_AK4535 if I2C
select SND_SOC_AK4554
@ -392,6 +393,11 @@ config SND_SOC_AK4104
tristate "AKM AK4104 CODEC"
depends on SPI_MASTER
config SND_SOC_AK4118
tristate "AKM AK4118 CODEC"
depends on I2C
select REGMAP_I2C
config SND_SOC_AK4458
tristate "AKM AK4458 CODEC"
depends on I2C

View File

@ -27,6 +27,7 @@ snd-soc-adav801-objs := adav801.o
snd-soc-adav803-objs := adav803.o
snd-soc-ads117x-objs := ads117x.o
snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4118-objs := ak4118.o
snd-soc-ak4458-objs := ak4458.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4554-objs := ak4554.o
@ -290,6 +291,7 @@ obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4118) += snd-soc-ak4118.o
obj-$(CONFIG_SND_SOC_AK4458) += snd-soc-ak4458.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o

View File

@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <sound/asoundef.h>
#include <sound/core.h>
@ -268,8 +268,8 @@ static const struct regmap_config ak4104_regmap = {
static int ak4104_spi_probe(struct spi_device *spi)
{
struct device_node *np = spi->dev.of_node;
struct ak4104_private *ak4104;
struct gpio_desc *reset_gpiod;
unsigned int val;
int ret;
@ -297,19 +297,11 @@ static int ak4104_spi_probe(struct spi_device *spi)
return ret;
}
if (np) {
enum of_gpio_flags flags;
int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
if (gpio_is_valid(gpio)) {
ret = devm_gpio_request_one(&spi->dev, gpio,
flags & OF_GPIO_ACTIVE_LOW ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
"ak4104 reset");
if (ret < 0)
return ret;
}
}
reset_gpiod = devm_gpiod_get_optional(&spi->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpiod) &&
PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
return -EPROBE_DEFER;
/* read the 'reserved' register - according to the datasheet, it
* should contain 0x5b. Not a good way to verify the presence of

438
sound/soc/codecs/ak4118.c Normal file
View File

@ -0,0 +1,438 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ak4118.c -- Asahi Kasei ALSA Soc Audio driver
*
* Copyright 2018 DEVIALET
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/asoundef.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/soc.h>
#define AK4118_REG_CLK_PWR_CTL 0x00
#define AK4118_REG_FORMAT_CTL 0x01
#define AK4118_REG_IO_CTL0 0x02
#define AK4118_REG_IO_CTL1 0x03
#define AK4118_REG_INT0_MASK 0x04
#define AK4118_REG_INT1_MASK 0x05
#define AK4118_REG_RCV_STATUS0 0x06
#define AK4118_REG_RCV_STATUS1 0x07
#define AK4118_REG_RXCHAN_STATUS0 0x08
#define AK4118_REG_RXCHAN_STATUS1 0x09
#define AK4118_REG_RXCHAN_STATUS2 0x0a
#define AK4118_REG_RXCHAN_STATUS3 0x0b
#define AK4118_REG_RXCHAN_STATUS4 0x0c
#define AK4118_REG_TXCHAN_STATUS0 0x0d
#define AK4118_REG_TXCHAN_STATUS1 0x0e
#define AK4118_REG_TXCHAN_STATUS2 0x0f
#define AK4118_REG_TXCHAN_STATUS3 0x10
#define AK4118_REG_TXCHAN_STATUS4 0x11
#define AK4118_REG_BURST_PREAMB_PC0 0x12
#define AK4118_REG_BURST_PREAMB_PC1 0x13
#define AK4118_REG_BURST_PREAMB_PD0 0x14
#define AK4118_REG_BURST_PREAMB_PD1 0x15
#define AK4118_REG_QSUB_CTL 0x16
#define AK4118_REG_QSUB_TRACK 0x17
#define AK4118_REG_QSUB_INDEX 0x18
#define AK4118_REG_QSUB_MIN 0x19
#define AK4118_REG_QSUB_SEC 0x1a
#define AK4118_REG_QSUB_FRAME 0x1b
#define AK4118_REG_QSUB_ZERO 0x1c
#define AK4118_REG_QSUB_ABS_MIN 0x1d
#define AK4118_REG_QSUB_ABS_SEC 0x1e
#define AK4118_REG_QSUB_ABS_FRAME 0x1f
#define AK4118_REG_GPE 0x20
#define AK4118_REG_GPDR 0x21
#define AK4118_REG_GPSCR 0x22
#define AK4118_REG_GPLR 0x23
#define AK4118_REG_DAT_MASK_DTS 0x24
#define AK4118_REG_RX_DETECT 0x25
#define AK4118_REG_STC_DAT_DETECT 0x26
#define AK4118_REG_RXCHAN_STATUS5 0x27
#define AK4118_REG_TXCHAN_STATUS5 0x28
#define AK4118_REG_MAX 0x29
#define AK4118_REG_FORMAT_CTL_DIF0 (1 << 4)
#define AK4118_REG_FORMAT_CTL_DIF1 (1 << 5)
#define AK4118_REG_FORMAT_CTL_DIF2 (1 << 6)
struct ak4118_priv {
struct regmap *regmap;
struct gpio_desc *reset;
struct gpio_desc *irq;
struct snd_soc_component *component;
};
static const struct reg_default ak4118_reg_defaults[] = {
{AK4118_REG_CLK_PWR_CTL, 0x43},
{AK4118_REG_FORMAT_CTL, 0x6a},
{AK4118_REG_IO_CTL0, 0x88},
{AK4118_REG_IO_CTL1, 0x48},
{AK4118_REG_INT0_MASK, 0xee},
{AK4118_REG_INT1_MASK, 0xb5},
{AK4118_REG_RCV_STATUS0, 0x00},
{AK4118_REG_RCV_STATUS1, 0x10},
{AK4118_REG_TXCHAN_STATUS0, 0x00},
{AK4118_REG_TXCHAN_STATUS1, 0x00},
{AK4118_REG_TXCHAN_STATUS2, 0x00},
{AK4118_REG_TXCHAN_STATUS3, 0x00},
{AK4118_REG_TXCHAN_STATUS4, 0x00},
{AK4118_REG_GPE, 0x77},
{AK4118_REG_GPDR, 0x00},
{AK4118_REG_GPSCR, 0x00},
{AK4118_REG_GPLR, 0x00},
{AK4118_REG_DAT_MASK_DTS, 0x3f},
{AK4118_REG_RX_DETECT, 0x00},
{AK4118_REG_STC_DAT_DETECT, 0x00},
{AK4118_REG_TXCHAN_STATUS5, 0x00},
};
static const char * const ak4118_input_select_txt[] = {
"RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7",
};
static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0,
ak4118_input_select_txt);
static const struct snd_kcontrol_new ak4118_input_mux_controls =
SOC_DAPM_ENUM("Input Select", ak4118_insel_enum);
static const char * const ak4118_iec958_fs_txt[] = {
"44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200",
"8000", "96000", "64000", "176400", "192000",
};
static const int ak4118_iec958_fs_val[] = {
0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE,
};
static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1,
0x4, 0x4, ak4118_iec958_fs_txt,
ak4118_iec958_fs_val);
static struct snd_kcontrol_new ak4118_iec958_controls[] = {
SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0),
SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0),
SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1),
SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0),
SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum),
};
static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("INRX0"),
SND_SOC_DAPM_INPUT("INRX1"),
SND_SOC_DAPM_INPUT("INRX2"),
SND_SOC_DAPM_INPUT("INRX3"),
SND_SOC_DAPM_INPUT("INRX4"),
SND_SOC_DAPM_INPUT("INRX5"),
SND_SOC_DAPM_INPUT("INRX6"),
SND_SOC_DAPM_INPUT("INRX7"),
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
&ak4118_input_mux_controls),
};
static const struct snd_soc_dapm_route ak4118_dapm_routes[] = {
{"Input Mux", "RX0", "INRX0"},
{"Input Mux", "RX1", "INRX1"},
{"Input Mux", "RX2", "INRX2"},
{"Input Mux", "RX3", "INRX3"},
{"Input Mux", "RX4", "INRX4"},
{"Input Mux", "RX5", "INRX5"},
{"Input Mux", "RX6", "INRX6"},
{"Input Mux", "RX7", "INRX7"},
};
static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118,
unsigned int format)
{
int dif;
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2;
break;
case SND_SOC_DAIFMT_RIGHT_J:
dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1;
break;
case SND_SOC_DAIFMT_LEFT_J:
dif = AK4118_REG_FORMAT_CTL_DIF2;
break;
default:
return -ENOTSUPP;
}
return dif;
}
static int ak4118_set_dai_fmt_slave(struct ak4118_priv *ak4118,
unsigned int format)
{
int dif;
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 |
AK4118_REG_FORMAT_CTL_DIF2;
break;
case SND_SOC_DAIFMT_LEFT_J:
dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2;
break;
default:
return -ENOTSUPP;
}
return dif;
}
static int ak4118_set_dai_fmt(struct snd_soc_dai *dai,
unsigned int format)
{
struct snd_soc_component *component = dai->component;
struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
int dif;
int ret = 0;
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
/* component is master */
dif = ak4118_set_dai_fmt_master(ak4118, format);
break;
case SND_SOC_DAIFMT_CBS_CFS:
/*component is slave */
dif = ak4118_set_dai_fmt_slave(ak4118, format);
break;
default:
ret = -ENOTSUPP;
goto exit;
}
/* format not supported */
if (dif < 0) {
ret = dif;
goto exit;
}
ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL,
AK4118_REG_FORMAT_CTL_DIF0 |
AK4118_REG_FORMAT_CTL_DIF1 |
AK4118_REG_FORMAT_CTL_DIF2, dif);
if (ret < 0)
goto exit;
exit:
return ret;
}
static int ak4118_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
return 0;
}
static const struct snd_soc_dai_ops ak4118_dai_ops = {
.hw_params = ak4118_hw_params,
.set_fmt = ak4118_set_dai_fmt,
};
static struct snd_soc_dai_driver ak4118_dai = {
.name = "ak4118-hifi",
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_3LE |
SNDRV_PCM_FMTBIT_S24_LE
},
.ops = &ak4118_dai_ops,
};
static irqreturn_t ak4118_irq_handler(int irq, void *data)
{
struct ak4118_priv *ak4118 = data;
struct snd_soc_component *component = ak4118->component;
struct snd_kcontrol_new *kctl_new;
struct snd_kcontrol *kctl;
struct snd_ctl_elem_id *id;
unsigned int i;
if (!component)
return IRQ_NONE;
for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
kctl_new = &ak4118_iec958_controls[i];
kctl = snd_soc_card_get_kcontrol(component->card,
kctl_new->name);
if (!kctl)
continue;
id = &kctl->id;
snd_ctl_notify(component->card->snd_card,
SNDRV_CTL_EVENT_MASK_VALUE, id);
}
return IRQ_HANDLED;
}
static int ak4118_probe(struct snd_soc_component *component)
{
struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
int ret = 0;
ak4118->component = component;
/* release reset */
gpiod_set_value(ak4118->reset, 0);
/* unmask all int1 sources */
ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00);
if (ret < 0) {
dev_err(component->dev,
"failed to write regmap 0x%x 0x%x: %d\n",
AK4118_REG_INT1_MASK, 0x00, ret);
return ret;
}
/* rx detect enable on all channels */
ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff);
if (ret < 0) {
dev_err(component->dev,
"failed to write regmap 0x%x 0x%x: %d\n",
AK4118_REG_RX_DETECT, 0xff, ret);
return ret;
}
ret = snd_soc_add_component_controls(component, ak4118_iec958_controls,
ARRAY_SIZE(ak4118_iec958_controls));
if (ret) {
dev_err(component->dev,
"failed to add component kcontrols: %d\n", ret);
return ret;
}
return 0;
}
static void ak4118_remove(struct snd_soc_component *component)
{
struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
/* hold reset */
gpiod_set_value(ak4118->reset, 1);
}
static const struct snd_soc_component_driver soc_component_drv_ak4118 = {
.probe = ak4118_probe,
.remove = ak4118_remove,
.dapm_widgets = ak4118_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak4118_dapm_widgets),
.dapm_routes = ak4118_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(ak4118_dapm_routes),
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static const struct regmap_config ak4118_regmap = {
.reg_bits = 8,
.val_bits = 8,
.reg_defaults = ak4118_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults),
.cache_type = REGCACHE_NONE,
.max_register = AK4118_REG_MAX - 1,
};
static int ak4118_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct ak4118_priv *ak4118;
int ret;
ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv),
GFP_KERNEL);
if (ak4118 == NULL)
return -ENOMEM;
ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap);
if (IS_ERR(ak4118->regmap))
return PTR_ERR(ak4118->regmap);
i2c_set_clientdata(i2c, ak4118);
ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ak4118->reset)) {
ret = PTR_ERR(ak4118->reset);
if (ret != -EPROBE_DEFER)
dev_err(&i2c->dev, "Failed to get reset: %d\n", ret);
return ret;
}
ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN);
if (IS_ERR(ak4118->irq)) {
ret = PTR_ERR(ak4118->irq);
if (ret != -EPROBE_DEFER)
dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret);
return ret;
}
ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq),
NULL, ak4118_irq_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"ak4118-irq", ak4118);
if (ret < 0) {
dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret);
return ret;
}
return snd_soc_register_component(&i2c->dev, &soc_component_drv_ak4118,
&ak4118_dai, 1);
}
static int ak4118_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_component(&i2c->dev);
return 0;
}
static const struct of_device_id ak4118_of_match[] = {
{ .compatible = "asahi-kasei,ak4118", },
{}
};
MODULE_DEVICE_TABLE(of, ak4118_of_match);
static const struct i2c_device_id ak4118_id_table[] = {
{ "ak4118", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ak4118_id_table);
static struct i2c_driver ak4118_i2c_driver = {
.driver = {
.name = "ak4118",
.of_match_table = of_match_ptr(ak4118_of_match),
},
.id_table = ak4118_id_table,
.probe = ak4118_i2c_probe,
.remove = ak4118_i2c_remove,
};
module_i2c_driver(ak4118_i2c_driver);
MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver");
MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>");
MODULE_LICENSE("GPL");

View File

@ -456,7 +456,7 @@ static int ak4458_startup(struct snd_pcm_substream *substream,
return ret;
}
static struct snd_soc_dai_ops ak4458_dai_ops = {
static const struct snd_soc_dai_ops ak4458_dai_ops = {
.startup = ak4458_startup,
.hw_params = ak4458_hw_params,
.set_fmt = ak4458_set_dai_fmt,

View File

@ -130,16 +130,12 @@ static int ak5558_hw_params(struct snd_pcm_substream *substream,
u8 bits;
int pcm_width = max(params_physical_width(params), ak5558->slot_width);
/* set master/slave audio interface */
bits = snd_soc_component_read32(component, AK5558_02_CONTROL1);
bits &= ~AK5558_BITS;
switch (pcm_width) {
case 16:
bits |= AK5558_DIF_24BIT_MODE;
bits = AK5558_DIF_24BIT_MODE;
break;
case 32:
bits |= AK5558_DIF_32BIT_MODE;
bits = AK5558_DIF_32BIT_MODE;
break;
default:
return -EINVAL;
@ -168,18 +164,15 @@ static int ak5558_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
/* set master/slave audio interface */
format = snd_soc_component_read32(component, AK5558_02_CONTROL1);
format &= ~AK5558_DIF;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
format |= AK5558_DIF_I2S_MODE;
format = AK5558_DIF_I2S_MODE;
break;
case SND_SOC_DAIFMT_LEFT_J:
format |= AK5558_DIF_MSB_MODE;
format = AK5558_DIF_MSB_MODE;
break;
case SND_SOC_DAIFMT_DSP_B:
format |= AK5558_DIF_MSB_MODE;
format = AK5558_DIF_MSB_MODE;
break;
default:
return -EINVAL;
@ -246,7 +239,7 @@ static int ak5558_startup(struct snd_pcm_substream *substream,
&ak5558_rate_constraints);
}
static struct snd_soc_dai_ops ak5558_dai_ops = {
static const struct snd_soc_dai_ops ak5558_dai_ops = {
.startup = ak5558_startup,
.hw_params = ak5558_hw_params,

View File

@ -29,8 +29,8 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
/*
* The codec isn't really big-endian or little-endian, since the I2S
@ -658,8 +658,8 @@ static const struct regmap_config cs4270_regmap = {
static int cs4270_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct device_node *np = i2c_client->dev.of_node;
struct cs4270_private *cs4270;
struct gpio_desc *reset_gpiod;
unsigned int val;
int ret, i;
@ -678,20 +678,11 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
if (ret < 0)
return ret;
/* See if we have a way to bring the codec out of reset */
if (np) {
enum of_gpio_flags flags;
int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
if (gpio_is_valid(gpio)) {
ret = devm_gpio_request_one(&i2c_client->dev, gpio,
flags & OF_GPIO_ACTIVE_LOW ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
"cs4270 reset");
if (ret < 0)
return ret;
}
}
reset_gpiod = devm_gpiod_get_optional(&i2c_client->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpiod) &&
PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
return -EPROBE_DEFER;
cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
if (IS_ERR(cs4270->regmap))

View File

@ -30,9 +30,39 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#define MAX_MODESWITCH_DELAY 70
static int modeswitch_delay;
module_param(modeswitch_delay, uint, 0644);
static int wakeup_delay;
module_param(wakeup_delay, uint, 0644);
struct dmic {
struct gpio_desc *gpio_en;
int wakeup_delay;
/* Delay after DMIC mode switch */
int modeswitch_delay;
};
int dmic_daiops_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct dmic *dmic = snd_soc_component_get_drvdata(component);
switch (cmd) {
case SNDRV_PCM_TRIGGER_STOP:
if (dmic->modeswitch_delay)
mdelay(dmic->modeswitch_delay);
break;
}
return 0;
}
static const struct snd_soc_dai_ops dmic_dai_ops = {
.trigger = dmic_daiops_trigger,
};
static int dmic_aif_event(struct snd_soc_dapm_widget *w,
@ -68,6 +98,7 @@ static struct snd_soc_dai_driver dmic_dai = {
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &dmic_dai_ops,
};
static int dmic_component_probe(struct snd_soc_component *component)
@ -85,6 +116,15 @@ static int dmic_component_probe(struct snd_soc_component *component)
device_property_read_u32(component->dev, "wakeup-delay-ms",
&dmic->wakeup_delay);
device_property_read_u32(component->dev, "modeswitch-delay-ms",
&dmic->modeswitch_delay);
if (wakeup_delay)
dmic->wakeup_delay = wakeup_delay;
if (modeswitch_delay)
dmic->modeswitch_delay = modeswitch_delay;
if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY)
dmic->modeswitch_delay = MAX_MODESWITCH_DELAY;
snd_soc_component_set_drvdata(component, dmic);

View File

@ -46,7 +46,7 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai,
static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt,
struct snd_soc_dai *dai);
static struct snd_soc_dai_ops hdac_hda_dai_ops = {
static const struct snd_soc_dai_ops hdac_hda_dai_ops = {
.startup = hdac_hda_dai_open,
.shutdown = hdac_hda_dai_close,
.prepare = hdac_hda_dai_prepare,

View File

@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map {
struct hdac_hdmi_cvt *cvt;
};
/*
* pin to port mapping table where the value indicate the pin number and
* the index indicate the port number with 1 base.
*/
static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb};
struct hdac_hdmi_drv_data {
unsigned int vendor_nid;
const int *port_map; /* pin to port mapping table */
int port_num;
};
struct hdac_hdmi_priv {
@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid)
return 0;
}
#define INTEL_VENDOR_NID 0x08
#define INTEL_GLK_VENDOR_NID 0x0b
#define INTEL_VENDOR_NID_0x2 0x02
#define INTEL_VENDOR_NID_0x8 0x08
#define INTEL_VENDOR_NID_0xb 0x0b
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev)
@ -1538,7 +1547,26 @@ free_widgets:
static int hdac_hdmi_pin2port(void *aptr, int pin)
{
return pin - 4; /* map NID 0x05 -> port #1 */
struct hdac_device *hdev = aptr;
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
const int *map = hdmi->drv_data->port_map;
int i;
if (!hdmi->drv_data->port_num)
return pin - 4; /* map NID 0x05 -> port #1 */
/*
* looking for the pin number in the mapping table and return
* the index which indicate the port number
*/
for (i = 0; i < hdmi->drv_data->port_num; i++) {
if (pin == map[i])
return i + 1;
}
/* return -1 if pin number exceeds our expectation */
dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin);
return -1;
}
static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
struct hdac_hdmi_port *hport = NULL;
struct snd_soc_component *component = hdmi->component;
int i;
hda_nid_t pin_nid;
/* Don't know how this mapping is derived */
hda_nid_t pin_nid = port + 0x04;
if (!hdmi->drv_data->port_num) {
/* for legacy platforms */
pin_nid = port + 0x04;
} else if (port < hdmi->drv_data->port_num) {
/* get pin number from the pin2port mapping table */
pin_nid = hdmi->drv_data->port_map[port - 1];
} else {
dev_err(&hdev->dev, "Can't find the pin for port %d\n", port);
return;
}
dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__,
pin_nid, pipe);
@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx)
return port->eld.info.spk_alloc;
}
static struct hdac_hdmi_drv_data intel_icl_drv_data = {
.vendor_nid = INTEL_VENDOR_NID_0x2,
.port_map = icl_pin2port_map,
.port_num = ARRAY_SIZE(icl_pin2port_map),
};
static struct hdac_hdmi_drv_data intel_glk_drv_data = {
.vendor_nid = INTEL_GLK_VENDOR_NID,
.vendor_nid = INTEL_VENDOR_NID_0xb,
};
static struct hdac_hdmi_drv_data intel_drv_data = {
.vendor_nid = INTEL_VENDOR_NID,
.vendor_nid = INTEL_VENDOR_NID_0x8,
};
static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
@ -2258,6 +2301,8 @@ static const struct hda_device_id hdmi_list[] = {
&intel_glk_drv_data),
HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
&intel_glk_drv_data),
HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI",
&intel_icl_drv_data),
{}
};

View File

@ -724,14 +724,39 @@ static struct snd_soc_dai_driver max98373_dai[] = {
}
};
static void max98373_reset(struct max98373_priv *max98373, struct device *dev)
{
int ret, reg, count;
/* Software Reset */
ret = regmap_update_bits(max98373->regmap,
MAX98373_R2000_SW_RESET,
MAX98373_SOFT_RESET,
MAX98373_SOFT_RESET);
if (ret)
dev_err(dev, "Reset command failed. (ret:%d)\n", ret);
count = 0;
while (count < 3) {
usleep_range(10000, 11000);
/* Software Reset Verification */
ret = regmap_read(max98373->regmap,
MAX98373_R21FF_REV_ID, &reg);
if (!ret) {
dev_info(dev, "Reset completed (retry:%d)\n", count);
return;
}
count++;
}
dev_err(dev, "Reset failed. (ret:%d)\n", ret);
}
static int max98373_probe(struct snd_soc_component *component)
{
struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
/* Software Reset */
regmap_write(max98373->regmap,
MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
usleep_range(10000, 11000);
max98373_reset(max98373, component->dev);
/* IV default slot configuration */
regmap_write(max98373->regmap,
@ -818,9 +843,7 @@ static int max98373_resume(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
regmap_write(max98373->regmap,
MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET);
usleep_range(10000, 11000);
max98373_reset(max98373, dev);
regcache_cache_only(max98373->regmap, false);
regcache_sync(max98373->regmap);
return 0;

View File

@ -1,12 +1,10 @@
/*
* max9867.c -- max9867 ALSA SoC Audio driver
*
* Copyright 2013-15 Maxim Integrated Products
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// MAX9867 ALSA SoC codec driver
//
// Copyright 2013-2015 Maxim Integrated Products
// Copyright 2018 Ladislav Michl <ladis@linux-mips.org>
//
#include <linux/delay.h>
#include <linux/i2c.h>
@ -23,179 +21,218 @@ static const char *const max9867_spmode[] = {
"Stereo Single", "Mono Single",
"Stereo Single Fast", "Mono Single Fast"
};
static const char *const max9867_sidetone_text[] = {
"None", "Left", "Right", "LeftRight", "LeftRightDiv2",
};
static const char *const max9867_filter_text[] = {"IIR", "FIR"};
static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7,
max9867_filter_text);
static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0,
max9867_spmode);
static SOC_ENUM_SINGLE_DECL(max9867_sidetone, MAX9867_DACGAIN, 6,
max9867_sidetone_text);
static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0);
static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1);
static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1);
static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1);
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv,
0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_master_tlv,
0, 2, TLV_DB_SCALE_ITEM(-8600, 200, 1),
3, 17, TLV_DB_SCALE_ITEM(-7800, 400, 0),
18, 25, TLV_DB_SCALE_ITEM(-2000, 200, 0),
26, 34, TLV_DB_SCALE_ITEM( -500, 100, 0),
35, 40, TLV_DB_SCALE_ITEM( 350, 50, 0),
);
static DECLARE_TLV_DB_SCALE(max9867_mic_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(max9867_line_tlv, -600, 200, 0);
static DECLARE_TLV_DB_SCALE(max9867_adc_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(max9867_dac_tlv, -1500, 100, 0);
static DECLARE_TLV_DB_SCALE(max9867_dacboost_tlv, 0, 600, 0);
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_micboost_tlv,
0, 2, TLV_DB_SCALE_ITEM(-2000, 2000, 1),
3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0),
);
static const struct snd_kcontrol_new max9867_snd_controls[] = {
SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL,
MAX9867_RIGHTVOL, 0, 63, 1),
SOC_DOUBLE_R_TLV("Capture Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN,
0, 15, 1, max9860_capture_tlv),
SOC_DOUBLE_R_TLV("Mic Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN, 0, 31, 1, max9860_mic_tlv),
SOC_DOUBLE_R_TLV("Mic Boost Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN, 5, 3, 0, max98088_micboost_tlv),
SOC_ENUM("Digital Sidetone Src", max9867_sidetone),
SOC_SINGLE("Sidetone Volume", MAX9867_DACGAIN, 0, 31, 1),
SOC_SINGLE("DAC Volume", MAX9867_DACLEVEL, 4, 3, 0),
SOC_SINGLE("DAC Attenuation", MAX9867_DACLEVEL, 0, 15, 1),
SOC_SINGLE_TLV("ADC Left Volume", MAX9867_ADCLEVEL,
4, 15, 1, max9860_adc_left_tlv),
SOC_SINGLE_TLV("ADC Right Volume", MAX9867_ADCLEVEL,
0, 15, 1, max9860_adc_right_tlv),
SOC_DOUBLE_R_TLV("Master Playback Volume", MAX9867_LEFTVOL,
MAX9867_RIGHTVOL, 0, 41, 1, max9867_master_tlv),
SOC_DOUBLE_R_TLV("Line Capture Volume", MAX9867_LEFTLINELVL,
MAX9867_RIGHTLINELVL, 0, 15, 1, max9867_line_tlv),
SOC_DOUBLE_R_TLV("Mic Capture Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN, 0, 20, 1, max9867_mic_tlv),
SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", MAX9867_LEFTMICGAIN,
MAX9867_RIGHTMICGAIN, 5, 4, 0, max9867_micboost_tlv),
SOC_SINGLE("Digital Sidetone Volume", MAX9867_SIDETONE, 0, 31, 1),
SOC_SINGLE_TLV("Digital Playback Volume", MAX9867_DACLEVEL, 0, 15, 1,
max9867_dac_tlv),
SOC_SINGLE_TLV("Digital Boost Playback Volume", MAX9867_DACLEVEL, 4, 3, 0,
max9867_dacboost_tlv),
SOC_DOUBLE_TLV("Digital Capture Volume", MAX9867_ADCLEVEL, 0, 4, 15, 1,
max9867_adc_tlv),
SOC_ENUM("Speaker Mode", max9867_spkmode),
SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0),
SOC_SINGLE("ZCD Switch", MAX9867_MODECONFIG, 5, 1, 0),
SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0),
SOC_ENUM("DSP Filter", max9867_filter),
};
static const char *const max9867_mux[] = {"None", "Mic", "Line", "Mic_Line"};
/* Input mixer */
static const struct snd_kcontrol_new max9867_input_mixer_controls[] = {
SOC_DAPM_DOUBLE("Line Capture Switch", MAX9867_INPUTCONFIG, 7, 5, 1, 0),
SOC_DAPM_DOUBLE("Mic Capture Switch", MAX9867_INPUTCONFIG, 6, 4, 1, 0),
};
static SOC_ENUM_SINGLE_DECL(max9867_mux_enum,
MAX9867_INPUTCONFIG, MAX9867_INPUT_SHIFT,
max9867_mux);
/* Output mixer */
static const struct snd_kcontrol_new max9867_output_mixer_controls[] = {
SOC_DAPM_DOUBLE_R("Line Bypass Switch",
MAX9867_LEFTLINELVL, MAX9867_RIGHTLINELVL, 6, 1, 1),
};
static const struct snd_kcontrol_new max9867_dapm_mux_controls =
SOC_DAPM_ENUM("Route", max9867_mux_enum);
/* Sidetone mixer */
static const struct snd_kcontrol_new max9867_sidetone_mixer_controls[] = {
SOC_DAPM_DOUBLE("Sidetone Switch", MAX9867_SIDETONE, 6, 7, 1, 0),
};
/* Line out switch */
static const struct snd_kcontrol_new max9867_line_out_control =
SOC_DAPM_DOUBLE_R("Switch",
MAX9867_LEFTVOL, MAX9867_RIGHTVOL, 6, 1, 1);
static const struct snd_kcontrol_new max9867_left_dapm_control =
SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 6, 1, 0);
static const struct snd_kcontrol_new max9867_right_dapm_control =
SOC_DAPM_SINGLE("Switch", MAX9867_PWRMAN, 5, 1, 0);
static const struct snd_kcontrol_new max9867_line_dapm_control =
SOC_DAPM_SINGLE("Switch", MAX9867_LEFTLINELVL, 6, 1, 1);
static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("Left DAC", NULL, MAX9867_PWRMAN, 3, 0),
SND_SOC_DAPM_DAC("Right DAC", NULL, MAX9867_PWRMAN, 2, 0),
SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("HPOUT"),
SND_SOC_DAPM_INPUT("MICL"),
SND_SOC_DAPM_INPUT("MICR"),
SND_SOC_DAPM_INPUT("LINL"),
SND_SOC_DAPM_INPUT("LINR"),
SND_SOC_DAPM_AIF_IN("DAI_IN", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
&max9867_dapm_mux_controls),
SND_SOC_DAPM_PGA("Left Line Input", MAX9867_PWRMAN, 6, 0, NULL, 0),
SND_SOC_DAPM_PGA("Right Line Input", MAX9867_PWRMAN, 5, 0, NULL, 0),
SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
max9867_input_mixer_controls,
ARRAY_SIZE(max9867_input_mixer_controls)),
SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", MAX9867_PWRMAN, 1, 0),
SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", MAX9867_PWRMAN, 0, 0),
SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_SWITCH("Left Line", MAX9867_LEFTLINELVL, 6, 1,
&max9867_left_dapm_control),
SND_SOC_DAPM_SWITCH("Right Line", MAX9867_RIGTHLINELVL, 6, 1,
&max9867_right_dapm_control),
SND_SOC_DAPM_SWITCH("Line Mixer", SND_SOC_NOPM, 0, 0,
&max9867_line_dapm_control),
SND_SOC_DAPM_INPUT("LINE_IN"),
SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0,
max9867_sidetone_mixer_controls,
ARRAY_SIZE(max9867_sidetone_mixer_controls)),
SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0,
max9867_output_mixer_controls,
ARRAY_SIZE(max9867_output_mixer_controls)),
SND_SOC_DAPM_DAC("DACL", "HiFi Playback", MAX9867_PWRMAN, 3, 0),
SND_SOC_DAPM_DAC("DACR", "HiFi Playback", MAX9867_PWRMAN, 2, 0),
SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0,
&max9867_line_out_control),
SND_SOC_DAPM_OUTPUT("LOUT"),
SND_SOC_DAPM_OUTPUT("ROUT"),
};
static const struct snd_soc_dapm_route max9867_audio_map[] = {
{"Left DAC", NULL, "DAI_OUT"},
{"Right DAC", NULL, "DAI_OUT"},
{"Output Mixer", NULL, "Left DAC"},
{"Output Mixer", NULL, "Right DAC"},
{"HPOUT", NULL, "Output Mixer"},
{"Left Line Input", NULL, "LINL"},
{"Right Line Input", NULL, "LINR"},
{"Input Mixer", "Mic Capture Switch", "MICL"},
{"Input Mixer", "Mic Capture Switch", "MICR"},
{"Input Mixer", "Line Capture Switch", "Left Line Input"},
{"Input Mixer", "Line Capture Switch", "Right Line Input"},
{"ADCL", NULL, "Input Mixer"},
{"ADCR", NULL, "Input Mixer"},
{"Left ADC", NULL, "DAI_IN"},
{"Right ADC", NULL, "DAI_IN"},
{"Input Mixer", NULL, "Left ADC"},
{"Input Mixer", NULL, "Right ADC"},
{"Input Mux", "Line", "Input Mixer"},
{"Input Mux", "Mic", "Input Mixer"},
{"Input Mux", "Mic_Line", "Input Mixer"},
{"Right Line", "Switch", "Input Mux"},
{"Left Line", "Switch", "Input Mux"},
{"LINE_IN", NULL, "Left Line"},
{"LINE_IN", NULL, "Right Line"},
{"Digital", "Sidetone Switch", "ADCL"},
{"Digital", "Sidetone Switch", "ADCR"},
{"DACL", NULL, "Digital"},
{"DACR", NULL, "Digital"},
{"Output Mixer", "Line Bypass Switch", "Left Line Input"},
{"Output Mixer", "Line Bypass Switch", "Right Line Input"},
{"Output Mixer", NULL, "DACL"},
{"Output Mixer", NULL, "DACR"},
{"Master Playback", "Switch", "Output Mixer"},
{"LOUT", NULL, "Master Playback"},
{"ROUT", NULL, "Master Playback"},
};
enum rates {
pcm_rate_8, pcm_rate_16, pcm_rate_24,
pcm_rate_32, pcm_rate_44,
pcm_rate_48, max_pcm_rate,
static const unsigned int max9867_rates_44k1[] = {
11025, 22050, 44100,
};
static const struct ni_div_rates {
u32 mclk;
u16 ni[max_pcm_rate];
} ni_div[] = {
{11289600, {0x116A, 0x22D4, 0x343F, 0x45A9, 0x6000, 0x687D} },
{12000000, {0x1062, 0x20C5, 0x3127, 0x4189, 0x5A51, 0x624E} },
{12288000, {0x1000, 0x2000, 0x3000, 0x4000, 0x5833, 0x6000} },
{13000000, {0x0F20, 0x1E3F, 0x2D5F, 0x3C7F, 0x535F, 0x5ABE} },
{19200000, {0x0A3D, 0x147B, 0x1EB8, 0x28F6, 0x3873, 0x3D71} },
{24000000, {0x1062, 0x20C5, 0x1893, 0x4189, 0x5A51, 0x624E} },
{26000000, {0x0F20, 0x1E3F, 0x16AF, 0x3C7F, 0x535F, 0x5ABE} },
{27000000, {0x0E90, 0x1D21, 0x15D8, 0x3A41, 0x5048, 0x5762} },
static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = {
.list = max9867_rates_44k1,
.count = ARRAY_SIZE(max9867_rates_44k1),
};
static inline int get_ni_value(int mclk, int rate)
static const unsigned int max9867_rates_48k[] = {
8000, 16000, 32000, 48000,
};
static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = {
.list = max9867_rates_48k,
.count = ARRAY_SIZE(max9867_rates_48k),
};
struct max9867_priv {
struct regmap *regmap;
const struct snd_pcm_hw_constraint_list *constraints;
unsigned int sysclk, pclk;
bool master, dsp_a;
};
static int max9867_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int i, ret = 0;
struct max9867_priv *max9867 =
snd_soc_component_get_drvdata(dai->component);
/* find the closest rate index*/
for (i = 0; i < ARRAY_SIZE(ni_div); i++) {
if (ni_div[i].mclk >= mclk)
break;
}
if (i == ARRAY_SIZE(ni_div))
return -EINVAL;
if (max9867->constraints)
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, max9867->constraints);
switch (rate) {
case 8000:
return ni_div[i].ni[pcm_rate_8];
case 16000:
return ni_div[i].ni[pcm_rate_16];
case 32000:
return ni_div[i].ni[pcm_rate_32];
case 44100:
return ni_div[i].ni[pcm_rate_44];
case 48000:
return ni_div[i].ni[pcm_rate_48];
default:
pr_err("%s wrong rate %d\n", __func__, rate);
ret = -EINVAL;
}
return ret;
return 0;
}
static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
int value;
unsigned long int rate, ratio;
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
unsigned int ni_h, ni_l;
int value;
unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params),
max9867->pclk);
value = get_ni_value(max9867->sysclk, params_rate(params));
if (value < 0)
return value;
ni_h = (0xFF00 & value) >> 8;
ni_l = 0x00FF & value;
/* set up the ni value */
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
MAX9867_NI_HIGH_MASK, ni_h);
MAX9867_NI_HIGH_MASK, (0xFF00 & ni) >> 8);
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
MAX9867_NI_LOW_MASK, ni_l);
if (!max9867->master) {
MAX9867_NI_LOW_MASK, 0x00FF & ni);
if (max9867->master) {
if (max9867->dsp_a) {
value = MAX9867_IFC1B_48X;
} else {
rate = params_rate(params) * 2 * params_width(params);
ratio = max9867->pclk / rate;
switch (params_width(params)) {
case 8:
case 16:
switch (ratio) {
case 2:
value = MAX9867_IFC1B_PCLK_2;
break;
case 4:
value = MAX9867_IFC1B_PCLK_4;
break;
case 8:
value = MAX9867_IFC1B_PCLK_8;
break;
case 16:
value = MAX9867_IFC1B_PCLK_16;
break;
default:
return -EINVAL;
}
break;
case 24:
value = MAX9867_IFC1B_48X;
break;
case 32:
value = MAX9867_IFC1B_64X;
break;
default:
return -EINVAL;
}
}
regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
MAX9867_IFC1B_BCLK_MASK, value);
} else {
/*
* digital pll locks on to any externally supplied LRCLK signal
* and also enable rapid lock mode.
@ -204,73 +241,17 @@ static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
MAX9867_PLL, MAX9867_PLL);
} else {
unsigned long int bclk_rate, pclk_bclk_ratio;
int bclk_value;
bclk_rate = params_rate(params) * 2 * params_width(params);
pclk_bclk_ratio = max9867->pclk/bclk_rate;
switch (params_width(params)) {
case 8:
case 16:
switch (pclk_bclk_ratio) {
case 2:
bclk_value = MAX9867_IFC1B_PCLK_2;
break;
case 4:
bclk_value = MAX9867_IFC1B_PCLK_4;
break;
case 8:
bclk_value = MAX9867_IFC1B_PCLK_8;
break;
case 16:
bclk_value = MAX9867_IFC1B_PCLK_16;
break;
default:
dev_err(component->dev,
"unsupported sampling rate\n");
return -EINVAL;
}
break;
case 24:
bclk_value = MAX9867_IFC1B_24BIT;
break;
case 32:
bclk_value = MAX9867_IFC1B_32BIT;
break;
default:
dev_err(component->dev, "unsupported sampling rate\n");
return -EINVAL;
}
regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
MAX9867_IFC1B_BCLK_MASK, bclk_value);
}
return 0;
}
static int max9867_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
return 0;
}
static int max9867_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_component *component = dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
if (mute)
regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
MAX9867_DAC_MUTE_MASK, MAX9867_DAC_MUTE_MASK);
else
regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
MAX9867_DAC_MUTE_MASK, 0);
return 0;
return regmap_update_bits(max9867->regmap, MAX9867_DACLEVEL,
1 << 6, !!mute << 6);
}
static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@ -283,21 +264,29 @@ static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai,
/* Set the prescaler based on the master clock frequency*/
if (freq >= 10000000 && freq <= 20000000) {
value |= MAX9867_PSCLK_10_20;
max9867->pclk = freq;
max9867->pclk = freq;
} else if (freq >= 20000000 && freq <= 40000000) {
value |= MAX9867_PSCLK_20_40;
max9867->pclk = freq/2;
max9867->pclk = freq / 2;
} else if (freq >= 40000000 && freq <= 60000000) {
value |= MAX9867_PSCLK_40_60;
max9867->pclk = freq/4;
max9867->pclk = freq / 4;
} else {
dev_err(component->dev,
"Invalid clock frequency %uHz (required 10-60MHz)\n",
freq);
return -EINVAL;
}
value = value << MAX9867_PSCLK_SHIFT;
if (freq % 48000 == 0)
max9867->constraints = &max9867_constraints_48k;
else if (freq % 44100 == 0)
max9867->constraints = &max9867_constraints_44k1;
else
dev_warn(component->dev,
"Unable to set exact rate with %uHz clock frequency\n",
freq);
max9867->sysclk = freq;
value = value << MAX9867_PSCLK_SHIFT;
/* exact integer mode is not supported */
value &= ~MAX9867_FREQ_MASK;
regmap_update_bits(max9867->regmap, MAX9867_SYSCLK,
@ -310,16 +299,17 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
{
struct snd_soc_component *component = codec_dai->component;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
u8 iface1A = 0, iface1B = 0;
u8 iface1A, iface1B;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
max9867->master = 1;
iface1A |= MAX9867_MASTER;
max9867->master = true;
iface1A = MAX9867_MASTER;
iface1B = MAX9867_IFC1B_48X;
break;
case SND_SOC_DAIFMT_CBS_CFS:
max9867->master = 0;
iface1A &= ~MAX9867_MASTER;
max9867->master = false;
iface1A = iface1B = 0;
break;
default:
return -EINVAL;
@ -327,9 +317,11 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
max9867->dsp_a = false;
iface1A |= MAX9867_I2S_DLY;
break;
case SND_SOC_DAIFMT_DSP_A:
max9867->dsp_a = true;
iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ;
break;
default:
@ -355,21 +347,18 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
return 0;
}
static const struct snd_soc_dai_ops max9867_dai_ops = {
.set_fmt = max9867_dai_set_fmt,
.set_sysclk = max9867_set_dai_sysclk,
.prepare = max9867_prepare,
.set_fmt = max9867_dai_set_fmt,
.digital_mute = max9867_mute,
.hw_params = max9867_dai_hw_params,
.startup = max9867_startup,
.hw_params = max9867_dai_hw_params,
};
#define MAX9867_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
#define MAX9867_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
static struct snd_soc_dai_driver max9867_dai[] = {
{
.name = "max9867-aif1",
@ -377,42 +366,74 @@ static struct snd_soc_dai_driver max9867_dai[] = {
.stream_name = "HiFi Playback",
.channels_min = 2,
.channels_max = 2,
.rates = MAX9867_RATES,
.formats = MAX9867_FORMATS,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 2,
.channels_max = 2,
.rates = MAX9867_RATES,
.formats = MAX9867_FORMATS,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.ops = &max9867_dai_ops,
.symmetric_rates = 1,
}
};
#ifdef CONFIG_PM_SLEEP
static int max9867_suspend(struct device *dev)
#ifdef CONFIG_PM
static int max9867_suspend(struct snd_soc_component *component)
{
struct max9867_priv *max9867 = dev_get_drvdata(dev);
snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
/* Drop down to power saving mode when system is suspended */
regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN_MASK, ~MAX9867_SHTDOWN_MASK);
return 0;
}
static int max9867_resume(struct device *dev)
static int max9867_resume(struct snd_soc_component *component)
{
struct max9867_priv *max9867 = dev_get_drvdata(dev);
snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN_MASK, MAX9867_SHTDOWN_MASK);
return 0;
}
#else
#define max9867_suspend NULL
#define max9867_resume NULL
#endif
static int max9867_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
int err;
struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component);
switch (level) {
case SND_SOC_BIAS_STANDBY:
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
err = regcache_sync(max9867->regmap);
if (err)
return err;
err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN, MAX9867_SHTDOWN);
if (err)
return err;
}
break;
case SND_SOC_BIAS_OFF:
err = regmap_update_bits(max9867->regmap, MAX9867_PWRMAN,
MAX9867_SHTDOWN, 0);
if (err)
return err;
regcache_mark_dirty(max9867->regmap);
break;
default:
break;
}
return 0;
}
static const struct snd_soc_component_driver max9867_component = {
.controls = max9867_snd_controls,
.num_controls = ARRAY_SIZE(max9867_snd_controls),
@ -420,6 +441,9 @@ static const struct snd_soc_component_driver max9867_component = {
.num_dapm_routes = ARRAY_SIZE(max9867_audio_map),
.dapm_widgets = max9867_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets),
.suspend = max9867_suspend,
.resume = max9867_resume,
.set_bias_level = max9867_set_bias_level,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
@ -450,8 +474,8 @@ static const struct reg_default max9867_reg[] = {
{ 0x0B, 0x00 },
{ 0x0C, 0x00 },
{ 0x0D, 0x00 },
{ 0x0E, 0x00 },
{ 0x0F, 0x00 },
{ 0x0E, 0x40 },
{ 0x0F, 0x40 },
{ 0x10, 0x00 },
{ 0x11, 0x00 },
{ 0x12, 0x00 },
@ -476,10 +500,9 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct max9867_priv *max9867;
int ret = 0, reg;
int ret, reg;
max9867 = devm_kzalloc(&i2c->dev,
sizeof(*max9867), GFP_KERNEL);
max9867 = devm_kzalloc(&i2c->dev, sizeof(*max9867), GFP_KERNEL);
if (!max9867)
return -ENOMEM;
@ -490,8 +513,7 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
return ret;
}
ret = regmap_read(max9867->regmap,
MAX9867_REVISION, &reg);
ret = regmap_read(max9867->regmap, MAX9867_REVISION, &reg);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to read: %d\n", ret);
return ret;
@ -499,10 +521,8 @@ static int max9867_i2c_probe(struct i2c_client *i2c,
dev_info(&i2c->dev, "device revision: %x\n", reg);
ret = devm_snd_soc_register_component(&i2c->dev, &max9867_component,
max9867_dai, ARRAY_SIZE(max9867_dai));
if (ret < 0) {
if (ret < 0)
dev_err(&i2c->dev, "Failed to register component: %d\n", ret);
return ret;
}
return ret;
}
@ -518,15 +538,10 @@ static const struct of_device_id max9867_of_match[] = {
};
MODULE_DEVICE_TABLE(of, max9867_of_match);
static const struct dev_pm_ops max9867_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume)
};
static struct i2c_driver max9867_i2c_driver = {
.driver = {
.name = "max9867",
.of_match_table = of_match_ptr(max9867_of_match),
.pm = &max9867_pm_ops,
},
.probe = max9867_i2c_probe,
.id_table = max9867_i2c_id,
@ -534,6 +549,6 @@ static struct i2c_driver max9867_i2c_driver = {
module_i2c_driver(max9867_i2c_driver);
MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>");
MODULE_DESCRIPTION("ALSA SoC MAX9867 driver");
MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");
MODULE_DESCRIPTION("ASoC MAX9867 driver");
MODULE_LICENSE("GPL");

View File

@ -26,13 +26,11 @@
#define MAX9867_PSCLK_10_20 0x1
#define MAX9867_PSCLK_20_40 0x2
#define MAX9867_PSCLK_40_60 0x3
#define MAX9867_AUDIOCLKHIGH 0x06
#define MAX9867_NI_HIGH_WIDTH 0x7
#define MAX9867_NI_HIGH_MASK 0x7F
#define MAX9867_NI_LOW_MASK 0x7F
#define MAX9867_NI_LOW_SHIFT 0x1
#define MAX9867_PLL (1<<7)
#define MAX9867_AUDIOCLKLOW 0x07
#define MAX9867_AUDIOCLKHIGH 0x06
#define MAX9867_NI_HIGH_MASK 0x7F
#define MAX9867_NI_LOW_MASK 0xFE
#define MAX9867_PLL (1<<7)
#define MAX9867_AUDIOCLKLOW 0x07
#define MAX9867_RAPID_LOCK 0x01
#define MAX9867_IFC1A 0x08
#define MAX9867_MASTER (1<<7)
@ -43,40 +41,29 @@
#define MAX9867_BCI_MODE (1<<5)
#define MAX9867_IFC1B 0x09
#define MAX9867_IFC1B_BCLK_MASK 7
#define MAX9867_IFC1B_32BIT 0x01
#define MAX9867_IFC1B_24BIT 0x02
#define MAX9867_IFC1B_PCLK_2 4
#define MAX9867_IFC1B_PCLK_4 5
#define MAX9867_IFC1B_PCLK_8 6
#define MAX9867_IFC1B_PCLK_16 7
#define MAX9867_IFC1B_64X 0x01
#define MAX9867_IFC1B_48X 0x02
#define MAX9867_IFC1B_PCLK_2 0x04
#define MAX9867_IFC1B_PCLK_4 0x05
#define MAX9867_IFC1B_PCLK_8 0x06
#define MAX9867_IFC1B_PCLK_16 0x07
#define MAX9867_CODECFLTR 0x0a
#define MAX9867_DACGAIN 0x0b
#define MAX9867_SIDETONE 0x0b
#define MAX9867_DACLEVEL 0x0c
#define MAX9867_DAC_MUTE_SHIFT 0x6
#define MAX9867_DAC_MUTE_WIDTH 0x1
#define MAX9867_DAC_MUTE_MASK (0x1<<MAX9867_DAC_MUTE_SHIFT)
#define MAX9867_ADCLEVEL 0x0d
#define MAX9867_LEFTLINELVL 0x0e
#define MAX9867_RIGTHLINELVL 0x0f
#define MAX9867_RIGHTLINELVL 0x0f
#define MAX9867_LEFTVOL 0x10
#define MAX9867_RIGHTVOL 0x11
#define MAX9867_LEFTMICGAIN 0x12
#define MAX9867_RIGHTMICGAIN 0x13
#define MAX9867_INPUTCONFIG 0x14
#define MAX9867_INPUT_SHIFT 0x6
#define MAX9867_MICCONFIG 0x15
#define MAX9867_MODECONFIG 0x16
#define MAX9867_PWRMAN 0x17
#define MAX9867_SHTDOWN_MASK (1<<7)
#define MAX9867_SHTDOWN 0x80
#define MAX9867_REVISION 0xff
#define MAX9867_CACHEREGNUM 10
/* codec private data */
struct max9867_priv {
struct regmap *regmap;
unsigned int sysclk;
unsigned int pclk;
unsigned int master;
};
#endif

View File

@ -585,7 +585,7 @@ static int nau8540_calc_fll_param(unsigned int fll_in,
fvco_max = 0;
fvco_sel = ARRAY_SIZE(mclk_src_scaling);
for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
fvco_max < fvco) {
fvco_max = fvco;

View File

@ -1,18 +1,14 @@
/*
* nau8822.c -- NAU8822 ALSA Soc Audio Codec driver
*
* Copyright 2017 Nuvoton Technology Corp.
*
* Author: David Lin <ctlin0@nuvoton.com>
* Co-author: John Hsu <kchsu0@nuvoton.com>
* Co-author: Seven Li <wtli@nuvoton.com>
*
* Based on WM8974.c
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0
//
// nau8822.c -- NAU8822 ALSA Soc Audio driver
//
// Copyright 2017 Nuvoton Technology Crop.
//
// Author: David Lin <ctlin0@nuvoton.com>
// Co-author: John Hsu <kchsu0@nuvoton.com>
// Co-author: Seven Li <wtli@nuvoton.com>
//
// Based on WM8974.c
#include <linux/module.h>
#include <linux/moduleparam.h>

View File

@ -1,13 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* nau8822.h -- NAU8822 Soc Audio Codec driver
* nau8822.h -- NAU8822 ALSA SoC Audio driver
*
* Copyright 2017 Nuvoton Technology Crop.
*
* Author: David Lin <ctlin0@nuvoton.com>
* Co-author: John Hsu <kchsu0@nuvoton.com>
* Co-author: Seven Li <wtli@nuvoton.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 __NAU8822_H__

View File

@ -424,10 +424,8 @@ static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros)
{
u32 gain, sidetone;
if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) {
WARN_ON(1);
if (WARN_ON(sig_org == 0 || sig_cros == 0))
return 0;
}
sig_org = nau8825_intlog10_dec3(sig_org);
sig_cros = nau8825_intlog10_dec3(sig_cros);

View File

@ -198,19 +198,25 @@ static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
};
static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "Playback", PCM3060_REG64,
PCM3060_REG_SHIFT_DAPSV, 1),
SND_SOC_DAPM_OUTPUT("OUTL"),
SND_SOC_DAPM_OUTPUT("OUTR"),
SND_SOC_DAPM_INPUT("INL"),
SND_SOC_DAPM_INPUT("INR"),
SND_SOC_DAPM_ADC("ADC", "Capture", PCM3060_REG64,
PCM3060_REG_SHIFT_ADPSV, 1),
};
static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
{ "OUTL", NULL, "Playback" },
{ "OUTR", NULL, "Playback" },
{ "OUTL", NULL, "DAC" },
{ "OUTR", NULL, "DAC" },
{ "Capture", NULL, "INL" },
{ "Capture", NULL, "INR" },
{ "ADC", NULL, "INL" },
{ "ADC", NULL, "INR" },
};
/* soc component */
@ -270,9 +276,23 @@ EXPORT_SYMBOL(pcm3060_regmap);
/* device */
static void pcm3060_parse_dt(const struct device_node *np,
struct pcm3060_priv *priv)
{
priv->out_se = of_property_read_bool(np, "ti,out-single-ended");
}
int pcm3060_probe(struct device *dev)
{
int rc;
struct pcm3060_priv *priv = dev_get_drvdata(dev);
if (dev->of_node)
pcm3060_parse_dt(dev->of_node, priv);
if (priv->out_se)
regmap_update_bits(priv->regmap, PCM3060_REG64,
PCM3060_REG_SE, PCM3060_REG_SE);
rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
pcm3060_dai,

View File

@ -25,6 +25,7 @@ struct pcm3060_priv_dai {
struct pcm3060_priv {
struct regmap *regmap;
struct pcm3060_priv_dai dai[PCM3060_DAI_IDS_NUM];
u8 out_se: 1;
};
int pcm3060_probe(struct device *dev);
@ -36,7 +37,9 @@ int pcm3060_remove(struct device *dev);
#define PCM3060_REG_MRST 0x80
#define PCM3060_REG_SRST 0x40
#define PCM3060_REG_ADPSV 0x20
#define PCM3060_REG_SHIFT_ADPSV 0x05
#define PCM3060_REG_DAPSV 0x10
#define PCM3060_REG_SHIFT_DAPSV 0x04
#define PCM3060_REG_SE 0x01
#define PCM3060_REG65 0x41

View File

@ -133,10 +133,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0),
SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0),
SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0),
SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0),
SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
@ -176,9 +172,6 @@ static const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0),
SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0),
SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0),
SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
@ -504,6 +497,10 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
unsigned int fmt;
unsigned int sample_min;
unsigned int channel_max;
unsigned int channel_maxs[] = {
6, /* rx */
8 /* tx */
};
if (tx)
fmt = pcm3168a->dac_fmt;
@ -528,18 +525,9 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
channel_max = 2;
break;
case PCM3168A_FMT_LEFT_J:
sample_min = 24;
if (tx)
channel_max = 8;
else
channel_max = 6;
break;
case PCM3168A_FMT_I2S:
sample_min = 24;
if (tx)
channel_max = 8;
else
channel_max = 6;
channel_max = channel_maxs[tx];
break;
default:
sample_min = 24;

View File

@ -53,6 +53,8 @@ struct pcm512x_priv {
unsigned long overclock_pll;
unsigned long overclock_dac;
unsigned long overclock_dsp;
int mute;
struct mutex mutex;
};
/*
@ -384,6 +386,61 @@ static const struct soc_enum pcm512x_veds =
SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
pcm512x_ramp_step_text);
static int pcm512x_update_mute(struct pcm512x_priv *pcm512x)
{
return regmap_update_bits(
pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR,
(!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT)
| (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT));
}
static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
mutex_lock(&pcm512x->mutex);
ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
mutex_unlock(&pcm512x->mutex);
return 0;
}
static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
int ret, changed = 0;
mutex_lock(&pcm512x->mutex);
if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
pcm512x->mute ^= 0x4;
changed = 1;
}
if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) {
pcm512x->mute ^= 0x2;
changed = 1;
}
if (changed) {
ret = pcm512x_update_mute(pcm512x);
if (ret != 0) {
dev_err(component->dev,
"Failed to update digital mute: %d\n", ret);
mutex_unlock(&pcm512x->mutex);
return ret;
}
}
mutex_unlock(&pcm512x->mutex);
return changed;
}
static const struct snd_kcontrol_new pcm512x_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
@ -391,8 +448,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
PCM512x_RQMR_SHIFT, 1, 1),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Digital Playback Switch",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = snd_ctl_boolean_stereo_info,
.get = pcm512x_digital_playback_switch_get,
.put = pcm512x_digital_playback_switch_put
},
SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
SOC_ENUM("DSP Program", pcm512x_dsp_program),
@ -1319,10 +1383,61 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_component *component = dai->component;
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
int ret;
unsigned int mute_det;
mutex_lock(&pcm512x->mutex);
if (mute) {
pcm512x->mute |= 0x1;
ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE,
PCM512x_RQML | PCM512x_RQMR,
PCM512x_RQML | PCM512x_RQMR);
if (ret != 0) {
dev_err(component->dev,
"Failed to set digital mute: %d\n", ret);
mutex_unlock(&pcm512x->mutex);
return ret;
}
regmap_read_poll_timeout(pcm512x->regmap,
PCM512x_ANALOG_MUTE_DET,
mute_det, (mute_det & 0x3) == 0,
200, 10000);
mutex_unlock(&pcm512x->mutex);
} else {
pcm512x->mute &= ~0x1;
ret = pcm512x_update_mute(pcm512x);
if (ret != 0) {
dev_err(component->dev,
"Failed to update digital mute: %d\n", ret);
mutex_unlock(&pcm512x->mutex);
return ret;
}
regmap_read_poll_timeout(pcm512x->regmap,
PCM512x_ANALOG_MUTE_DET,
mute_det,
(mute_det & 0x3)
== ((~pcm512x->mute >> 1) & 0x3),
200, 10000);
}
mutex_unlock(&pcm512x->mutex);
return 0;
}
static const struct snd_soc_dai_ops pcm512x_dai_ops = {
.startup = pcm512x_dai_startup,
.hw_params = pcm512x_hw_params,
.set_fmt = pcm512x_set_fmt,
.digital_mute = pcm512x_digital_mute,
};
static struct snd_soc_dai_driver pcm512x_dai = {
@ -1388,6 +1503,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
if (!pcm512x)
return -ENOMEM;
mutex_init(&pcm512x->mutex);
dev_set_drvdata(dev, pcm512x);
pcm512x->regmap = regmap;

View File

@ -112,7 +112,9 @@
#define PCM512x_RQST_SHIFT 4
/* Page 0, Register 3 - mute */
#define PCM512x_RQMR (1 << 0)
#define PCM512x_RQMR_SHIFT 0
#define PCM512x_RQML (1 << 4)
#define PCM512x_RQML_SHIFT 4
/* Page 0, Register 4 - PLL */

View File

@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/pcm.h>
@ -33,6 +34,9 @@
#define RT5663_DEVICE_ID_2 0x6451
#define RT5663_DEVICE_ID_1 0x6406
#define RT5663_POWER_ON_DELAY_MS 300
#define RT5663_SUPPLY_CURRENT_UA 500000
enum {
CODEC_VER_1,
CODEC_VER_0,
@ -48,6 +52,11 @@ struct impedance_mapping_table {
unsigned int dc_offset_r_manual_mic;
};
static const char *const rt5663_supply_names[] = {
"avdd",
"cpvdd",
};
struct rt5663_priv {
struct snd_soc_component *component;
struct rt5663_platform_data pdata;
@ -56,6 +65,7 @@ struct rt5663_priv {
struct snd_soc_jack *hs_jack;
struct timer_list btn_check_timer;
struct impedance_mapping_table *imp_table;
struct regulator_bulk_data supplies[ARRAY_SIZE(rt5663_supply_names)];
int codec_ver;
int sysclk;
@ -3483,7 +3493,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
{
struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5663_priv *rt5663;
int ret;
int ret, i;
unsigned int val;
struct regmap *regmap;
@ -3500,12 +3510,44 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
else
rt5663_parse_dp(rt5663, &i2c->dev);
for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++)
rt5663->supplies[i].supply = rt5663_supply_names[i];
ret = devm_regulator_bulk_get(&i2c->dev,
ARRAY_SIZE(rt5663->supplies),
rt5663->supplies);
if (ret) {
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
/* Set load for regulator. */
for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) {
ret = regulator_set_load(rt5663->supplies[i].consumer,
RT5663_SUPPLY_CURRENT_UA);
if (ret < 0) {
dev_err(&i2c->dev,
"Failed to set regulator load on %s, ret: %d\n",
rt5663->supplies[i].supply, ret);
return ret;
}
}
ret = regulator_bulk_enable(ARRAY_SIZE(rt5663->supplies),
rt5663->supplies);
if (ret) {
dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
return ret;
}
msleep(RT5663_POWER_ON_DELAY_MS);
regmap = devm_regmap_init_i2c(i2c, &temp_regmap);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n",
ret);
return ret;
goto err_enable;
}
ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val);
@ -3530,14 +3572,15 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev,
"Device with ID register %#x is not rt5663\n",
val);
return -ENODEV;
ret = -ENODEV;
goto err_enable;
}
if (IS_ERR(rt5663->regmap)) {
ret = PTR_ERR(rt5663->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
goto err_enable;
}
/* reset and calibrate */
@ -3635,20 +3678,32 @@ static int rt5663_i2c_probe(struct i2c_client *i2c,
ret = request_irq(i2c->irq, rt5663_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5663", rt5663);
if (ret)
if (ret) {
dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n",
__func__, ret);
goto err_enable;
}
}
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_rt5663,
rt5663_dai, ARRAY_SIZE(rt5663_dai));
if (ret) {
if (i2c->irq)
free_irq(i2c->irq, rt5663);
}
if (ret)
goto err_enable;
return 0;
/*
* Error after enabling regulators should goto err_enable
* to disable regulators.
*/
err_enable:
if (i2c->irq)
free_irq(i2c->irq, rt5663);
regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
return ret;
}
@ -3659,6 +3714,8 @@ static int rt5663_i2c_remove(struct i2c_client *i2c)
if (i2c->irq)
free_irq(i2c->irq, rt5663);
regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies);
return 0;
}

View File

@ -19,6 +19,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <sound/soc.h>
#define DRV_NAME "simple-amplifier"
@ -58,11 +59,14 @@ static const struct snd_soc_dapm_widget simple_amp_dapm_widgets[] = {
(SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)),
SND_SOC_DAPM_OUTPUT("OUTL"),
SND_SOC_DAPM_OUTPUT("OUTR"),
SND_SOC_DAPM_REGULATOR_SUPPLY("VCC", 20, 0),
};
static const struct snd_soc_dapm_route simple_amp_dapm_routes[] = {
{ "DRV", NULL, "INL" },
{ "DRV", NULL, "INR" },
{ "OUTL", NULL, "VCC" },
{ "OUTR", NULL, "VCC" },
{ "OUTL", NULL, "DRV" },
{ "OUTR", NULL, "DRV" },
};

View File

@ -378,7 +378,7 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
.non_legacy_dai_naming = 1,
};
static struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
.hw_params = tas6424_hw_params,
.set_fmt = tas6424_set_dai_fmt,
.set_tdm_slot = tas6424_set_dai_tdm_slot,

View File

@ -1095,7 +1095,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
if (freq/i > 20000000) {
dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
__func__, freq);
return -EINVAL;
return -EINVAL;
}
aic31xx->p_div = i;

View File

@ -1260,6 +1260,16 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
aic3x->master = 0;
iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
break;
case SND_SOC_DAIFMT_CBM_CFS:
aic3x->master = 1;
iface_areg |= BIT_CLK_MASTER;
iface_areg &= ~WORD_CLK_MASTER;
break;
case SND_SOC_DAIFMT_CBS_CFM:
aic3x->master = 1;
iface_areg |= WORD_CLK_MASTER;
iface_areg &= ~BIT_CLK_MASTER;
break;
default:
return -EINVAL;
}

View File

@ -394,7 +394,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret != 0) {
dev_err(component->dev,
"Failed to enable supplies: %d\n", ret);
goto exit;
goto exit;
}
if (dac33->power_gpio >= 0)

View File

@ -60,7 +60,7 @@ static int wm8998_asrc_ev(struct snd_soc_dapm_widget *w,
dev_warn(component->dev,
"Unsupported ASRC rate1 (%s)\n",
arizona_sample_rate_val_to_name(val));
return -EINVAL;
return -EINVAL;
}
break;
default:

View File

@ -325,8 +325,7 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
if (wm9705->mfd_pdata) {
wm9705->ac97 = wm9705->mfd_pdata->ac97;
regmap = wm9705->mfd_pdata->regmap;
} else {
#ifdef CONFIG_SND_SOC_AC97_BUS
} else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID,
WM9705_VENDOR_ID_MASK);
if (IS_ERR(wm9705->ac97)) {
@ -339,7 +338,8 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9705->ac97);
return PTR_ERR(regmap);
}
#endif
} else {
return -ENXIO;
}
snd_soc_component_set_drvdata(component, wm9705->ac97);
@ -350,14 +350,12 @@ static int wm9705_soc_probe(struct snd_soc_component *component)
static void wm9705_soc_remove(struct snd_soc_component *component)
{
#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component);
if (!wm9705->mfd_pdata) {
if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9705->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9705->ac97);
}
#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9705 = {

View File

@ -642,8 +642,7 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
if (wm9712->mfd_pdata) {
wm9712->ac97 = wm9712->mfd_pdata->ac97;
regmap = wm9712->mfd_pdata->regmap;
} else {
#ifdef CONFIG_SND_SOC_AC97_BUS
} else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
int ret;
wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID,
@ -660,7 +659,8 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9712->ac97);
return PTR_ERR(regmap);
}
#endif
} else {
return -ENXIO;
}
snd_soc_component_init_regmap(component, regmap);
@ -673,14 +673,12 @@ static int wm9712_soc_probe(struct snd_soc_component *component)
static void wm9712_soc_remove(struct snd_soc_component *component)
{
#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component);
if (!wm9712->mfd_pdata) {
if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9712->ac97);
}
#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9712 = {

View File

@ -1214,8 +1214,7 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
if (wm9713->mfd_pdata) {
wm9713->ac97 = wm9713->mfd_pdata->ac97;
regmap = wm9713->mfd_pdata->regmap;
} else {
#ifdef CONFIG_SND_SOC_AC97_BUS
} else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) {
wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID,
WM9713_VENDOR_ID_MASK);
if (IS_ERR(wm9713->ac97))
@ -1225,7 +1224,8 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
snd_soc_free_ac97_component(wm9713->ac97);
return PTR_ERR(regmap);
}
#endif
} else {
return -ENXIO;
}
snd_soc_component_init_regmap(component, regmap);
@ -1238,14 +1238,12 @@ static int wm9713_soc_probe(struct snd_soc_component *component)
static void wm9713_soc_remove(struct snd_soc_component *component)
{
#ifdef CONFIG_SND_SOC_AC97_BUS
struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component);
if (!wm9713->mfd_pdata) {
if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9713->mfd_pdata) {
snd_soc_component_exit_regmap(component);
snd_soc_free_ac97_component(wm9713->ac97);
}
#endif
}
static const struct snd_soc_component_driver soc_component_dev_wm9713 = {

View File

@ -2419,7 +2419,7 @@ static int wm_adsp_create_name(struct wm_adsp *dsp)
return 0;
}
int wm_adsp1_init(struct wm_adsp *dsp)
static int wm_adsp_common_init(struct wm_adsp *dsp)
{
int ret;
@ -2428,11 +2428,17 @@ int wm_adsp1_init(struct wm_adsp *dsp)
return ret;
INIT_LIST_HEAD(&dsp->alg_regions);
INIT_LIST_HEAD(&dsp->ctl_list);
mutex_init(&dsp->pwr_lock);
return 0;
}
int wm_adsp1_init(struct wm_adsp *dsp)
{
return wm_adsp_common_init(dsp);
}
EXPORT_SYMBOL_GPL(wm_adsp1_init);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
@ -2917,7 +2923,7 @@ int wm_adsp2_init(struct wm_adsp *dsp)
{
int ret;
ret = wm_adsp_create_name(dsp);
ret = wm_adsp_common_init(dsp);
if (ret)
return ret;
@ -2939,12 +2945,8 @@ int wm_adsp2_init(struct wm_adsp *dsp)
break;
}
INIT_LIST_HEAD(&dsp->alg_regions);
INIT_LIST_HEAD(&dsp->ctl_list);
INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
mutex_init(&dsp->pwr_lock);
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_init);

View File

@ -1,106 +0,0 @@
config SND_DAVINCI_SOC
tristate
depends on ARCH_DAVINCI
select SND_EDMA_SOC
config SND_EDMA_SOC
tristate "SoC Audio for Texas Instruments chips using eDMA"
depends on TI_EDMA
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M here if you want audio support for TI SoC which uses eDMA.
The following line of SoCs are supported by this platform driver:
- daVinci devices
- AM335x
- AM437x/AM438x
- DRA7xx family
config SND_DAVINCI_SOC_I2S
tristate "DaVinci Multichannel Buffered Serial Port (McBSP) support"
depends on SND_EDMA_SOC
help
Say Y or M here if you want to have support for McBSP IP found in
Texas Instruments DaVinci DA850 SoCs.
config SND_DAVINCI_SOC_MCASP
tristate "Multichannel Audio Serial Port (McASP) support"
depends on SND_SDMA_SOC || SND_EDMA_SOC
help
Say Y or M here if you want to have support for McASP IP found in
various Texas Instruments SoCs like:
- daVinci devices
- Sitara line of SoCs (AM335x, AM438x, etc)
- DRA7x devices
config SND_DAVINCI_SOC_VCIF
tristate
config SND_DAVINCI_SOC_GENERIC_EVM
tristate
select SND_SOC_TLV320AIC3X
select SND_DAVINCI_SOC_MCASP
config SND_AM33XX_SOC_EVM
tristate "SoC Audio for the AM33XX chip based boards"
depends on SND_EDMA_SOC && SOC_AM33XX && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y or M if you want to add support for SoC audio on AM33XX
boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
AM335X-EVMSK, and BeagelBone with AudioCape boards have this
setup.
config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
depends on SND_EDMA_SOC && I2C
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
DaVinci DM6446, DM355 or DM365 EVM platforms.
choice
prompt "DM365 codec select"
depends on SND_DAVINCI_SOC_EVM
depends on MACH_DAVINCI_DM365_EVM
config SND_DM365_AIC3X_CODEC
tristate "Audio Codec - AIC3101"
help
Say Y if you want to add support for AIC3101 audio codec
config SND_DM365_VOICE_CODEC
tristate "Voice Codec - CQ93VC"
select MFD_DAVINCI_VOICECODEC
select SND_DAVINCI_SOC_VCIF
select SND_SOC_CQ0093VC
help
Say Y if you want to add support for SoC On-chip voice codec
endchoice
config SND_DM6467_SOC_EVM
tristate "SoC Audio support for DaVinci DM6467 EVM"
depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
select SND_SOC_SPDIF
help
Say Y if you want to add support for SoC audio on TI
config SND_DA830_SOC_EVM
tristate "SoC Audio support for DA830/OMAP-L137 EVM"
depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
DA830/OMAP-L137 EVM
config SND_DA850_SOC_EVM
tristate "SoC Audio support for DA850/OMAP-L138 EVM"
depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C
select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
DA850/OMAP-L138 EVM

View File

@ -1,16 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
# DAVINCI Platform Support
snd-soc-edma-objs := edma-pcm.o
snd-soc-davinci-i2s-objs := davinci-i2s.o
snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
snd-soc-davinci-vcif-objs:= davinci-vcif.o
obj-$(CONFIG_SND_EDMA_SOC) += snd-soc-edma.o
obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
# Generic DAVINCI/AM33xx Machine Support
snd-soc-evm-objs := davinci-evm.o
obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o

View File

@ -221,7 +221,7 @@ config SND_SOC_PHYCORE_AC97
config SND_SOC_EUKREA_TLV320
tristate "Eukrea TLV320"
depends on ARCH_MXC && I2C
depends on ARCH_MXC && !ARM64 && I2C
select SND_SOC_TLV320AIC23_I2C
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_SSI

View File

@ -571,17 +571,17 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
}
/* Common settings for corresponding Freescale CPU DAI driver */
if (strstr(cpu_np->name, "ssi")) {
if (of_node_name_eq(cpu_np, "ssi")) {
/* Only SSI needs to configure AUDMUX */
ret = fsl_asoc_card_audmux_init(np, priv);
if (ret) {
dev_err(&pdev->dev, "failed to init audmux\n");
goto asrc_fail;
}
} else if (strstr(cpu_np->name, "esai")) {
} else if (of_node_name_eq(cpu_np, "esai")) {
priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
} else if (strstr(cpu_np->name, "sai")) {
} else if (of_node_name_eq(cpu_np, "sai")) {
priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
}

View File

@ -124,17 +124,7 @@ static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
return 0;
}
static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, fsl_ssi_stats_show, inode->i_private);
}
static const struct file_operations fsl_ssi_stats_ops = {
.open = fsl_ssi_stats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(fsl_ssi_stats);
int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
{
@ -144,7 +134,7 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev)
ssi_dbg->dbg_stats = debugfs_create_file("stats", 0444,
ssi_dbg->dbg_dir, ssi_dbg,
&fsl_ssi_stats_ops);
&fsl_ssi_stats_fops);
if (!ssi_dbg->dbg_stats) {
debugfs_remove(ssi_dbg->dbg_dir);
return -ENOMEM;

View File

@ -6,6 +6,7 @@ config SND_SIMPLE_CARD
select SND_SIMPLE_CARD_UTILS
help
This option enables generic simple sound card support
It also support DPCM of multi CPU single Codec ststem.
config SND_SIMPLE_SCU_CARD
tristate "ASoC Simple SCU sound card support"
@ -20,8 +21,9 @@ config SND_AUDIO_GRAPH_CARD
depends on OF
select SND_SIMPLE_CARD_UTILS
help
This option enables generic simple simple sound card support
This option enables generic simple sound card support
with OF-graph DT bindings.
It also support DPCM of multi CPU single Codec ststem.
config SND_AUDIO_GRAPH_SCU_CARD
tristate "ASoC Audio Graph SCU sound card support"

View File

@ -23,19 +23,29 @@
struct graph_card_data {
struct snd_soc_card snd_card;
struct graph_dai_props {
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platform;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
unsigned int mclk_fs;
} *dai_props;
unsigned int mclk_fs;
struct asoc_simple_jack hp_jack;
struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct snd_soc_codec_conf *codec_conf;
struct gpio_desc *pa_gpio;
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
#define PREFIX "audio-graph-card,"
static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@ -63,11 +73,6 @@ static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@ -75,13 +80,13 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret;
ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
@ -92,9 +97,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
asoc_simple_card_clk_disable(&dai_props->codec_dai);
asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
@ -108,9 +113,7 @@ static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream,
unsigned int mclk, mclk_fs = 0;
int ret = 0;
if (priv->mclk_fs)
mclk_fs = priv->mclk_fs;
else if (dai_props->mclk_fs)
if (dai_props->mclk_fs)
mclk_fs = dai_props->mclk_fs;
if (mclk_fs) {
@ -139,86 +142,238 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = rtd->cpu_dai;
struct graph_dai_props *dai_props =
graph_priv_to_props(priv, rtd->num);
int ret;
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret = 0;
ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
ret = asoc_simple_card_init_dai(rtd->codec_dai,
dai_props->codec_dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
ret = asoc_simple_card_init_dai(rtd->cpu_dai,
dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
struct graph_card_data *priv,
int idx)
static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
asoc_simple_card_convert_fixup(&dai_props->adata, params);
return 0;
}
static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct graph_card_data *priv,
int *dai_idx, int link_idx,
int *conf_idx, int is_cpu)
{
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL);
struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
struct device_node *ep = is_cpu ? cpu_ep : codec_ep;
struct device_node *port = of_get_parent(ep);
struct device_node *ports = of_get_parent(port);
struct device_node *node = of_graph_get_port_parent(ep);
struct asoc_simple_dai *dai;
struct snd_soc_dai_link_component *codecs = dai_link->codecs;
int ret;
if (rcpu_ep != cpu_ep) {
dev_err(dev, "remote-endpoint mismatch (%s/%s/%s)\n",
cpu_ep->name, codec_ep->name, rcpu_ep->name);
ret = -EINVAL;
goto dai_link_of_err;
dev_dbg(dev, "link_of DPCM (for %s)\n", is_cpu ? "CPU" : "Codec");
of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs);
asoc_simple_card_parse_convert(dev, top, NULL, &dai_props->adata);
asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata);
asoc_simple_card_parse_convert(dev, ports, NULL, &dai_props->adata);
asoc_simple_card_parse_convert(dev, port, NULL, &dai_props->adata);
asoc_simple_card_parse_convert(dev, ep, NULL, &dai_props->adata);
of_node_put(ports);
of_node_put(port);
if (is_cpu) {
/* BE is dummy */
codecs->of_node = NULL;
codecs->dai_name = "snd-soc-dummy-dai";
codecs->name = "snd-soc-dummy";
/* FE settings */
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
if (ret)
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"fe.%s",
dai_link->cpu_dai_name);
if (ret < 0)
return ret;
/* card->num_links includes Codec */
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
} else {
struct snd_soc_codec_conf *cconf;
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
dai_link->cpu_name = "snd-soc-dummy";
/* BE settings */
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup;
dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
cconf =
dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"be.%s",
codecs->dai_name);
if (ret < 0)
return ret;
/* check "prefix" from top node */
snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
"prefix");
snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
PREFIX "prefix");
snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node,
"prefix");
snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node,
"prefix");
}
ret = asoc_simple_card_of_parse_tdm(ep, dai);
if (ret)
return ret;
ret = asoc_simple_card_canonicalize_dailink(dai_link);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &dai_link->dai_fmt);
if (ret < 0)
goto dai_link_of_err;
return ret;
of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_graph_card_ops;
dai_link->init = asoc_graph_card_dai_init;
return 0;
}
static int asoc_graph_card_dai_link_of(struct device_node *top,
struct device_node *cpu_ep,
struct device_node *codec_ep,
struct graph_card_data *priv,
int *dai_idx, int link_idx)
{
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
struct device_node *cpu_port = of_get_parent(cpu_ep);
struct device_node *codec_port = of_get_parent(codec_ep);
struct device_node *cpu_ports = of_get_parent(cpu_port);
struct device_node *codec_ports = of_get_parent(codec_port);
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
int ret;
dev_dbg(dev, "link_of\n");
cpu_dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
codec_dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
/* Factor to mclk, used in hw_params() */
of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(cpu_ports, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(codec_ports, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(cpu_port, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(codec_port, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
of_node_put(cpu_port);
of_node_put(cpu_ports);
of_node_put(codec_port);
of_node_put(codec_ports);
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &dai_link->dai_fmt);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_canonicalize_dailink(dai_link);
if (ret < 0)
goto dai_link_of_err;
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"%s-%s",
dai_link->cpu_dai_name,
dai_link->codecs->dai_name);
if (ret < 0)
goto dai_link_of_err;
return ret;
dai_link->ops = &asoc_graph_card_ops;
dai_link->init = asoc_graph_card_dai_init;
@ -226,12 +381,7 @@ static int asoc_graph_card_dai_link_of(struct device_node *cpu_port,
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
dai_link_of_err:
of_node_put(cpu_ep);
of_node_put(rcpu_ep);
of_node_put(codec_ep);
return ret;
return 0;
}
static int asoc_graph_card_parse_of(struct graph_card_data *priv)
@ -239,44 +389,173 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
struct of_phandle_iterator it;
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_card *card = graph_priv_to_card(priv);
struct device_node *node = dev->of_node;
int rc, idx = 0;
int ret;
struct device_node *top = dev->of_node;
struct device_node *node = top;
struct device_node *cpu_port;
struct device_node *cpu_ep = NULL;
struct device_node *codec_ep = NULL;
struct device_node *codec_port = NULL;
struct device_node *codec_port_old = NULL;
int rc, ret;
int link_idx, dai_idx, conf_idx;
int cpu;
ret = asoc_simple_card_of_parse_widgets(card, NULL);
if (ret < 0)
return ret;
ret = asoc_simple_card_of_parse_routing(card, NULL, 1);
ret = asoc_simple_card_of_parse_routing(card, NULL);
if (ret < 0)
return ret;
/* Factor to mclk, used in hw_params() */
of_property_read_u32(node, "mclk-fs", &priv->mclk_fs);
link_idx = 0;
dai_idx = 0;
conf_idx = 0;
codec_port_old = NULL;
for (cpu = 1; cpu >= 0; cpu--) {
/*
* Detect all CPU first, and Detect all Codec 2nd.
*
* In Normal sound case, all DAIs are detected
* as "CPU-Codec".
*
* In DPCM sound case,
* all CPUs are detected as "CPU-dummy", and
* all Codecs are detected as "dummy-Codec".
* To avoid random sub-device numbering,
* detect "dummy-Codec" in last;
*/
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = NULL;
while (1) {
cpu_ep = of_get_next_child(cpu_port, cpu_ep);
if (!cpu_ep)
break;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
ret = asoc_graph_card_dai_link_of(it.node, priv, idx++);
if (ret < 0) {
of_node_put(it.node);
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
codec_port = of_get_parent(codec_ep);
return ret;
of_node_put(codec_ep);
of_node_put(codec_port);
dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep);
if (of_get_child_count(codec_port) > 1) {
/*
* for DPCM sound
*/
if (!cpu) {
if (codec_port_old == codec_port)
continue;
codec_port_old = codec_port;
}
ret = asoc_graph_card_dai_link_of_dpcm(
top, cpu_ep, codec_ep, priv,
&dai_idx, link_idx++,
&conf_idx, cpu);
} else if (cpu) {
/*
* for Normal sound
*/
ret = asoc_graph_card_dai_link_of(
top, cpu_ep, codec_ep, priv,
&dai_idx, link_idx++);
}
if (ret < 0)
return ret;
}
}
}
return asoc_simple_card_parse_card_name(card, NULL);
}
static int asoc_graph_get_dais_count(struct device *dev)
static void asoc_graph_get_dais_count(struct device *dev,
int *link_num,
int *dais_num,
int *ccnf_num)
{
struct of_phandle_iterator it;
struct device_node *node = dev->of_node;
int count = 0;
struct device_node *cpu_port;
struct device_node *cpu_ep;
struct device_node *codec_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
struct device_node *codec_port_old2;
int rc;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0)
count++;
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for "dummy-Codec"
*
* ex1)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 7
* CPU2 -/ ccnf : 1
* CPU3 --- Codec2
*
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
* => 7 DAIs = 4xCPU + 3xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex2)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 6
* CPU2 -/ ccnf : 1
* CPU3 -/
*
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex3)
* CPU0 --- Codec0 link : 6
* CPU1 -/ dais : 6
* CPU2 --- Codec1 ccnf : 2
* CPU3 -/
*
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 2 ccnf = 2xdummy-Codec
*/
codec_port_old = NULL;
codec_port_old2 = NULL;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = NULL;
while (1) {
cpu_ep = of_get_next_child(cpu_port, cpu_ep);
if (!cpu_ep)
break;
return count;
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
codec_port = of_get_parent(codec_ep);
of_node_put(codec_ep);
of_node_put(codec_port);
(*link_num)++;
(*dais_num)++;
if (codec_port_old == codec_port) {
if (codec_port_old2 != codec_port_old) {
(*link_num)++;
(*ccnf_num)++;
}
codec_port_old2 = codec_port_old;
continue;
}
(*dais_num)++;
codec_port_old = codec_port;
}
}
}
static int asoc_graph_soc_card_probe(struct snd_soc_card *card)
@ -300,22 +579,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
struct graph_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
int num, ret, i;
struct snd_soc_codec_conf *cconf;
int lnum = 0, dnum = 0, cnum = 0;
int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
num = asoc_graph_get_dais_count(dev);
if (num == 0)
asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
if (!lnum || !dnum)
return -EINVAL;
dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
if (!dai_props || !dai_link)
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@ -324,7 +608,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
for (i = 0; i < num; i++) {
for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@ -339,16 +623,20 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
priv->dais = dais;
priv->codec_conf = cconf;
/* Init snd_soc_card */
card = graph_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = dai_link;
card->num_links = num;
card->dapm_widgets = asoc_graph_card_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
card->probe = asoc_graph_soc_card_probe;
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = dai_link;
card->num_links = lnum;
card->dapm_widgets = asoc_graph_card_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
card->probe = asoc_graph_soc_card_probe;
card->codec_conf = cconf;
card->num_configs = cnum;
ret = asoc_graph_card_parse_of(priv);
if (ret < 0) {
@ -379,6 +667,7 @@ static int asoc_graph_card_remove(struct platform_device *pdev)
static const struct of_device_id asoc_graph_of_match[] = {
{ .compatible = "audio-graph-card", },
{ .compatible = "audio-graph-scu-card", },
{},
};
MODULE_DEVICE_TABLE(of, asoc_graph_of_match);

View File

@ -24,14 +24,18 @@
struct graph_card_data {
struct snd_soc_card snd_card;
struct snd_soc_codec_conf codec_conf;
struct graph_dai_props {
struct asoc_simple_dai dai;
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs;
struct snd_soc_dai_link_component platform;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
} *dai_props;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
};
#define graph_priv_to_card(priv) (&(priv)->snd_card)
@ -39,13 +43,24 @@ struct graph_card_data {
#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
#define PREFIX "audio-graph-card,"
static int asoc_graph_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret = 0;
return asoc_simple_card_clk_enable(&dai_props->dai);
ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
@ -54,7 +69,9 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream)
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
asoc_simple_card_clk_disable(&dai_props->dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static const struct snd_soc_ops asoc_graph_card_ops = {
@ -65,39 +82,49 @@ static const struct snd_soc_ops asoc_graph_card_ops = {
static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
int num = rtd->num;
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
int ret = 0;
dai_link = graph_priv_to_link(priv, num);
dai_props = graph_priv_to_props(priv, num);
dai = dai_link->dynamic ?
rtd->cpu_dai :
rtd->codec_dai;
ret = asoc_simple_card_init_dai(rtd->codec_dai,
dai_props->codec_dai);
if (ret < 0)
return ret;
return asoc_simple_card_init_dai(dai, &dai_props->dai);
ret = asoc_simple_card_init_dai(rtd->cpu_dai,
dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
asoc_simple_card_convert_fixup(&dai_props->adata, params);
/* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup(&priv->adata, params);
return 0;
}
static int asoc_graph_card_dai_link_of(struct device_node *ep,
static int asoc_graph_card_dai_link_of(struct device_node *cpu_ep,
struct device_node *codec_ep,
struct graph_card_data *priv,
unsigned int daifmt,
int idx, int is_fe)
int *dai_idx, int link_idx,
int *conf_idx, int is_fe)
{
struct device *dev = graph_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx);
struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx);
struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx);
struct snd_soc_card *card = graph_priv_to_card(priv);
struct device_node *ep = is_fe ? cpu_ep : codec_ep;
struct device_node *node = of_graph_get_port_parent(ep);
struct asoc_simple_dai *dai;
int ret;
if (is_fe) {
@ -113,11 +140,14 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
if (ret)
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai);
ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
@ -131,6 +161,8 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
asoc_simple_card_canonicalize_cpu(dai_link,
of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
} else {
struct snd_soc_codec_conf *cconf;
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
@ -140,11 +172,17 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup;
dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
cconf =
dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai);
ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai);
if (ret < 0)
return ret;
@ -154,13 +192,20 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret < 0)
return ret;
snd_soc_of_parse_audio_prefix(card,
&priv->codec_conf,
/* check "prefix" from top node */
snd_soc_of_parse_audio_prefix(card, cconf,
dai_link->codecs->of_node,
"prefix");
/* check "prefix" from each node if top doesn't have */
if (!cconf->of_node)
snd_soc_of_parse_node_prefix(node, cconf,
dai_link->codecs->of_node,
PREFIX "prefix");
}
ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai);
asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata);
ret = asoc_simple_card_of_parse_tdm(ep, dai);
if (ret)
return ret;
@ -168,7 +213,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *ep,
if (ret < 0)
return ret;
dai_link->dai_fmt = daifmt;
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &dai_link->dai_fmt);
if (ret < 0)
return ret;
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_graph_card_ops;
@ -186,11 +235,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
struct device_node *cpu_port;
struct device_node *cpu_ep;
struct device_node *codec_ep;
struct device_node *rcpu_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
unsigned int daifmt = 0;
int dai_idx, ret;
int dai_idx, link_idx, conf_idx, ret;
int rc, codec;
if (!node)
@ -201,47 +248,20 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
* see simple-card
*/
ret = asoc_simple_card_of_parse_routing(card, NULL, 0);
ret = asoc_simple_card_of_parse_routing(card, NULL);
if (ret < 0)
return ret;
asoc_simple_card_parse_convert(dev, NULL, &priv->adata);
asoc_simple_card_parse_convert(dev, node, NULL, &priv->adata);
/*
* it supports multi CPU, single CODEC only here
* see asoc_graph_get_dais_count
*/
/* find 1st codec */
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = of_get_next_child(cpu_port, NULL);
codec_ep = of_graph_get_remote_endpoint(cpu_ep);
rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
of_node_put(cpu_ep);
of_node_put(codec_ep);
of_node_put(rcpu_ep);
if (!codec_ep)
continue;
if (rcpu_ep != cpu_ep) {
dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n",
cpu_ep->name, codec_ep->name, rcpu_ep->name);
ret = -EINVAL;
goto parse_of_err;
}
ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
NULL, &daifmt);
if (ret < 0) {
of_node_put(cpu_port);
goto parse_of_err;
}
}
link_idx = 0;
dai_idx = 0;
conf_idx = 0;
codec_port_old = NULL;
for (codec = 0; codec < 2; codec++) {
/*
@ -257,31 +277,23 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
of_node_put(cpu_ep);
of_node_put(codec_ep);
of_node_put(cpu_port);
of_node_put(codec_port);
it.node = NULL;
if (codec) {
if (!codec_port)
continue;
if (codec_port_old == codec_port)
continue;
codec_port_old = codec_port;
/* Back-End (= Codec) */
ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0);
if (ret < 0) {
of_node_put(cpu_port);
goto parse_of_err;
}
} else {
/* Front-End (= CPU) */
ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1);
if (ret < 0) {
of_node_put(cpu_port);
goto parse_of_err;
}
}
ret = asoc_graph_card_dai_link_of(cpu_ep, codec_ep,
priv, &dai_idx,
link_idx++, &conf_idx,
!codec);
if (ret < 0)
goto parse_of_err;
}
}
@ -289,13 +301,24 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv)
if (ret)
goto parse_of_err;
if ((card->num_links != link_idx) ||
(card->num_configs != conf_idx)) {
dev_err(dev, "dai_link or codec_config wrong (%d/%d, %d/%d)\n",
card->num_links, link_idx, card->num_configs, conf_idx);
ret = -EINVAL;
goto parse_of_err;
}
ret = 0;
parse_of_err:
return ret;
}
static int asoc_graph_get_dais_count(struct device *dev)
static void asoc_graph_get_dais_count(struct device *dev,
int *link_num,
int *dais_num,
int *ccnf_num)
{
struct of_phandle_iterator it;
struct device_node *node = dev->of_node;
@ -304,10 +327,48 @@ static int asoc_graph_get_dais_count(struct device *dev)
struct device_node *codec_ep;
struct device_node *codec_port;
struct device_node *codec_port_old;
int count = 0;
struct device_node *codec_port_old2;
int rc;
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for dummy-Codec
*
* ex1)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 7
* CPU2 -/ ccnf : 1
* CPU3 --- Codec2
*
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
* => 7 DAIs = 4xCPU + 3xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex2)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 6
* CPU2 -/ ccnf : 1
* CPU3 -/
*
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex3)
* CPU0 --- Codec0 link : 6
* CPU1 -/ dais : 6
* CPU2 --- Codec1 ccnf : 2
* CPU3 -/
*
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 2 ccnf = 2xdummy-Codec
*/
codec_port_old = NULL;
codec_port_old2 = NULL;
of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
cpu_port = it.node;
cpu_ep = of_get_next_child(cpu_port, NULL);
@ -318,20 +379,22 @@ static int asoc_graph_get_dais_count(struct device *dev)
of_node_put(codec_ep);
of_node_put(codec_port);
if (cpu_ep)
count++;
(*link_num)++;
(*dais_num)++;
if (!codec_port)
if (codec_port_old == codec_port) {
if (codec_port_old2 != codec_port_old) {
(*link_num)++;
(*ccnf_num)++;
}
codec_port_old2 = codec_port_old;
continue;
}
if (codec_port_old == codec_port)
continue;
count++;
(*dais_num)++;
codec_port_old = codec_port;
}
return count;
}
static int asoc_graph_card_probe(struct platform_device *pdev)
@ -339,22 +402,27 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
struct graph_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct graph_dai_props *dai_props;
struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct snd_soc_card *card;
int num, ret, i;
struct snd_soc_codec_conf *cconf;
int lnum = 0, dnum = 0, cnum = 0;
int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
num = asoc_graph_get_dais_count(dev);
if (num == 0)
asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum);
if (!lnum || !dnum)
return -EINVAL;
dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
if (!dai_props || !dai_link)
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@ -363,7 +431,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
for (i = 0; i < num; i++) {
for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@ -371,15 +439,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
priv->dais = dais;
priv->codec_conf = cconf;
/* Init snd_soc_card */
card = graph_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
card->num_links = num;
card->codec_conf = &priv->codec_conf;
card->num_configs = 1;
card->num_links = lnum;
card->codec_conf = cconf;
card->num_configs = cnum;
ret = asoc_graph_card_parse_of(priv);
if (ret < 0) {

View File

@ -32,10 +32,11 @@ void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
void asoc_simple_card_parse_convert(struct device *dev,
struct device_node *np,
char *prefix,
struct asoc_simple_card_data *data)
{
struct device_node *np = dev->of_node;
char prop[128];
if (!prefix)
@ -151,21 +152,19 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
struct clk *clk)
{
dai->clk = clk;
}
int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
{
return clk_prepare_enable(dai->clk);
if (dai)
return clk_prepare_enable(dai->clk);
return 0;
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
{
clk_disable_unprepare(dai->clk);
if (dai)
clk_disable_unprepare(dai->clk);
}
EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
@ -200,7 +199,7 @@ int asoc_simple_card_parse_clk(struct device *dev,
if (!IS_ERR(clk)) {
simple_dai->sysclk = clk_get_rate(clk);
asoc_simple_card_clk_register(simple_dai, clk);
simple_dai->clk = clk;
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
simple_dai->sysclk = val;
} else {
@ -272,13 +271,24 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep)
{
struct device_node *node;
struct device_node *endpoint;
struct of_endpoint info;
int i, id;
int ret;
/* use driver specified DAI ID if exist */
ret = snd_soc_get_dai_id(ep);
if (ret != -ENOTSUPP)
return ret;
/* use endpoint/port reg if exist */
ret = of_graph_parse_endpoint(ep, &info);
if (ret == 0) {
if (info.id)
return info.id;
if (info.port)
return info.port;
}
node = of_graph_get_port_parent(ep);
/*
@ -348,6 +358,9 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
{
int ret;
if (!simple_dai)
return 0;
if (simple_dai->sysclk) {
ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
simple_dai->clk_direction);
@ -415,8 +428,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
char *prefix,
int optional)
char *prefix)
{
struct device_node *node = card->dev->of_node;
char prop[128];
@ -426,11 +438,8 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
if (!of_property_read_bool(node, prop)) {
if (optional)
return 0;
return -EINVAL;
}
if (!of_property_read_bool(node, prop))
return 0;
return snd_soc_of_parse_audio_routing(card, prop);
}

View File

@ -18,16 +18,19 @@
struct simple_card_data {
struct snd_soc_card snd_card;
struct simple_dai_props {
struct asoc_simple_dai cpu_dai;
struct asoc_simple_dai codec_dai;
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platform;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
unsigned int mclk_fs;
} *dai_props;
unsigned int mclk_fs;
struct asoc_simple_jack hp_jack;
struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct snd_soc_codec_conf *codec_conf;
};
#define simple_priv_to_card(priv) (&(priv)->snd_card)
@ -47,13 +50,13 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
simple_priv_to_props(priv, rtd->num);
int ret;
ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
@ -65,14 +68,17 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
asoc_simple_card_clk_disable(&dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
asoc_simple_card_clk_disable(&dai_props->codec_dai);
asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
unsigned long rate)
{
if (!simple_dai)
return 0;
if (!simple_dai->clk)
return 0;
@ -94,19 +100,17 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
unsigned int mclk, mclk_fs = 0;
int ret = 0;
if (priv->mclk_fs)
mclk_fs = priv->mclk_fs;
else if (dai_props->mclk_fs)
if (dai_props->mclk_fs)
mclk_fs = dai_props->mclk_fs;
if (mclk_fs) {
mclk = params_rate(params) * mclk_fs;
ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
if (ret < 0)
return ret;
ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
if (ret < 0)
return ret;
@ -134,33 +138,169 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = rtd->cpu_dai;
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
int ret;
ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
ret = asoc_simple_card_init_dai(rtd->codec_dai,
dai_props->codec_dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
ret = asoc_simple_card_init_dai(rtd->cpu_dai,
dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
static int asoc_simple_card_dai_link_of(struct device_node *node,
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
asoc_simple_card_convert_fixup(&dai_props->adata, params);
return 0;
}
static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top,
struct device_node *node,
struct device_node *np,
struct device_node *codec,
struct simple_card_data *priv,
int *dai_idx, int link_idx,
int *conf_idx, int is_fe,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
struct asoc_simple_dai *dai;
struct snd_soc_dai_link_component *codecs = dai_link->codecs;
char prop[128];
char *prefix = "";
int ret;
/* For single DAI link & old style of DT node */
if (is_top_level_node)
prefix = PREFIX;
if (is_fe) {
int is_single_links = 0;
/* BE is dummy */
codecs->of_node = NULL;
codecs->dai_name = "snd-soc-dummy-dai";
codecs->name = "snd-soc-dummy";
/* FE settings */
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
&is_single_links);
if (ret)
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"fe.%s",
dai_link->cpu_dai_name);
if (ret < 0)
return ret;
asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
} else {
struct snd_soc_codec_conf *cconf;
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
dai_link->cpu_name = "snd-soc-dummy";
/* BE settings */
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
cconf =
dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
if (ret < 0)
return ret;
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
"be.%s",
codecs->dai_name);
if (ret < 0)
return ret;
/* check "prefix" from top node */
snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node,
PREFIX "prefix");
snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node,
"prefix");
snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node,
"prefix");
}
asoc_simple_card_parse_convert(dev, top, PREFIX, &dai_props->adata);
asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata);
asoc_simple_card_parse_convert(dev, np, NULL, &dai_props->adata);
ret = asoc_simple_card_of_parse_tdm(np, dai);
if (ret)
return ret;
ret = asoc_simple_card_canonicalize_dailink(dai_link);
if (ret < 0)
return ret;
snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(node, prop, &dai_props->mclk_fs);
of_property_read_u32(np, prop, &dai_props->mclk_fs);
ret = asoc_simple_card_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
return ret;
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_simple_card_ops;
dai_link->init = asoc_simple_card_dai_init;
return 0;
}
static int asoc_simple_card_dai_link_of(struct device_node *top,
struct device_node *node,
struct simple_card_data *priv,
int idx,
int *dai_idx, int link_idx,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct device_node *cpu = NULL;
struct device_node *plat = NULL;
struct device_node *codec = NULL;
@ -193,12 +333,21 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
goto dai_link_of_err;
}
cpu_dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
codec_dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
goto dai_link_of_err;
of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
of_property_read_u32(node, prop, &dai_props->mclk_fs);
of_property_read_u32(cpu, prop, &dai_props->mclk_fs);
of_property_read_u32(codec, prop, &dai_props->mclk_fs);
ret = asoc_simple_card_parse_cpu(cpu, dai_link,
DAI, CELL, &single_cpu);
@ -286,61 +435,148 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node,
static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
struct device_node *top = dev->of_node;
struct snd_soc_card *card = simple_priv_to_card(priv);
struct device_node *dai_link;
struct device_node *node = dev->of_node;
int ret;
struct device_node *node;
struct device_node *np;
struct device_node *codec;
bool is_fe;
int ret, loop;
int dai_idx, link_idx, conf_idx;
if (!node)
if (!top)
return -EINVAL;
dai_link = of_get_child_by_name(node, PREFIX "dai-link");
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (ret < 0)
goto card_parse_end;
return ret;
ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
ret = asoc_simple_card_of_parse_routing(card, PREFIX);
if (ret < 0)
goto card_parse_end;
/* Factor to mclk, used in hw_params() */
of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
return ret;
/* Single/Muti DAI link(s) & New style of DT node */
if (dai_link) {
struct device_node *np = NULL;
int i = 0;
for_each_child_of_node(node, np) {
dev_dbg(dev, "\tlink %d:\n", i);
ret = asoc_simple_card_dai_link_of(np, priv,
i, false);
if (ret < 0) {
of_node_put(np);
goto card_parse_end;
}
i++;
}
} else {
/* For single DAI link & old style of DT node */
ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
if (ret < 0)
goto card_parse_end;
loop = 1;
link_idx = 0;
dai_idx = 0;
conf_idx = 0;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = dev->of_node;
loop = 0;
}
do {
/* DPCM */
if (of_get_child_count(node) > 2) {
for_each_child_of_node(node, np) {
codec = of_get_child_by_name(node,
loop ? "codec" :
PREFIX "codec");
if (!codec)
return -ENODEV;
is_fe = (np != codec);
ret = asoc_simple_card_dai_link_of_dpcm(
top, node, np, codec, priv,
&dai_idx, link_idx++, &conf_idx,
is_fe, !loop);
}
} else {
ret = asoc_simple_card_dai_link_of(
top, node, priv,
&dai_idx, link_idx++, !loop);
}
if (ret < 0)
return ret;
node = of_get_next_child(top, node);
} while (loop && node);
ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0)
goto card_parse_end;
return ret;
ret = asoc_simple_card_parse_aux_devs(node, priv);
card_parse_end:
of_node_put(dai_link);
ret = asoc_simple_card_parse_aux_devs(top, priv);
return ret;
}
static void asoc_simple_card_get_dais_count(struct device *dev,
int *link_num,
int *dais_num,
int *ccnf_num)
{
struct device_node *top = dev->of_node;
struct device_node *node;
int loop;
int num;
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for "dummy-Codec"
*
* ex1)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 7
* CPU2 -/ ccnf : 1
* CPU3 --- Codec2
*
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
* => 7 DAIs = 4xCPU + 3xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex2)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 6
* CPU2 -/ ccnf : 1
* CPU3 -/
*
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex3)
* CPU0 --- Codec0 link : 6
* CPU1 -/ dais : 6
* CPU2 --- Codec1 ccnf : 2
* CPU3 -/
*
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 2 ccnf = 2xdummy-Codec
*/
if (!top) {
(*link_num) = 1;
(*dais_num) = 2;
(*ccnf_num) = 0;
return;
}
loop = 1;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = top;
loop = 0;
}
do {
num = of_get_child_count(node);
(*dais_num) += num;
if (num > 2) {
(*link_num) += num;
(*ccnf_num)++;
} else {
(*link_num)++;
}
node = of_get_next_child(top, node);
} while (loop && node);
}
static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
@ -362,25 +598,28 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
struct asoc_simple_dai *dais;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct snd_soc_card *card;
int num, ret, i;
/* Get the number of DAI links */
if (np && of_get_child_by_name(np, PREFIX "dai-link"))
num = of_get_child_count(np);
else
num = 1;
struct snd_soc_codec_conf *cconf;
int lnum = 0, dnum = 0, cnum = 0;
int ret, i;
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
if (!dai_props || !dai_link)
asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
if (!lnum || !dnum)
return -EINVAL;
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@ -389,7 +628,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
for (i = 0; i < num; i++) {
for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@ -397,13 +636,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
priv->dais = dais;
priv->codec_conf = cconf;
/* Init snd_soc_card */
card = simple_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
card->num_links = num;
card->num_links = lnum;
card->codec_conf = cconf;
card->num_configs = cnum;
card->probe = asoc_simple_soc_card_probe;
if (np && of_device_is_available(np)) {
@ -419,6 +662,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
struct asoc_simple_card_info *cinfo;
struct snd_soc_dai_link_component *codecs;
struct snd_soc_dai_link_component *platform;
int dai_idx = 0;
cinfo = dev->platform_data;
if (!cinfo) {
@ -435,6 +679,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
return -EINVAL;
}
dai_props->cpu_dai = &priv->dais[dai_idx++];
dai_props->codec_dai = &priv->dais[dai_idx++];
codecs = dai_link->codecs;
codecs->name = cinfo->codec;
codecs->dai_name = cinfo->codec_dai.name;
@ -448,10 +695,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
dai_link->cpu_dai_name = cinfo->cpu_dai.name;
dai_link->dai_fmt = cinfo->daifmt;
dai_link->init = asoc_simple_card_dai_init;
memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
sizeof(priv->dai_props->cpu_dai));
memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
sizeof(priv->dai_props->codec_dai));
memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
sizeof(*priv->dai_props->cpu_dai));
memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
sizeof(*priv->dai_props->codec_dai));
}
snd_soc_card_set_drvdata(card, priv);
@ -476,6 +723,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
static const struct of_device_id asoc_simple_of_match[] = {
{ .compatible = "simple-audio-card", },
{ .compatible = "simple-scu-audio-card", },
{},
};
MODULE_DEVICE_TABLE(of, asoc_simple_of_match);

View File

@ -21,14 +21,18 @@
struct simple_card_data {
struct snd_soc_card snd_card;
struct snd_soc_codec_conf codec_conf;
struct simple_dai_props {
struct asoc_simple_dai dai;
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component codecs;
struct snd_soc_dai_link_component platform;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
} *dai_props;
struct snd_soc_dai_link *dai_link;
struct asoc_simple_dai *dais;
struct asoc_simple_card_data adata;
struct snd_soc_codec_conf *codec_conf;
};
#define simple_priv_to_card(priv) (&(priv)->snd_card)
@ -46,8 +50,17 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
int ret;
return asoc_simple_card_clk_enable(&dai_props->dai);
ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
if (ret)
return ret;
ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
if (ret)
asoc_simple_card_clk_disable(dai_props->cpu_dai);
return ret;
}
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
@ -57,7 +70,9 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
struct simple_dai_props *dai_props =
simple_priv_to_props(priv, rtd->num);
asoc_simple_card_clk_disable(&dai_props->dai);
asoc_simple_card_clk_disable(dai_props->cpu_dai);
asoc_simple_card_clk_disable(dai_props->codec_dai);
}
static const struct snd_soc_ops asoc_simple_card_ops = {
@ -67,42 +82,57 @@ static const struct snd_soc_ops asoc_simple_card_ops = {
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
int num = rtd->num;
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
int ret;
dai_link = simple_priv_to_link(priv, num);
dai_props = simple_priv_to_props(priv, num);
dai = dai_link->dynamic ?
rtd->cpu_dai :
rtd->codec_dai;
ret = asoc_simple_card_init_dai(rtd->codec_dai,
dai_props->codec_dai);
if (ret < 0)
return ret;
return asoc_simple_card_init_dai(dai, &dai_props->dai);
ret = asoc_simple_card_init_dai(rtd->cpu_dai,
dai_props->cpu_dai);
if (ret < 0)
return ret;
return 0;
}
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
asoc_simple_card_convert_fixup(&dai_props->adata, params);
/* overwrite by top level adata if exist */
asoc_simple_card_convert_fixup(&priv->adata, params);
return 0;
}
static int asoc_simple_card_dai_link_of(struct device_node *np,
static int asoc_simple_card_dai_link_of(struct device_node *link,
struct device_node *np,
struct device_node *codec,
struct simple_card_data *priv,
unsigned int daifmt,
int idx, bool is_fe)
int *dai_idx, int link_idx,
int *conf_idx, int is_fe,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx);
struct snd_soc_card *card = simple_priv_to_card(priv);
struct asoc_simple_dai *dai;
char *prefix = "";
int ret;
/* For single DAI link & old style of DT node */
if (is_top_level_node)
prefix = PREFIX;
if (is_fe) {
int is_single_links = 0;
struct snd_soc_dai_link_component *codecs;
@ -117,12 +147,15 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
dai =
dai_props->cpu_dai = &priv->dais[(*dai_idx)++];
ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
&is_single_links);
if (ret)
return ret;
ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai);
ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai);
if (ret < 0)
return ret;
@ -134,6 +167,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
} else {
struct snd_soc_codec_conf *cconf;
/* FE is dummy */
dai_link->cpu_of_node = NULL;
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
@ -143,11 +178,17 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
dai =
dai_props->codec_dai = &priv->dais[(*dai_idx)++];
cconf =
dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++];
ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
if (ret < 0)
return ret;
ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai);
ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai);
if (ret < 0)
return ret;
@ -157,13 +198,20 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0)
return ret;
snd_soc_of_parse_audio_prefix(card,
&priv->codec_conf,
/* check "prefix" from top node */
snd_soc_of_parse_audio_prefix(card, cconf,
dai_link->codecs->of_node,
PREFIX "prefix");
/* check "prefix" from each node if top doesn't have */
if (!cconf->of_node)
snd_soc_of_parse_node_prefix(np, cconf,
dai_link->codecs->of_node,
"prefix");
}
ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai);
asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata);
ret = asoc_simple_card_of_parse_tdm(np, dai);
if (ret)
return ret;
@ -171,7 +219,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *np,
if (ret < 0)
return ret;
dai_link->dai_fmt = daifmt;
ret = asoc_simple_card_parse_daifmt(dev, link, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
return ret;
dai_link->dpcm_playback = 1;
dai_link->dpcm_capture = 1;
dai_link->ops = &asoc_simple_card_ops;
@ -184,47 +236,57 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
struct device_node *top = dev->of_node;
struct device_node *node;
struct device_node *np;
struct device_node *codec;
struct snd_soc_card *card = simple_priv_to_card(priv);
struct device_node *node = dev->of_node;
unsigned int daifmt = 0;
bool is_fe;
int ret, i;
int ret, loop;
int dai_idx, link_idx, conf_idx;
if (!node)
if (!top)
return -EINVAL;
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
if (ret < 0)
return ret;
ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
ret = asoc_simple_card_of_parse_routing(card, PREFIX);
if (ret < 0)
return ret;
asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata);
asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
/* find 1st codec */
np = of_get_child_by_name(node, PREFIX "codec");
if (!np)
return -ENODEV;
ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt);
if (ret < 0)
return ret;
i = 0;
for_each_child_of_node(node, np) {
is_fe = false;
if (strcmp(np->name, PREFIX "cpu") == 0)
is_fe = true;
ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe);
if (ret < 0)
return ret;
i++;
loop = 1;
link_idx = 0;
dai_idx = 0;
conf_idx = 0;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = dev->of_node;
loop = 0;
}
do {
codec = of_get_child_by_name(node,
loop ? "codec" : PREFIX "codec");
if (!codec)
return -ENODEV;
for_each_child_of_node(node, np) {
is_fe = (np != codec);
ret = asoc_simple_card_dai_link_of(node, np, codec, priv,
&dai_idx, link_idx++,
&conf_idx,
is_fe, !loop);
if (ret < 0)
return ret;
}
node = of_get_next_child(top, node);
} while (loop && node);
ret = asoc_simple_card_parse_card_name(card, PREFIX);
if (ret < 0)
return ret;
@ -232,26 +294,106 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv)
return 0;
}
static void asoc_simple_card_get_dais_count(struct device *dev,
int *link_num,
int *dais_num,
int *ccnf_num)
{
struct device_node *top = dev->of_node;
struct device_node *node;
int loop;
int num;
/*
* link_num : number of links.
* CPU-Codec / CPU-dummy / dummy-Codec
* dais_num : number of DAIs
* ccnf_num : number of codec_conf
* same number for "dummy-Codec"
*
* ex1)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 7
* CPU2 -/ ccnf : 1
* CPU3 --- Codec2
*
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
* => 7 DAIs = 4xCPU + 3xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex2)
* CPU0 --- Codec0 link : 5
* CPU1 --- Codec1 dais : 6
* CPU2 -/ ccnf : 1
* CPU3 -/
*
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 1 ccnf = 1xdummy-Codec
*
* ex3)
* CPU0 --- Codec0 link : 6
* CPU1 -/ dais : 6
* CPU2 --- Codec1 ccnf : 2
* CPU3 -/
*
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
* => 6 DAIs = 4xCPU + 2xCodec
* => 2 ccnf = 2xdummy-Codec
*/
if (!top) {
(*link_num) = 1;
(*dais_num) = 2;
(*ccnf_num) = 0;
return;
}
loop = 1;
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = top;
loop = 0;
}
do {
num = of_get_child_count(node);
(*dais_num) += num;
if (num > 2) {
(*link_num) += num;
(*ccnf_num)++;
} else {
(*link_num)++;
}
node = of_get_next_child(top, node);
} while (loop && node);
}
static int asoc_simple_card_probe(struct platform_device *pdev)
{
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct simple_dai_props *dai_props;
struct asoc_simple_dai *dais;
struct snd_soc_card *card;
struct snd_soc_codec_conf *cconf;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int num, ret, i;
int ret, i;
int lnum = 0, dnum = 0, cnum = 0;
/* Allocate the private data */
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
num = of_get_child_count(np);
asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
if (!lnum || !dnum)
return -EINVAL;
dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
if (!dai_props || !dai_link)
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL);
cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL);
if (!dai_props || !dai_link || !dais)
return -ENOMEM;
/*
@ -260,7 +402,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
* see
* soc-core.c :: snd_soc_init_multicodec()
*/
for (i = 0; i < num; i++) {
for (i = 0; i < lnum; i++) {
dai_link[i].codecs = &dai_props[i].codecs;
dai_link[i].num_codecs = 1;
dai_link[i].platform = &dai_props[i].platform;
@ -268,15 +410,17 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
priv->dai_props = dai_props;
priv->dai_link = dai_link;
priv->dais = dais;
priv->codec_conf = cconf;
/* Init snd_soc_card */
card = simple_priv_to_card(priv);
card->owner = THIS_MODULE;
card->dev = dev;
card->dai_link = priv->dai_link;
card->num_links = num;
card->codec_conf = &priv->codec_conf;
card->num_configs = 1;
card->num_links = lnum;
card->codec_conf = cconf;
card->num_configs = cnum;
ret = asoc_simple_card_parse_of(priv);
if (ret < 0) {

View File

@ -102,15 +102,74 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI
recommended option
config SND_SOC_INTEL_SKYLAKE
tristate "SKL/BXT/KBL/GLK/CNL... Platforms"
tristate "All Skylake/SST Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_COMMON
select SND_SOC_INTEL_SKL
select SND_SOC_INTEL_APL
select SND_SOC_INTEL_KBL
select SND_SOC_INTEL_GLK
select SND_SOC_INTEL_CNL
select SND_SOC_INTEL_CFL
help
If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
GeminiLake or CannonLake platform with the DSP enabled in the BIOS
then enable this option by saying Y or m.
This is a backwards-compatible option to select all devices
supported by the Intel SST/Skylake driver. This option is no
longer recommended and will be deprecated when the SOF
driver is introduced. Distributions should explicitly
select which platform uses this driver.
if SND_SOC_INTEL_SKYLAKE
config SND_SOC_INTEL_SKL
tristate "Skylake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel Skylake platform with the DSP enabled
in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_APL
tristate "Broxton/ApolloLake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel Broxton/ApolloLake platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_KBL
tristate "Kabylake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel Kabylake platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_GLK
tristate "GeminiLake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel GeminiLake platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_CNL
tristate "CannonLake/WhiskyLake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel CNL/WHL platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_CFL
tristate "CoffeeLake Platforms"
depends on PCI && ACPI
select SND_SOC_INTEL_SKYLAKE_FAMILY
help
If you have a Intel CoffeeLake platform with the DSP
enabled in the BIOS then enable this option by saying Y or m.
config SND_SOC_INTEL_SKYLAKE_FAMILY
tristate
select SND_SOC_INTEL_SKYLAKE_COMMON
if SND_SOC_INTEL_SKYLAKE_FAMILY
config SND_SOC_INTEL_SKYLAKE_SSP_CLK
tristate
@ -135,7 +194,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
GeminiLake or CannonLake platform with the DSP enabled in the BIOS
then enable this option by saying Y or m.
endif ## SND_SOC_INTEL_SKYLAKE
endif ## SND_SOC_INTEL_SKYLAKE_FAMILY
config SND_SOC_ACPI_INTEL_MATCH
tristate

View File

@ -341,6 +341,10 @@ static int sst_acpi_probe(struct platform_device *pdev)
byt_rvp_platform_data.res_info = &bytcr_res_info;
}
/* update machine parameters */
mach->mach_params.acpi_ipc_irq_index =
pdata->res_info->acpi_ipc_irq_index;
plat_dev = platform_device_register_data(dev, pdata->platform, -1,
NULL, 0);
if (IS_ERR(plat_dev)) {

View File

@ -354,14 +354,14 @@ static int sst_request_fw(struct intel_sst_drv *sst)
const struct firmware *fw;
retval = request_firmware(&fw, sst->firmware_name, sst->dev);
if (fw == NULL) {
dev_err(sst->dev, "fw is returning as null\n");
return -EINVAL;
}
if (retval) {
dev_err(sst->dev, "request fw failed %d\n", retval);
return retval;
}
if (fw == NULL) {
dev_err(sst->dev, "fw is returning as null\n");
return -EINVAL;
}
mutex_lock(&sst->sst_lock);
retval = sst_cache_and_parse_fw(sst, fw);
mutex_unlock(&sst->sst_lock);

View File

@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large)
{
struct ipc_post *msg;
msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
msg = kzalloc(sizeof(*msg), GFP_KERNEL);
if (!msg)
return -ENOMEM;
if (large) {
msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
if (!msg->mailbox_data) {
kfree(msg);
return -ENOMEM;

View File

@ -172,7 +172,7 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
endif ## SND_SST_ATOM_HIFI2_PLATFORM
if SND_SOC_INTEL_SKYLAKE
if SND_SOC_INTEL_SKL
config SND_SOC_INTEL_SKL_RT286_MACH
tristate "SKL with RT286 I2S mode"
@ -212,6 +212,10 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
endif ## SND_SOC_INTEL_SKL
if SND_SOC_INTEL_APL
config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@ -239,6 +243,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
endif ## SND_SOC_INTEL_APL
if SND_SOC_INTEL_KBL
config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
tristate "KBL with RT5663 and MAX98927 in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@ -293,6 +301,20 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_INTEL_KBL_RT5660_MACH
tristate "KBL with RT5660 in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5660
select SND_SOC_HDAC_HDMI
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for RT5660 I2S audio codec.
Say Y if you have such a device.
endif ## SND_SOC_INTEL_KBL
if SND_SOC_INTEL_GLK
config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
tristate "GLK with RT5682 and MAX98357A in I2S Mode"
depends on MFD_INTEL_LPSS && I2C && ACPI
@ -307,7 +329,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
Say Y if you have such a device.
If unsure select "N".
endif ## SND_SOC_INTEL_SKYLAKE
endif ## SND_SOC_INTEL_GLK
if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC

View File

@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o
snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
snd-soc-kbl_rt5660-objs := kbl_rt5660.o
snd-soc-skl_rt286-objs := skl_rt286.o
snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o
snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
@ -46,6 +47,7 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max9
obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o
obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o

View File

@ -29,7 +29,6 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@ -674,6 +673,33 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
{ /* Point of View Mobii TAB-P1005W-232 (V2.0) */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "POV"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "I102A"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_DIFF_MIC |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{
/* Prowise PT301 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Prowise"),
DMI_MATCH(DMI_PRODUCT_NAME, "PT301"),
},
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
BYT_RT5640_JD_SRC_JD2_IN4N |
BYT_RT5640_OVCD_TH_2000UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_DIFF_MIC |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
@ -1152,10 +1178,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (is_valleyview()) {
struct sst_platform_info *p_info = mach->pdata;
const struct sst_res_info *res_info = p_info->res_info;
if (res_info->acpi_ipc_irq_index == 0)
if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}

View File

@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@ -920,10 +919,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
* (will be overridden if DMI quirk is detected)
*/
if (x86_match_cpu(baytrail_cpu_ids)) {
struct sst_platform_info *p_info = mach->pdata;
const struct sst_res_info *res_info = p_info->res_info;
if (res_info->acpi_ipc_irq_index == 0)
if (mach->mach_params.acpi_ipc_irq_index == 0)
is_bytcr = true;
}

Some files were not shown because too many files have changed in this diff Show More