mirror of https://gitee.com/openkylin/linux.git
Merge branch 'asoc-4.21' into asoc-next
This commit is contained in:
commit
a7a850dba8
|
@ -12,8 +12,8 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpio : a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the device starts.
|
||||
- reset-gpios : a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the device starts.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
AK4118 S/PDIF transceiver
|
||||
|
||||
This device supports I2C mode.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "asahi-kasei,ak4118"
|
||||
- reg : The I2C address of the device for I2C
|
||||
- reset-gpios: A GPIO specifier for the reset pin
|
||||
- irq-gpios: A GPIO specifier for the IRQ pin
|
||||
|
||||
Example:
|
||||
|
||||
&i2c {
|
||||
ak4118: ak4118@13 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "asahi-kasei,ak4118";
|
||||
reg = <0x13>;
|
||||
reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>
|
||||
irq-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
* Amlogic Audio SPDIF Input
|
||||
|
||||
Required properties:
|
||||
- compatible: 'amlogic,axg-spdifin'
|
||||
- interrupts: interrupt specifier for the spdif input.
|
||||
- clocks: list of clock phandle, one for each entry clock-names.
|
||||
- clock-names: should contain the following:
|
||||
* "pclk" : peripheral clock.
|
||||
* "refclk" : spdif input reference clock
|
||||
- #sound-dai-cells: must be 0.
|
||||
|
||||
Example on the A113 SoC:
|
||||
|
||||
spdifin: audio-controller@400 {
|
||||
compatible = "amlogic,axg-spdifin";
|
||||
reg = <0x0 0x400 0x0 0x30>;
|
||||
#sound-dai-cells = <0>;
|
||||
interrupts = <GIC_SPI 87 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clkc_audio AUD_CLKID_SPDIFIN>,
|
||||
<&clkc_audio AUD_CLKID_SPDIFIN_CLK>;
|
||||
clock-names = "pclk", "refclk";
|
||||
};
|
|
@ -32,7 +32,9 @@ Required properties:
|
|||
Optional properties:
|
||||
- pa-gpios: GPIO used to control external amplifier.
|
||||
|
||||
-----------------------
|
||||
Example: Single DAI case
|
||||
-----------------------
|
||||
|
||||
sound_card {
|
||||
compatible = "audio-graph-card";
|
||||
|
@ -61,7 +63,9 @@ Example: Single DAI case
|
|||
};
|
||||
};
|
||||
|
||||
-----------------------
|
||||
Example: Multi DAI case
|
||||
-----------------------
|
||||
|
||||
sound-card {
|
||||
compatible = "audio-graph-card";
|
||||
|
@ -130,3 +134,204 @@ Example: Multi DAI case
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
-----------------------
|
||||
Example: Sampling Rate Conversion
|
||||
-----------------------
|
||||
|
||||
sound_card {
|
||||
compatible = "audio-graph-card";
|
||||
|
||||
label = "sound-card";
|
||||
prefix = "codec";
|
||||
routing = "codec Playback", "DAI0 Playback",
|
||||
"DAI0 Capture", "codec Capture";
|
||||
convert-rate = <48000>;
|
||||
|
||||
dais = <&cpu_port>;
|
||||
};
|
||||
|
||||
audio-codec {
|
||||
...
|
||||
port {
|
||||
codec_endpoint: endpoint {
|
||||
remote-endpoint = <&cpu_endpoint>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dai-controller {
|
||||
...
|
||||
cpu_port: port {
|
||||
cpu_endpoint: endpoint {
|
||||
remote-endpoint = <&codec_endpoint>;
|
||||
|
||||
dai-format = "left_j";
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
-----------------------
|
||||
Example: 2 CPU 1 Codec (Mixing)
|
||||
-----------------------
|
||||
|
||||
sound_card {
|
||||
compatible = "audio-graph-card";
|
||||
|
||||
label = "sound-card";
|
||||
routing = "codec Playback", "DAI0 Playback",
|
||||
"codec Playback", "DAI1 Playback",
|
||||
"DAI0 Capture", "codec Capture";
|
||||
|
||||
dais = <&cpu_port>;
|
||||
};
|
||||
|
||||
audio-codec {
|
||||
...
|
||||
|
||||
audio-graph-card,prefix = "codec";
|
||||
audio-graph-card,convert-rate = <48000>;
|
||||
port {
|
||||
reg = <0>;
|
||||
codec_endpoint0: endpoint@0 {
|
||||
remote-endpoint = <&cpu_endpoint0>;
|
||||
};
|
||||
codec_endpoint1: endpoint@1 {
|
||||
remote-endpoint = <&cpu_endpoint1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dai-controller {
|
||||
...
|
||||
cpu_port: port {
|
||||
cpu_endpoint0: endpoint@0 {
|
||||
remote-endpoint = <&codec_endpoint0>;
|
||||
|
||||
dai-format = "left_j";
|
||||
...
|
||||
};
|
||||
cpu_endpoint1: endpoint@1 {
|
||||
remote-endpoint = <&codec_endpoint1>;
|
||||
|
||||
dai-format = "left_j";
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
-----------------------
|
||||
Example: Multi DAI with DPCM
|
||||
-----------------------
|
||||
|
||||
CPU0 ------ ak4613
|
||||
CPU1 ------ HDMI
|
||||
CPU2 ------ PCM3168A-p /* DPCM 1ch/2ch */
|
||||
CPU3 --/ /* DPCM 3ch/4ch */
|
||||
CPU4 --/ /* DPCM 5ch/6ch */
|
||||
CPU5 --/ /* DPCM 7ch/8ch */
|
||||
CPU6 ------ PCM3168A-c
|
||||
|
||||
sound_card: sound {
|
||||
compatible = "audio-graph-card";
|
||||
|
||||
label = "sound-card";
|
||||
|
||||
routing = "pcm3168a Playback", "DAI2 Playback",
|
||||
"pcm3168a Playback", "DAI3 Playback",
|
||||
"pcm3168a Playback", "DAI4 Playback",
|
||||
"pcm3168a Playback", "DAI5 Playback";
|
||||
|
||||
dais = <&snd_port0 /* ak4613 */
|
||||
&snd_port1 /* HDMI0 */
|
||||
&snd_port2 /* pcm3168a playback */
|
||||
&snd_port3 /* pcm3168a capture */
|
||||
>;
|
||||
};
|
||||
|
||||
ak4613: codec@10 {
|
||||
...
|
||||
port {
|
||||
ak4613_endpoint: endpoint {
|
||||
remote-endpoint = <&rsnd_endpoint0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pcm3168a: audio-codec@44 {
|
||||
...
|
||||
audio-graph-card,prefix = "pcm3168a";
|
||||
audio-graph-card,convert-channels = <8>; /* TDM Split */
|
||||
ports {
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
pcm3168a_endpoint_p1: endpoint@1 {
|
||||
remote-endpoint = <&rsnd_endpoint2>;
|
||||
...
|
||||
};
|
||||
pcm3168a_endpoint_p2: endpoint@2 {
|
||||
remote-endpoint = <&rsnd_endpoint3>;
|
||||
...
|
||||
};
|
||||
pcm3168a_endpoint_p3: endpoint@3 {
|
||||
remote-endpoint = <&rsnd_endpoint4>;
|
||||
...
|
||||
};
|
||||
pcm3168a_endpoint_p4: endpoint@4 {
|
||||
remote-endpoint = <&rsnd_endpoint5>;
|
||||
...
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
pcm3168a_endpoint_c: endpoint {
|
||||
remote-endpoint = <&rsnd_endpoint6>;
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&sound {
|
||||
ports {
|
||||
snd_port0: port@0 {
|
||||
rsnd_endpoint0: endpoint {
|
||||
remote-endpoint = <&ak4613_endpoint>;
|
||||
...
|
||||
};
|
||||
};
|
||||
snd_port1: port@1 {
|
||||
rsnd_endpoint1: endpoint {
|
||||
remote-endpoint = <&dw_hdmi0_snd_in>;
|
||||
...
|
||||
};
|
||||
};
|
||||
snd_port2: port@2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
rsnd_endpoint2: endpoint@2 {
|
||||
remote-endpoint = <&pcm3168a_endpoint_p1>;
|
||||
...
|
||||
};
|
||||
rsnd_endpoint3: endpoint@3 {
|
||||
remote-endpoint = <&pcm3168a_endpoint_p2>;
|
||||
...
|
||||
};
|
||||
rsnd_endpoint4: endpoint@4 {
|
||||
remote-endpoint = <&pcm3168a_endpoint_p3>;
|
||||
...
|
||||
};
|
||||
rsnd_endpoint5: endpoint@5 {
|
||||
remote-endpoint = <&pcm3168a_endpoint_p4>;
|
||||
...
|
||||
};
|
||||
};
|
||||
snd_port3: port@6 {
|
||||
rsnd_endpoint6: endpoint {
|
||||
remote-endpoint = <&pcm3168a_endpoint_c>;
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -77,11 +77,9 @@ Example 2. 2 CPU 1 Codec (Mixing)
|
|||
compatible = "audio-graph-scu-card";
|
||||
|
||||
label = "sound-card";
|
||||
prefix = "codec";
|
||||
routing = "codec Playback", "DAI0 Playback",
|
||||
"codec Playback", "DAI1 Playback",
|
||||
"DAI0 Capture", "codec Capture";
|
||||
convert-rate = <48000>;
|
||||
|
||||
dais = <&cpu_port0
|
||||
&cpu_port1>;
|
||||
|
@ -90,6 +88,8 @@ Example 2. 2 CPU 1 Codec (Mixing)
|
|||
audio-codec {
|
||||
...
|
||||
|
||||
audio-graph-card,prefix = "codec";
|
||||
audio-graph-card,convert-rate = <48000>;
|
||||
port {
|
||||
codec_endpoint0: endpoint {
|
||||
remote-endpoint = <&cpu_endpoint0>;
|
||||
|
|
|
@ -10,8 +10,8 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpio : a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the codec starts.
|
||||
- reset-gpios : a GPIO spec for the reset pin. If specified, it will be
|
||||
deasserted before communication to the codec starts.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -30,6 +30,11 @@ Optional properties:
|
|||
- ti,hwmods : Must be "mcasp<n>", n is controller instance starting 0
|
||||
- tx-num-evt : FIFO levels.
|
||||
- rx-num-evt : FIFO levels.
|
||||
- dismod : Specify the drive on TX pin during inactive slots
|
||||
0 : 3-state
|
||||
2 : logic low
|
||||
3 : logic high
|
||||
Defaults to 'logic low' when the property is not present
|
||||
- sram-size-playback : size of sram to be allocated during playback
|
||||
- sram-size-capture : size of sram to be allocated during capture
|
||||
- interrupts : Interrupt numbers for McASP
|
||||
|
|
|
@ -9,6 +9,7 @@ Optional properties:
|
|||
- dmicen-gpios: GPIO specifier for dmic to control start and stop
|
||||
- num-channels: Number of microphones on this DAI
|
||||
- wakeup-delay-ms: Delay (in ms) after enabling the DMIC
|
||||
- modeswitch-delay-ms: Delay (in ms) to complete DMIC mode switch
|
||||
|
||||
Example node:
|
||||
|
||||
|
@ -17,4 +18,5 @@ Example node:
|
|||
dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
|
||||
num-channels = <1>;
|
||||
wakeup-delay-ms <50>;
|
||||
modeswitch-delay-ms <35>;
|
||||
};
|
||||
|
|
|
@ -35,13 +35,13 @@ Required properties:
|
|||
|
||||
- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
|
||||
that SAI will work in the synchronous mode (sync Tx
|
||||
with Rx) which means both the transimitter and the
|
||||
with Rx) which means both the transmitter and the
|
||||
receiver will send and receive data by following
|
||||
receiver's bit clocks and frame sync clocks.
|
||||
|
||||
- fsl,sai-asynchronous: This is a boolean property. If present, indicating
|
||||
that SAI will work in the asynchronous mode, which
|
||||
means both transimitter and receiver will send and
|
||||
means both transmitter and receiver will send and
|
||||
receive data by following their own bit clocks and
|
||||
frame sync clocks separately.
|
||||
|
||||
|
@ -58,8 +58,8 @@ Optional properties (for mx6ul):
|
|||
Note:
|
||||
- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
|
||||
default synchronous mode (sync Rx with Tx) will be used, which means both
|
||||
transimitter and receiver will send and receive data by following clocks
|
||||
of transimitter.
|
||||
transmitter and receiver will send and receive data by following clocks
|
||||
of transmitter.
|
||||
- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive.
|
||||
|
||||
Example:
|
||||
|
|
|
@ -7,6 +7,8 @@ Required properties:
|
|||
<L3 interconnect address, size>;
|
||||
- interrupts: Interrupt number for McPDM
|
||||
- ti,hwmods: Name of the hwmod associated to the McPDM
|
||||
- clocks: phandle for the pdmclk provider, likely <&twl6040>
|
||||
- clock-names: Must be "pdmclk"
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -18,3 +20,11 @@ mcpdm: mcpdm@40132000 {
|
|||
interrupt-parent = <&gic>;
|
||||
ti,hwmods = "mcpdm";
|
||||
};
|
||||
|
||||
In board DTS file the pdmclk needs to be added:
|
||||
|
||||
&mcpdm {
|
||||
clocks = <&twl6040>;
|
||||
clock-names = "pdmclk";
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -9,9 +9,15 @@ Required properties:
|
|||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- ti,out-single-ended: "true" if output is single-ended;
|
||||
"false" or not specified if output is differential.
|
||||
|
||||
Examples:
|
||||
|
||||
pcm3060: pcm3060@46 {
|
||||
compatible = "ti,pcm3060";
|
||||
reg = <0x46>;
|
||||
ti,out-single-ended = "true";
|
||||
};
|
||||
|
|
|
@ -27,6 +27,28 @@ used by the apr service device.
|
|||
Value type: <u32>
|
||||
Definition: Must be 1
|
||||
|
||||
== ASM DAI is subnode of "dais" and represent a dai, it includes board specific
|
||||
configuration of each dai. Must contain the following properties.
|
||||
|
||||
- reg
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: Must be dai id
|
||||
|
||||
- direction:
|
||||
Usage: Required for Compress offload dais
|
||||
Value type: <u32>
|
||||
Definition: Specifies the direction of the dai stream
|
||||
0 for both tx and rx
|
||||
1 for only tx (Capture/Encode)
|
||||
2 for only rx (Playback/Decode)
|
||||
|
||||
- is-compress-dai:
|
||||
Usage: Required for Compress offload dais
|
||||
Value type: <boolean>
|
||||
Definition: present for Compress offload dais
|
||||
|
||||
|
||||
= EXAMPLE
|
||||
|
||||
q6asm@7 {
|
||||
|
@ -35,5 +57,10 @@ q6asm@7 {
|
|||
q6asmdai: dais {
|
||||
compatible = "qcom,q6asm-dais";
|
||||
#sound-dai-cells = <1>;
|
||||
mm@0 {
|
||||
reg = <0>;
|
||||
direction = <2>;
|
||||
is-compress-dai;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -39,15 +39,7 @@ This is example of
|
|||
Playback: [MEM] -> [SRC2] -> [DVC0] -> [SSIU0/SSI0] -> [codec]
|
||||
Capture: [MEM] <- [DVC1] <- [SRC3] <- [SSIU1/SSI1] <- [codec]
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
rcar_sound,dai {
|
||||
dai0 {
|
||||
playback = <&ssi0 &src2 &dvc0>;
|
||||
capture = <&ssi1 &src3 &dvc1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
see "Example: simple sound card"
|
||||
|
||||
You can use below.
|
||||
${LINUX}/arch/arm/boot/dts/r8a7790.dts can be good example.
|
||||
|
@ -83,29 +75,8 @@ SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
|
|||
** Asynchronous mode
|
||||
------------------
|
||||
|
||||
You need to use "simple-scu-audio-card" sound card for it.
|
||||
example)
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
/*
|
||||
* SRC Asynchronous mode setting
|
||||
* Playback:
|
||||
* All input data will be converted to 48kHz
|
||||
* Capture:
|
||||
* Inputed 48kHz data will be converted to
|
||||
* system specified Hz
|
||||
*/
|
||||
simple-audio-card,convert-rate = <48000>;
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
|
||||
see "Example: simple sound card for Asynchronous mode"
|
||||
|
||||
------------------
|
||||
** Synchronous mode
|
||||
|
@ -141,26 +112,8 @@ For more detail information, see below
|
|||
${LINUX}/sound/soc/sh/rcar/ctu.c
|
||||
- comment of header
|
||||
|
||||
You need to use "simple-scu-audio-card" sound card for it.
|
||||
example)
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
/*
|
||||
* CTU setting
|
||||
* All input data will be converted to 2ch
|
||||
* as output data
|
||||
*/
|
||||
simple-audio-card,convert-channels = <2>;
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
|
||||
see "Example: simple sound card for channel convert"
|
||||
|
||||
Ex) Exchange output channel
|
||||
Input -> Output
|
||||
|
@ -190,42 +143,13 @@ and these sounds will be merged by MIX.
|
|||
aplay -D plughw:0,0 xxxx.wav &
|
||||
aplay -D plughw:0,1 yyyy.wav
|
||||
|
||||
You need to use "simple-scu-audio-card" sound card for it.
|
||||
You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it.
|
||||
Ex)
|
||||
[MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
|
||||
|
|
||||
[MEM] -> [SRC2] -> [CTU03] -+
|
||||
|
||||
sound {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
simple-audio-card,cpu@0 {
|
||||
reg = <0>;
|
||||
sound-dai = <&rcar_sound 0>;
|
||||
};
|
||||
simple-audio-card,cpu@1 {
|
||||
reg = <1>;
|
||||
sound-dai = <&rcar_sound 1>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
rcar_sound,dai {
|
||||
dai0 {
|
||||
playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
|
||||
};
|
||||
dai1 {
|
||||
playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
see "Example: simple sound card for MIXer"
|
||||
|
||||
=============================================
|
||||
* DVC (Digital Volume and Mute Function)
|
||||
|
@ -257,15 +181,31 @@ Volume Ramp
|
|||
* SSIU (Serial Sound Interface Unit)
|
||||
=============================================
|
||||
|
||||
There is no DT settings for SSIU, because SSIU will be automatically
|
||||
selected via SSI.
|
||||
SSIU can avoid some under/over run error, because it has some buffer.
|
||||
But you can't use it if SSI was PIO mode.
|
||||
In DMA mode, you can select not to use SSIU by using "no-busif" on DT.
|
||||
In DMA mode, you can select not to use SSIU by using "no-busif" via SSI.
|
||||
|
||||
&ssi0 {
|
||||
no-busif;
|
||||
};
|
||||
SSIU handles BUSIF which will be used for TDM Split mode.
|
||||
This driver is assuming that audio-graph card will be used.
|
||||
|
||||
TDM Split mode merges 4 sounds. You can see 4 sound interface on system,
|
||||
and these sounds will be merged SSIU/SSI.
|
||||
|
||||
aplay -D plughw:0,0 xxxx.wav &
|
||||
aplay -D plughw:0,1 xxxx.wav &
|
||||
aplay -D plughw:0,2 xxxx.wav &
|
||||
aplay -D plughw:0,3 xxxx.wav
|
||||
|
||||
2ch 8ch
|
||||
[MEM] -> [SSIU 30] -+-> [SSIU 3] --> [Codec]
|
||||
2ch |
|
||||
[MEM] -> [SSIU 31] -+
|
||||
2ch |
|
||||
[MEM] -> [SSIU 32] -+
|
||||
2ch |
|
||||
[MEM] -> [SSIU 33] -+
|
||||
|
||||
see "Example: simple sound card for TDM Split"
|
||||
|
||||
=============================================
|
||||
* SSI (Serial Sound Interface)
|
||||
|
@ -304,14 +244,7 @@ This is example if SSI1 want to share WS pin with SSI0
|
|||
You can use Multi-SSI.
|
||||
This is example of SSI0/SSI1/SSI2 (= for 6ch)
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
rcar_sound,dai {
|
||||
dai0 {
|
||||
playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
see "Example: simple sound card for Multi channel"
|
||||
|
||||
** TDM-SSI
|
||||
|
||||
|
@ -319,19 +252,7 @@ You can use TDM with SSI.
|
|||
This is example of TDM 6ch.
|
||||
Driver can automatically switches TDM <-> stereo mode in this case.
|
||||
|
||||
rsnd_tdm: sound {
|
||||
compatible = "simple-audio-card";
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
/* system can use TDM 6ch */
|
||||
dai-tdm-slot-num = <6>;
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
see "Example: simple sound card for TDM"
|
||||
|
||||
=============================================
|
||||
Required properties:
|
||||
|
@ -346,6 +267,7 @@ Required properties:
|
|||
- "renesas,rcar_sound-r8a7744" (RZ/G1N)
|
||||
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
|
||||
- "renesas,rcar_sound-r8a774a1" (RZ/G2M)
|
||||
- "renesas,rcar_sound-r8a774c0" (RZ/G2E)
|
||||
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
||||
- "renesas,rcar_sound-r8a7779" (R-Car H1)
|
||||
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
||||
|
@ -356,6 +278,7 @@ Required properties:
|
|||
- "renesas,rcar_sound-r8a7796" (R-Car M3-W)
|
||||
- "renesas,rcar_sound-r8a77965" (R-Car M3-N)
|
||||
- "renesas,rcar_sound-r8a77990" (R-Car E3)
|
||||
- "renesas,rcar_sound-r8a77995" (R-Car D3)
|
||||
- reg : Should contain the register physical address.
|
||||
required register is
|
||||
SRU/ADG/SSI if generation1
|
||||
|
@ -363,6 +286,9 @@ Required properties:
|
|||
- rcar_sound,ssi : Should contain SSI feature.
|
||||
The number of SSI subnode should be same as HW.
|
||||
see below for detail.
|
||||
- rcar_sound,ssiu : Should contain SSIU feature.
|
||||
The number of SSIU subnode should be same as HW.
|
||||
see below for detail.
|
||||
- rcar_sound,src : Should contain SRC feature.
|
||||
The number of SRC subnode should be same as HW.
|
||||
see below for detail.
|
||||
|
@ -402,8 +328,13 @@ SSI subnode properties:
|
|||
- no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case
|
||||
- dma : Should contain Audio DMAC entry
|
||||
- dma-names : SSI case "rx" (=playback), "tx" (=capture)
|
||||
Deprecated: see SSIU subnode properties
|
||||
SSIU case "rxu" (=playback), "txu" (=capture)
|
||||
|
||||
SSIU subnode properties:
|
||||
- dma : Should contain Audio DMAC entry
|
||||
- dma-names : "rx" (=playback), "tx" (=capture)
|
||||
|
||||
SRC subnode properties:
|
||||
- dma : Should contain Audio DMAC entry
|
||||
- dma-names : "rx" (=playback), "tx" (=capture)
|
||||
|
@ -532,56 +463,55 @@ rcar_sound: sound@ec500000 {
|
|||
};
|
||||
};
|
||||
|
||||
rcar_sound,ssiu {
|
||||
ssiu00: ssiu-0 {
|
||||
dmas = <&audma0 0x15>, <&audma1 0x16>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssiu01: ssiu-1 {
|
||||
dmas = <&audma0 0x35>, <&audma1 0x36>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
ssiu95: ssiu-49 {
|
||||
dmas = <&audma0 0xA5>, <&audma1 0xA6>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssiu96: ssiu-50 {
|
||||
dmas = <&audma0 0xA7>, <&audma1 0xA8>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssiu97: ssiu-51 {
|
||||
dmas = <&audma0 0xA9>, <&audma1 0xAA>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
};
|
||||
|
||||
rcar_sound,ssi {
|
||||
ssi0: ssi-0 {
|
||||
interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
dmas = <&audma0 0x01>, <&audma1 0x02>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssi1: ssi-1 {
|
||||
interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi2: ssi-2 {
|
||||
interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi3: ssi-3 {
|
||||
interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi4: ssi-4 {
|
||||
interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi5: ssi-5 {
|
||||
interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi6: ssi-6 {
|
||||
interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
};
|
||||
ssi7: ssi-7 {
|
||||
interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
dmas = <&audma0 0x03>, <&audma1 0x04>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
ssi8: ssi-8 {
|
||||
interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
dmas = <&audma0 0x11>, <&audma1 0x12>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
ssi9: ssi-9 {
|
||||
interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
|
||||
dma-names = "rx", "tx", "rxu", "txu";
|
||||
dmas = <&audma0 0x13>, <&audma1 0x14>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -646,26 +576,175 @@ Example: simple sound card
|
|||
shared-pin;
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for Asynchronous mode
|
||||
=============================================
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
/*
|
||||
* SRC Asynchronous mode setting
|
||||
* Playback:
|
||||
* All input data will be converted to 48kHz
|
||||
* Capture:
|
||||
* Inputed 48kHz data will be converted to
|
||||
* system specified Hz
|
||||
*/
|
||||
simple-audio-card,convert-rate = <48000>;
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for channel convert
|
||||
=============================================
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
/*
|
||||
* CTU setting
|
||||
* All input data will be converted to 2ch
|
||||
* as output data
|
||||
*/
|
||||
simple-audio-card,convert-channels = <2>;
|
||||
...
|
||||
simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for MIXer
|
||||
=============================================
|
||||
|
||||
sound {
|
||||
compatible = "simple-scu-audio-card";
|
||||
...
|
||||
simple-audio-card,cpu@0 {
|
||||
sound-dai = <&rcar_sound 0>;
|
||||
};
|
||||
simple-audio-card,cpu@1 {
|
||||
sound-dai = <&rcar_sound 1>;
|
||||
};
|
||||
simple-audio-card,codec {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
rcar_sound,dai {
|
||||
dai0 {
|
||||
playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>;
|
||||
};
|
||||
dai1 {
|
||||
playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for TDM
|
||||
=============================================
|
||||
|
||||
rsnd_tdm: sound {
|
||||
compatible = "simple-audio-card";
|
||||
rsnd_tdm: sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&sndcodec>;
|
||||
simple-audio-card,frame-master = <&sndcodec>;
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&sndcodec>;
|
||||
simple-audio-card,frame-master = <&sndcodec>;
|
||||
|
||||
sndcpu: simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
dai-tdm-slot-num = <6>;
|
||||
sndcpu: simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
dai-tdm-slot-num = <6>;
|
||||
};
|
||||
|
||||
sndcodec: simple-audio-card,codec {
|
||||
sound-dai = <&xxx>;
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for TDM Split
|
||||
=============================================
|
||||
|
||||
sound_card: sound {
|
||||
compatible = "audio-graph-scu-card";
|
||||
prefix = "xxxx";
|
||||
routing = "xxxx Playback", "DAI0 Playback",
|
||||
"xxxx Playback", "DAI1 Playback",
|
||||
"xxxx Playback", "DAI2 Playback",
|
||||
"xxxx Playback", "DAI3 Playback";
|
||||
convert-channels = <8>; /* TDM Split */
|
||||
|
||||
dais = <&rsnd_port0 /* playback ch1/ch2 */
|
||||
&rsnd_port1 /* playback ch3/ch4 */
|
||||
&rsnd_port2 /* playback ch5/ch6 */
|
||||
&rsnd_port3 /* playback ch7/ch8 */
|
||||
>;
|
||||
};
|
||||
|
||||
audio-codec {
|
||||
...
|
||||
port {
|
||||
codec_0: endpoint@1 {
|
||||
remote-endpoint = <&rsnd_ep0>;
|
||||
};
|
||||
|
||||
sndcodec: simple-audio-card,codec {
|
||||
sound-dai = <&xxx>;
|
||||
codec_1: endpoint@2 {
|
||||
remote-endpoint = <&rsnd_ep1>;
|
||||
};
|
||||
codec_2: endpoint@3 {
|
||||
remote-endpoint = <&rsnd_ep2>;
|
||||
};
|
||||
codec_3: endpoint@4 {
|
||||
remote-endpoint = <&rsnd_ep3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&rcar_sound {
|
||||
...
|
||||
ports {
|
||||
rsnd_port0: port@0 {
|
||||
rsnd_ep0: endpoint {
|
||||
remote-endpoint = <&codec_0>;
|
||||
...
|
||||
playback = <&ssiu30 &ssi3>;
|
||||
};
|
||||
};
|
||||
rsnd_port1: port@1 {
|
||||
rsnd_ep1: endpoint {
|
||||
remote-endpoint = <&codec_1>;
|
||||
...
|
||||
playback = <&ssiu31 &ssi3>;
|
||||
};
|
||||
};
|
||||
rsnd_port2: port@2 {
|
||||
rsnd_ep2: endpoint {
|
||||
remote-endpoint = <&codec_2>;
|
||||
...
|
||||
playback = <&ssiu32 &ssi3>;
|
||||
};
|
||||
};
|
||||
rsnd_port3: port@3 {
|
||||
rsnd_ep3: endpoint {
|
||||
remote-endpoint = <&codec_3>;
|
||||
...
|
||||
playback = <&ssiu33 &ssi3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
=============================================
|
||||
Example: simple sound card for Multi channel
|
||||
|
|
|
@ -35,14 +35,14 @@ Pins on the device (for linking into audio routes):
|
|||
|
||||
Example:
|
||||
|
||||
alc5631: alc5631@1a {
|
||||
alc5631: audio-codec@1a {
|
||||
compatible = "realtek,alc5631";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
||||
or
|
||||
|
||||
rt5631: rt5631@1a {
|
||||
rt5631: audio-codec@1a {
|
||||
compatible = "realtek,rt5631";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
|
|
@ -10,6 +10,10 @@ Required properties:
|
|||
|
||||
- interrupts : The CODEC's interrupt output.
|
||||
|
||||
- avdd-supply: Power supply for AVDD, providing 1.8V.
|
||||
|
||||
- cpvdd-supply: Power supply for CPVDD, providing 3.5V.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- "realtek,dc_offset_l_manual"
|
||||
|
@ -51,4 +55,6 @@ rt5663: codec@12 {
|
|||
compatible = "realtek,rt5663";
|
||||
reg = <0x12>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
|
||||
avdd-supply = <&pp1800_a_alc5662>;
|
||||
cpvdd-supply = <&pp3500_a_alc5662>;
|
||||
};
|
||||
|
|
|
@ -4,9 +4,14 @@ Required properties:
|
|||
- compatible : "dioo,dio2125" or "simple-audio-amplifier"
|
||||
- enable-gpios : the gpio connected to the enable pin of the simple amplifier
|
||||
|
||||
Optional properties:
|
||||
- VCC-supply : power supply for the device, as covered
|
||||
in Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
Example:
|
||||
|
||||
amp: analog-amplifier {
|
||||
compatible = "simple-audio-amplifier";
|
||||
VCC-supply = <®ulator>;
|
||||
enable-gpios = <&gpio GPIOH_3 0>;
|
||||
};
|
||||
|
|
|
@ -95,7 +95,9 @@ Optional CPU/CODEC subnodes properties:
|
|||
initialization. It is useful for some aCPUs with
|
||||
fixed clocks.
|
||||
|
||||
-------------------------------------------
|
||||
Example 1 - single DAI link:
|
||||
-------------------------------------------
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
@ -138,7 +140,9 @@ sh_fsi2: sh_fsi2@ec230000 {
|
|||
interrupts = <0 146 0x4>;
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 2 - many DAI links:
|
||||
-------------------------------------------
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
@ -176,8 +180,10 @@ sound {
|
|||
};
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 3 - route audio from IMX6 SSI2 through TLV320DAC3100 codec
|
||||
through TPA6130A2 amplifier to headphones:
|
||||
-------------------------------------------
|
||||
|
||||
&i2c0 {
|
||||
codec: tlv320dac3100@18 {
|
||||
|
@ -210,3 +216,134 @@ sound {
|
|||
clocks = ...
|
||||
};
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 4. Sampling Rate Conversion
|
||||
-------------------------------------------
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
||||
simple-audio-card,name = "rsnd-ak4643";
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&sndcodec>;
|
||||
simple-audio-card,frame-master = <&sndcodec>;
|
||||
|
||||
simple-audio-card,convert-rate = <48000>;
|
||||
|
||||
simple-audio-card,prefix = "ak4642";
|
||||
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
|
||||
"DAI0 Capture", "ak4642 Capture";
|
||||
|
||||
sndcpu: simple-audio-card,cpu {
|
||||
sound-dai = <&rcar_sound>;
|
||||
};
|
||||
|
||||
sndcodec: simple-audio-card,codec {
|
||||
sound-dai = <&ak4643>;
|
||||
system-clock-frequency = <11289600>;
|
||||
};
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 5. 2 CPU 1 Codec (Mixing)
|
||||
-------------------------------------------
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
||||
simple-audio-card,name = "rsnd-ak4643";
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&dpcmcpu>;
|
||||
simple-audio-card,frame-master = <&dpcmcpu>;
|
||||
|
||||
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
|
||||
"ak4642 Playback", "DAI1 Playback";
|
||||
|
||||
dpcmcpu: cpu@0 {
|
||||
sound-dai = <&rcar_sound 0>;
|
||||
};
|
||||
|
||||
cpu@1 {
|
||||
sound-dai = <&rcar_sound 1>;
|
||||
};
|
||||
|
||||
codec {
|
||||
prefix = "ak4642";
|
||||
sound-dai = <&ak4643>;
|
||||
clocks = <&audio_clock>;
|
||||
};
|
||||
};
|
||||
|
||||
-------------------------------------------
|
||||
Example 6 - many DAI links with DPCM:
|
||||
-------------------------------------------
|
||||
|
||||
CPU0 ------ ak4613
|
||||
CPU1 ------ PCM3168A-p /* DPCM 1ch/2ch */
|
||||
CPU2 --/ /* DPCM 3ch/4ch */
|
||||
CPU3 --/ /* DPCM 5ch/6ch */
|
||||
CPU4 --/ /* DPCM 7ch/8ch */
|
||||
CPU5 ------ PCM3168A-c
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
|
||||
simple-audio-card,routing =
|
||||
"pcm3168a Playback", "DAI1 Playback",
|
||||
"pcm3168a Playback", "DAI2 Playback",
|
||||
"pcm3168a Playback", "DAI3 Playback",
|
||||
"pcm3168a Playback", "DAI4 Playback";
|
||||
|
||||
simple-audio-card,dai-link@0 {
|
||||
format = "left_j";
|
||||
bitclock-master = <&sndcpu0>;
|
||||
frame-master = <&sndcpu0>;
|
||||
|
||||
sndcpu0: cpu {
|
||||
sound-dai = <&rcar_sound 0>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&ak4613>;
|
||||
};
|
||||
};
|
||||
simple-audio-card,dai-link@1 {
|
||||
format = "i2s";
|
||||
bitclock-master = <&sndcpu1>;
|
||||
frame-master = <&sndcpu1>;
|
||||
|
||||
convert-channels = <8>; /* TDM Split */
|
||||
|
||||
sndcpu1: cpu@0 {
|
||||
sound-dai = <&rcar_sound 1>;
|
||||
};
|
||||
cpu@1 {
|
||||
sound-dai = <&rcar_sound 2>;
|
||||
};
|
||||
cpu@2 {
|
||||
sound-dai = <&rcar_sound 3>;
|
||||
};
|
||||
cpu@3 {
|
||||
sound-dai = <&rcar_sound 4>;
|
||||
};
|
||||
codec {
|
||||
mclk-fs = <512>;
|
||||
prefix = "pcm3168a";
|
||||
dai-tdm-slot-num = <8>;
|
||||
sound-dai = <&pcm3168a 0>;
|
||||
};
|
||||
};
|
||||
simple-audio-card,dai-link@2 {
|
||||
format = "i2s";
|
||||
bitclock-master = <&sndcpu2>;
|
||||
frame-master = <&sndcpu2>;
|
||||
|
||||
sndcpu2: cpu {
|
||||
sound-dai = <&rcar_sound 5>;
|
||||
};
|
||||
codec {
|
||||
mclk-fs = <512>;
|
||||
prefix = "pcm3168a";
|
||||
sound-dai = <&pcm3168a 1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -75,7 +75,6 @@ sound {
|
|||
simple-audio-card,bitclock-master = <&dpcmcpu>;
|
||||
simple-audio-card,frame-master = <&dpcmcpu>;
|
||||
|
||||
simple-audio-card,prefix = "ak4642";
|
||||
simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
|
||||
"ak4642 Playback", "DAI1 Playback";
|
||||
|
||||
|
@ -88,6 +87,7 @@ sound {
|
|||
};
|
||||
|
||||
codec {
|
||||
prefix = "ak4642";
|
||||
sound-dai = <&ak4643>;
|
||||
clocks = <&audio_clock>;
|
||||
};
|
||||
|
|
|
@ -4,9 +4,11 @@ Required properties:
|
|||
- compatible: must be one of the following compatibles:
|
||||
- "allwinner,sun50i-a64-codec-analog"
|
||||
- reg: must contain the registers location and length
|
||||
- cpvdd-supply: Regulator supply for the headphone amplifier
|
||||
|
||||
Example:
|
||||
codec_analog: codec-analog@1f015c0 {
|
||||
compatible = "allwinner,sun50i-a64-codec-analog";
|
||||
reg = <0x01f015c0 0x4>;
|
||||
cpvdd-supply = <®_eldo1>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
Device-Tree bindings for Xilinx I2S PL block
|
||||
|
||||
The IP supports I2S based playback/capture audio
|
||||
|
||||
Required property:
|
||||
- compatible: "xlnx,i2s-transmitter-1.0" for playback and
|
||||
"xlnx,i2s-receiver-1.0" for capture
|
||||
|
||||
Required property common to both I2S playback and capture:
|
||||
- reg: Base address and size of the IP core instance.
|
||||
- xlnx,dwidth: sample data width. Can be any of 16, 24.
|
||||
- xlnx,num-channels: Number of I2S streams. Can be any of 1, 2, 3, 4.
|
||||
supported channels = 2 * xlnx,num-channels
|
||||
|
||||
Example:
|
||||
|
||||
i2s_receiver@a0080000 {
|
||||
compatible = "xlnx,i2s-receiver-1.0";
|
||||
reg = <0x0 0xa0080000 0x0 0x10000>;
|
||||
xlnx,dwidth = <0x18>;
|
||||
xlnx,num-channels = <1>;
|
||||
};
|
||||
i2s_transmitter@a0090000 {
|
||||
compatible = "xlnx,i2s-transmitter-1.0";
|
||||
reg = <0x0 0xa0090000 0x0 0x10000>;
|
||||
xlnx,dwidth = <0x18>;
|
||||
xlnx,num-channels = <1>;
|
||||
};
|
18
MAINTAINERS
18
MAINTAINERS
|
@ -1310,6 +1310,13 @@ F: drivers/pinctrl/meson/
|
|||
F: drivers/mmc/host/meson*
|
||||
N: meson
|
||||
|
||||
ARM/Amlogic Meson SoC Sound Drivers
|
||||
M: Jerome Brunet <jbrunet@baylibre.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: sound/soc/meson/
|
||||
F: Documentation/devicetree/bindings/sound/amlogic*
|
||||
|
||||
ARM/Annapurna Labs ALPINE ARCHITECTURE
|
||||
M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
|
||||
M: Antoine Tenart <antoine.tenart@bootlin.com>
|
||||
|
@ -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
|
||||
|
|
|
@ -167,8 +167,9 @@ CONFIG_SOUND=m
|
|||
CONFIG_SND=m
|
||||
CONFIG_SND_USB_AUDIO=m
|
||||
CONFIG_SND_SOC=m
|
||||
CONFIG_SND_EDMA_SOC=m
|
||||
CONFIG_SND_DA850_SOC_EVM=m
|
||||
CONFIG_SND_SOC_TLV320AIC3X=m
|
||||
CONFIG_SND_SOC_DAVINCI_MCASP=m
|
||||
CONFIG_SND_SOC_DAVINCI_EVM=m
|
||||
CONFIG_SND_SIMPLE_CARD=m
|
||||
CONFIG_HID=m
|
||||
CONFIG_HID_A4TECH=m
|
||||
|
|
|
@ -175,8 +175,6 @@ CONFIG_SND_PCM_OSS=y
|
|||
# CONFIG_SND_VERBOSE_PROCFS is not set
|
||||
CONFIG_SND_DUMMY=y
|
||||
CONFIG_SND_USB_AUDIO=y
|
||||
CONFIG_SND_SOC=y
|
||||
CONFIG_SND_OMAP_SOC=y
|
||||
# CONFIG_USB_HID is not set
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_PHY=y
|
||||
|
|
|
@ -381,13 +381,13 @@ CONFIG_SND_VERBOSE_PRINTK=y
|
|||
CONFIG_SND_DEBUG=y
|
||||
CONFIG_SND_USB_AUDIO=m
|
||||
CONFIG_SND_SOC=m
|
||||
CONFIG_SND_EDMA_SOC=m
|
||||
CONFIG_SND_AM33XX_SOC_EVM=m
|
||||
CONFIG_SND_OMAP_SOC=m
|
||||
CONFIG_SND_OMAP_SOC_HDMI_AUDIO=m
|
||||
CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m
|
||||
CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m
|
||||
CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
|
||||
CONFIG_SND_SOC_TLV320AIC3X=m
|
||||
CONFIG_SND_SOC_DAVINCI_MCASP=m
|
||||
CONFIG_SND_SOC_NOKIA_RX51=m
|
||||
CONFIG_SND_SOC_OMAP_HDMI=m
|
||||
CONFIG_SND_SOC_OMAP_ABE_TWL6040=m
|
||||
CONFIG_SND_SOC_OMAP3_PANDORA=m
|
||||
CONFIG_SND_SOC_OMAP3_TWL4030=m
|
||||
CONFIG_SND_SOC_CPCAP=m
|
||||
CONFIG_SND_SIMPLE_CARD=m
|
||||
CONFIG_SND_AUDIO_GRAPH_CARD=m
|
||||
|
|
|
@ -794,9 +794,9 @@ static __init void dm365_evm_init(void)
|
|||
/* maybe setup mmc1/etc ... _after_ mmc0 */
|
||||
evm_init_cpld();
|
||||
|
||||
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
|
||||
#ifdef CONFIG_SND_SOC_DM365_AIC3X_CODEC
|
||||
dm365_init_asp();
|
||||
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
|
||||
#elif defined(CONFIG_SND_SOC_DM365_VOICE_CODEC)
|
||||
dm365_init_vc();
|
||||
#endif
|
||||
dm365_init_rtc();
|
||||
|
|
|
@ -8,7 +8,7 @@ obj-y := io.o id.o sram-init.o sram.o time.o irq.o mux.o flash.o \
|
|||
serial.o devices.o dma.o fb.o
|
||||
obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
|
||||
|
||||
ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
|
||||
ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
|
||||
obj-y += mcbsp.o
|
||||
endif
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ obj-$(CONFIG_SOC_OMAP5) += $(hwmod-common) $(secure-common)
|
|||
obj-$(CONFIG_SOC_AM43XX) += $(hwmod-common) $(secure-common)
|
||||
obj-$(CONFIG_SOC_DRA7XX) += $(hwmod-common) $(secure-common)
|
||||
|
||||
ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
|
||||
ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
|
||||
obj-y += mcbsp.o
|
||||
endif
|
||||
|
||||
|
|
|
@ -524,7 +524,7 @@ void omap_auxdata_legacy_init(struct device *dev)
|
|||
dev->platform_data = &twl_gpio_auxdata;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
|
||||
static struct omap_mcbsp_platform_data mcbsp_pdata;
|
||||
static void __init omap3_mcbsp_init(void)
|
||||
{
|
||||
|
@ -572,7 +572,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] = {
|
|||
OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
|
||||
&am35xx_emac_pdata),
|
||||
/* McBSP modules with sidetone core */
|
||||
#if IS_ENABLED(CONFIG_SND_OMAP_SOC_MCBSP)
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP)
|
||||
OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49022000, "49022000.mcbsp", &mcbsp_pdata),
|
||||
OF_DEV_AUXDATA("ti,omap3-mcbsp", 0x49024000, "49024000.mcbsp", &mcbsp_pdata),
|
||||
#endif
|
||||
|
|
|
@ -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__ */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -116,12 +116,12 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card);
|
|||
|
||||
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
|
||||
struct snd_pcm_hw_params *params);
|
||||
void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
|
||||
void asoc_simple_card_parse_convert(struct device *dev,
|
||||
struct device_node *np, char *prefix,
|
||||
struct asoc_simple_card_data *data);
|
||||
|
||||
int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
|
||||
char *prefix,
|
||||
int optional);
|
||||
char *prefix);
|
||||
int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
|
||||
char *prefix);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[];
|
|||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
|
||||
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[];
|
||||
|
||||
/*
|
||||
* generic table used for HDA codec-based platforms, possibly with
|
||||
|
|
|
@ -37,6 +37,20 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
|
|||
struct snd_soc_acpi_mach *
|
||||
snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines);
|
||||
|
||||
/**
|
||||
* snd_soc_acpi_mach_params: interface for machine driver configuration
|
||||
*
|
||||
* @acpi_ipc_irq_index: used for BYT-CR detection
|
||||
* @platform: string used for HDaudio codec support
|
||||
* @codec_mask: used for HDAudio support
|
||||
*/
|
||||
struct snd_soc_acpi_mach_params {
|
||||
u32 acpi_ipc_irq_index;
|
||||
const char *platform;
|
||||
u32 codec_mask;
|
||||
u32 dmic_num;
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are
|
||||
* related to the hardware, except for the firmware and topology file names.
|
||||
|
@ -68,6 +82,7 @@ struct snd_soc_acpi_mach {
|
|||
struct snd_soc_acpi_mach * (*machine_quirk)(void *arg);
|
||||
const void *quirk_data;
|
||||
void *pdata;
|
||||
struct snd_soc_acpi_mach_params mach_params;
|
||||
const char *sof_fw_filename;
|
||||
const char *sof_tplg_filename;
|
||||
const char *asoc_plat_name;
|
||||
|
|
|
@ -553,12 +553,12 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_SOC_AC97_BUS
|
||||
struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component);
|
||||
struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component,
|
||||
unsigned int id, unsigned int id_mask);
|
||||
void snd_soc_free_ac97_component(struct snd_ac97 *ac97);
|
||||
|
||||
#ifdef CONFIG_SND_SOC_AC97_BUS
|
||||
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
|
||||
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
|
||||
struct platform_device *pdev);
|
||||
|
@ -1477,10 +1477,20 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
|
|||
unsigned int *rx_mask,
|
||||
unsigned int *slots,
|
||||
unsigned int *slot_width);
|
||||
void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
|
||||
void snd_soc_of_parse_node_prefix(struct device_node *np,
|
||||
struct snd_soc_codec_conf *codec_conf,
|
||||
struct device_node *of_node,
|
||||
const char *propname);
|
||||
static inline
|
||||
void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
|
||||
struct snd_soc_codec_conf *codec_conf,
|
||||
struct device_node *of_node,
|
||||
const char *propname)
|
||||
{
|
||||
snd_soc_of_parse_node_prefix(card->dev->of_node,
|
||||
codec_conf, of_node, propname);
|
||||
}
|
||||
|
||||
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
|
||||
const char *propname);
|
||||
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -46,13 +46,11 @@ source "sound/soc/atmel/Kconfig"
|
|||
source "sound/soc/au1x/Kconfig"
|
||||
source "sound/soc/bcm/Kconfig"
|
||||
source "sound/soc/cirrus/Kconfig"
|
||||
source "sound/soc/davinci/Kconfig"
|
||||
source "sound/soc/dwc/Kconfig"
|
||||
source "sound/soc/fsl/Kconfig"
|
||||
source "sound/soc/hisilicon/Kconfig"
|
||||
source "sound/soc/jz4740/Kconfig"
|
||||
source "sound/soc/nuc900/Kconfig"
|
||||
source "sound/soc/omap/Kconfig"
|
||||
source "sound/soc/kirkwood/Kconfig"
|
||||
source "sound/soc/img/Kconfig"
|
||||
source "sound/soc/intel/Kconfig"
|
||||
|
@ -70,9 +68,11 @@ source "sound/soc/sti/Kconfig"
|
|||
source "sound/soc/stm/Kconfig"
|
||||
source "sound/soc/sunxi/Kconfig"
|
||||
source "sound/soc/tegra/Kconfig"
|
||||
source "sound/soc/ti/Kconfig"
|
||||
source "sound/soc/txx9/Kconfig"
|
||||
source "sound/soc/uniphier/Kconfig"
|
||||
source "sound/soc/ux500/Kconfig"
|
||||
source "sound/soc/xilinx/Kconfig"
|
||||
source "sound/soc/xtensa/Kconfig"
|
||||
source "sound/soc/zte/Kconfig"
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ obj-$(CONFIG_SND_SOC) += atmel/
|
|||
obj-$(CONFIG_SND_SOC) += au1x/
|
||||
obj-$(CONFIG_SND_SOC) += bcm/
|
||||
obj-$(CONFIG_SND_SOC) += cirrus/
|
||||
obj-$(CONFIG_SND_SOC) += davinci/
|
||||
obj-$(CONFIG_SND_SOC) += dwc/
|
||||
obj-$(CONFIG_SND_SOC) += fsl/
|
||||
obj-$(CONFIG_SND_SOC) += hisilicon/
|
||||
|
@ -41,7 +40,6 @@ obj-$(CONFIG_SND_SOC) += mediatek/
|
|||
obj-$(CONFIG_SND_SOC) += meson/
|
||||
obj-$(CONFIG_SND_SOC) += mxs/
|
||||
obj-$(CONFIG_SND_SOC) += nuc900/
|
||||
obj-$(CONFIG_SND_SOC) += omap/
|
||||
obj-$(CONFIG_SND_SOC) += kirkwood/
|
||||
obj-$(CONFIG_SND_SOC) += pxa/
|
||||
obj-$(CONFIG_SND_SOC) += qcom/
|
||||
|
@ -54,8 +52,10 @@ obj-$(CONFIG_SND_SOC) += sti/
|
|||
obj-$(CONFIG_SND_SOC) += stm/
|
||||
obj-$(CONFIG_SND_SOC) += sunxi/
|
||||
obj-$(CONFIG_SND_SOC) += tegra/
|
||||
obj-$(CONFIG_SND_SOC) += ti/
|
||||
obj-$(CONFIG_SND_SOC) += txx9/
|
||||
obj-$(CONFIG_SND_SOC) += uniphier/
|
||||
obj-$(CONFIG_SND_SOC) += ux500/
|
||||
obj-$(CONFIG_SND_SOC) += xilinx/
|
||||
obj-$(CONFIG_SND_SOC) += xtensa/
|
||||
obj-$(CONFIG_SND_SOC) += zte/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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");
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev,
|
|||
|
||||
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),
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -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, ®);
|
||||
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;
|
||||
|
|
|
@ -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, ®);
|
||||
ret = regmap_read(max9867->regmap, MAX9867_REVISION, ®);
|
||||
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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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" },
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue