Merge branch 'asoc-4.18' into asoc-next

This commit is contained in:
Mark Brown 2018-06-05 12:27:32 +01:00
commit 5544717d41
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0
251 changed files with 29777 additions and 3987 deletions

View file

@ -0,0 +1,84 @@
Qualcomm APR (Asynchronous Packet Router) binding
This binding describes the Qualcomm APR. APR is a IPC protocol for
communication between Application processor and QDSP. APR is mainly
used for audio/voice services on the QDSP.
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be "qcom,apr-v<VERSION-NUMBER>", example "qcom,apr-v2"
- reg
Usage: required
Value type: <u32>
Definition: Destination processor ID.
Possible values are :
1 - APR simulator
2 - PC
3 - MODEM
4 - ADSP
5 - APPS
6 - MODEM2
7 - APPS2
= APR SERVICES
Each subnode of the APR node represents service tied to this apr. The name
of the nodes are not important. The properties of these nodes are defined
by the individual bindings for the specific service
- All APR services MUST contain the following property:
- reg
Usage: required
Value type: <u32>
Definition: APR Service ID
Possible values are :
3 - DSP Core Service
4 - Audio Front End Service.
5 - Voice Stream Manager Service.
6 - Voice processing manager.
7 - Audio Stream Manager Service.
8 - Audio Device Manager Service.
9 - Multimode voice manager.
10 - Core voice stream.
11 - Core voice processor.
12 - Ultrasound stream manager.
13 - Listen stream manager.
= EXAMPLE
The following example represents a QDSP based sound card on a MSM8996 device
which uses apr as communication between Apps and QDSP.
apr@4 {
compatible = "qcom,apr-v2";
reg = <APR_DOMAIN_ADSP>;
q6core@3 {
compatible = "qcom,q6core";
reg = <APR_SVC_ADSP_CORE>;
};
q6afe@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
dais {
#sound-dai-cells = <1>;
hdmi@1 {
reg = <1>;
};
};
};
q6asm@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
...
};
q6adm@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
...
};
};

View file

@ -0,0 +1,14 @@
Analog Devices SSM2305 Speaker Amplifier
========================================
Required properties:
- compatible : "adi,ssm2305"
- shutdown-gpios : The gpio connected to the shutdown pin.
The gpio signal is ACTIVE_LOW.
Example:
ssm2305: analog-amplifier {
compatible = "adi,ssm2305";
shutdown-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>;
};

View file

@ -0,0 +1,47 @@
* Atmel I2S controller
Required properties:
- compatible: Should be "atmel,sama5d2-i2s".
- reg: Should be the physical base address of the controller and the
length of memory mapped region.
- interrupts: Should contain the interrupt for the controller.
- dmas: Should be one per channel name listed in the dma-names property,
as described in atmel-dma.txt and dma.txt files.
- dma-names: Two dmas have to be defined, "tx" and "rx".
This IP also supports one shared channel for both rx and tx;
if this mode is used, one "rx-tx" name must be used.
- clocks: Must contain an entry for each entry in clock-names.
Please refer to clock-bindings.txt.
- clock-names: Should be one of each entry matching the clocks phandles list:
- "pclk" (peripheral clock) Required.
- "gclk" (generated clock) Optional (1).
- "aclk" (Audio PLL clock) Optional (1).
- "muxclk" (I2S mux clock) Optional (1).
Optional properties:
- pinctrl-0: Should specify pin control groups used for this controller.
- princtrl-names: Should contain only one value - "default".
(1) : Only the peripheral clock is required. The generated clock, the Audio
PLL clock adn the I2S mux clock are optional and should only be set
together, when Master Mode is required.
Example:
i2s@f8050000 {
compatible = "atmel,sama5d2-i2s";
reg = <0xf8050000 0x300>;
interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>;
dmas = <&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(31))>,
<&dma0
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
AT91_XDMAC_DT_PERID(32))>;
dma-names = "tx", "rx";
clocks = <&i2s0_clk>, <&i2s0_gclk>, <&audio_pll_pmc>, <&i2s0muxck>;
clock-names = "pclk", "gclk", "aclk", "muxclk";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2s0_default>;
};

View file

@ -16,7 +16,7 @@ Required properties:
Example:
codec: cs42888@48 {
cs42888: codec@48 {
compatible = "cirrus,cs42888";
reg = <0x48>;
clocks = <&codec_mclk 0>;

View file

@ -31,14 +31,16 @@ Required properties:
it. This property is optional depending on the SoC
design.
- big-endian : If this property is absent, the little endian mode
will be in use as default. Otherwise, the big endian
mode will be in use for all the device registers.
- fsl,asrc-rate : Defines a mutual sample rate used by DPCM Back Ends.
- fsl,asrc-width : Defines a mutual sample width used by DPCM Back Ends.
Optional properties:
- big-endian : If this property is absent, the little endian mode
will be in use as default. Otherwise, the big endian
mode will be in use for all the device registers.
Example:
asrc: asrc@2034000 {

View file

@ -42,6 +42,8 @@ Required properties:
means all the settings for Receiving would be
duplicated from Transmition related registers.
Optional properties:
- big-endian : If this property is absent, the native endian mode
will be in use as default, or the big endian mode
will be in use for all the device registers.

View file

@ -33,6 +33,8 @@ Required properties:
it. This property is optional depending on the SoC
design.
Optional properties:
- big-endian : If this property is absent, the native endian mode
will be in use as default, or the big endian mode
will be in use for all the device registers.

View file

@ -28,9 +28,6 @@ Required properties:
pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
for details of the property values.
- big-endian : Boolean property, required if all the FTM_PWM
registers are big-endian rather than little-endian.
- lsb-first : Configures whether the LSB or the MSB is transmitted
first for the fifo data. If this property is absent,
the MSB is transmitted first as default, or the LSB
@ -48,6 +45,11 @@ Required properties:
receive data by following their own bit clocks and
frame sync clocks separately.
Optional properties:
- big-endian : Boolean property, required if all the SAI
registers are big-endian rather than little-endian.
Optional properties (for mx6ul):
- fsl,sai-mclk-direction-output: This is a boolean property. If present,

View file

@ -1,7 +1,9 @@
Mediatek AFE PCM controller for mt2701
Required properties:
- compatible = "mediatek,mt2701-audio";
- compatible: should be one of the followings.
- "mediatek,mt2701-audio"
- "mediatek,mt7622-audio"
- interrupts: should contain AFE and ASYS interrupts
- interrupt-names: should be "afe" and "asys"
- power-domains: should define the power domain

View file

@ -0,0 +1,16 @@
Mediatek MT6351 Audio Codec
The communication between MT6351 and SoC is through Mediatek PMIC wrapper.
For more detail, please visit Mediatek PMIC wrapper documentation.
Must be a child node of PMIC wrapper.
Required properties:
- compatible : "mediatek,mt6351-sound".
Example:
mt6351_snd {
compatible = "mediatek,mt6351-sound";
};

View file

@ -0,0 +1,42 @@
Mediatek AFE PCM controller for mt6797
Required properties:
- compatible = "mediatek,mt6797-audio";
- reg: register location and size
- interrupts: should contain AFE interrupt
- power-domains: should define the power domain
- clocks: Must contain an entry for each entry in clock-names
- clock-names: should have these clock names:
"infra_sys_audio_clk",
"infra_sys_audio_26m",
"mtkaif_26m_clk",
"top_mux_audio",
"top_mux_aud_intbus",
"top_sys_pll3_d4",
"top_sys_pll1_d4",
"top_clk26m_clk";
Example:
afe: mt6797-afe-pcm@11220000 {
compatible = "mediatek,mt6797-audio";
reg = <0 0x11220000 0 0x1000>;
interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&scpsys MT6797_POWER_DOMAIN_AUDIO>;
clocks = <&infrasys CLK_INFRA_AUDIO>,
<&infrasys CLK_INFRA_AUDIO_26M>,
<&infrasys CLK_INFRA_AUDIO_26M_PAD_TOP>,
<&topckgen CLK_TOP_MUX_AUDIO>,
<&topckgen CLK_TOP_MUX_AUD_INTBUS>,
<&topckgen CLK_TOP_SYSPLL3_D4>,
<&topckgen CLK_TOP_SYSPLL1_D4>,
<&clk26m>;
clock-names = "infra_sys_audio_clk",
"infra_sys_audio_26m",
"mtkaif_26m_clk",
"top_mux_audio",
"top_mux_aud_intbus",
"top_sys_pll3_d4",
"top_sys_pll1_d4",
"top_clk26m_clk";
};

View file

@ -0,0 +1,14 @@
MT6797 with MT6351 CODEC
Required properties:
- compatible: "mediatek,mt6797-mt6351-sound"
- mediatek,platform: the phandle of MT6797 ASoC platform
- mediatek,audio-codec: the phandles of MT6351 codec
Example:
sound {
compatible = "mediatek,mt6797-mt6351-sound";
mediatek,audio-codec = <&mt6351_snd>;
mediatek,platform = <&afe>;
};

View file

@ -0,0 +1,109 @@
* Qualcomm Technologies APQ8096 ASoC sound card driver
This binding describes the APQ8096 sound card, which uses qdsp for audio.
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be "qcom,apq8096-sndcard"
- qcom,audio-routing:
Usage: Optional
Value type: <stringlist>
Definition: A list of the connections between audio components.
Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's
source. Valid names could be power supplies, MicBias
of codec and the jacks on the board:
Valid names include:
Board Connectors:
"Headphone Left"
"Headphone Right"
"Earphone"
"Line Out1"
"Line Out2"
"Line Out3"
"Line Out4"
"Analog Mic1"
"Analog Mic2"
"Analog Mic3"
"Analog Mic4"
"Analog Mic5"
"Analog Mic6"
"Digital Mic2"
"Digital Mic3"
Audio pins and MicBias on WCD9335 Codec:
"MIC_BIAS1
"MIC_BIAS2"
"MIC_BIAS3"
"MIC_BIAS4"
"AMIC1"
"AMIC2"
"AMIC3"
"AMIC4"
"AMIC5"
"AMIC6"
"AMIC6"
"DMIC1"
"DMIC2"
"DMIC3"
= dailinks
Each subnode of sndcard represents either a dailink, and subnodes of each
dailinks would be cpu/codec/platform dais.
- link-name:
Usage: required
Value type: <string>
Definition: User friendly name for dai link
= CPU, PLATFORM, CODEC dais subnodes
- cpu:
Usage: required
Value type: <subnode>
Definition: cpu dai sub-node
- codec:
Usage: Optional
Value type: <subnode>
Definition: codec dai sub-node
- platform:
Usage: Optional
Value type: <subnode>
Definition: platform dai sub-node
- sound-dai:
Usage: required
Value type: <phandle with arguments>
Definition: dai phandle/s and port of CPU/CODEC/PLATFORM node.
Example:
audio {
compatible = "qcom,apq8096-sndcard";
qcom,model = "DB820c";
mm1-dai-link {
link-name = "MultiMedia1";
cpu {
sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
};
};
hdmi-dai-link {
link-name = "HDMI Playback";
cpu {
sound-dai = <&q6afe HDMI_RX>;
};
platform {
sound-dai = <&q6adm>;
};
codec {
sound-dai = <&hdmi 0>;
};
};
};

View file

@ -0,0 +1,33 @@
Qualcomm Audio Device Manager (Q6ADM) binding
Q6ADM is one of the APR audio service on Q6DSP.
Please refer to qcom,apr.txt for details of the coommon apr service bindings
used by the apr service device.
- but must contain the following property:
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be "qcom,q6adm-v<MAJOR-NUMBER>.<MINOR-NUMBER>".
Or "qcom,q6adm" where the version number can be queried
from DSP.
example "qcom,q6adm-v2.0"
= ADM routing
"routing" subnode of the ADM node represents adm routing specific configuration
- #sound-dai-cells
Usage: required
Value type: <u32>
Definition: Must be 0
= EXAMPLE
q6adm@8 {
compatible = "qcom,q6adm";
reg = <APR_SVC_ADM>;
q6routing: routing {
#sound-dai-cells = <0>;
};
};

View file

@ -0,0 +1,172 @@
Qualcomm Audio Front End (Q6AFE) binding
AFE is one of the APR audio service on Q6DSP
Please refer to qcom,apr.txt for details of the common apr service bindings
used by all apr services. Must contain the following properties.
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be "qcom,q6afe-v<MAJOR-NUMBER>.<MINOR-NUMBER>"
Or "qcom,q6afe" where the version number can be queried
from DSP.
example "qcom,q6afe"
= AFE DAIs (Digial Audio Interface)
"dais" subnode of the AFE node. It represents afe dais, each afe dai is a
subnode of "dais" representing board specific dai setup.
"dais" node should have following properties followed by dai children.
- #sound-dai-cells
Usage: required
Value type: <u32>
Definition: Must be 1
- #address-cells
Usage: required
Value type: <u32>
Definition: Must be 1
- #size-cells
Usage: required
Value type: <u32>
Definition: Must be 0
== AFE 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
- qcom,sd-lines
Usage: required for mi2s interface
Value type: <prop-encoded-array>
Definition: Must be list of serial data lines used by this dai.
should be one or more of the 1-4 sd lines.
- qcom,tdm-sync-mode:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Synchronization mode.
0 - Short sync bit mode
1 - Long sync mode
2 - Short sync slot mode
- qcom,tdm-sync-src:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Synchronization source.
0 - External source
1 - Internal source
- qcom,tdm-data-out:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Data out signal to drive with other masters.
0 - Disable
1 - Enable
- qcom,tdm-invert-sync:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Invert the sync.
0 - Normal
1 - Invert
- qcom,tdm-data-delay:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Number of bit clock to delay data
with respect to sync edge.
0 - 0 bit clock cycle
1 - 1 bit clock cycle
2 - 2 bit clock cycle
- qcom,tdm-data-align:
Usage: required for tdm interface
Value type: <prop-encoded-array>
Definition: Indicate how data is packed
within the slot. For example, 32 slot width in case of
sample bit width is 24.
0 - MSB
1 - LSB
= EXAMPLE
q6afe@4 {
compatible = "qcom,q6afe";
reg = <APR_SVC_AFE>;
dais {
#sound-dai-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
hdmi@1 {
reg = <1>;
};
tdm@24 {
reg = <24>;
qcom,tdm-sync-mode = <1>:
qcom,tdm-sync-src = <1>;
qcom,tdm-data-out = <0>;
qcom,tdm-invert-sync = <1>;
qcom,tdm-data-delay = <1>;
qcom,tdm-data-align = <0>;
};
tdm@25 {
reg = <25>;
qcom,tdm-sync-mode = <1>:
qcom,tdm-sync-src = <1>;
qcom,tdm-data-out = <0>;
qcom,tdm-invert-sync = <1>;
qcom,tdm-data-delay <1>:
qcom,tdm-data-align = <0>;
};
prim-mi2s-rx@16 {
reg = <16>;
qcom,sd-lines = <1 3>;
};
prim-mi2s-tx@17 {
reg = <17>;
qcom,sd-lines = <2>;
};
sec-mi2s-rx@18 {
reg = <18>;
qcom,sd-lines = <1 4>;
};
sec-mi2s-tx@19 {
reg = <19>;
qcom,sd-lines = <2>;
};
tert-mi2s-rx@20 {
reg = <20>;
qcom,sd-lines = <2 4>;
};
tert-mi2s-tx@21 {
reg = <21>;
qcom,sd-lines = <1>;
};
quat-mi2s-rx@22 {
reg = <22>;
qcom,sd-lines = <1>;
};
quat-mi2s-tx@23 {
reg = <23>;
qcom,sd-lines = <2>;
};
};
};

View file

@ -0,0 +1,33 @@
Qualcomm Audio Stream Manager (Q6ASM) binding
Q6ASM is one of the APR audio service on Q6DSP.
Please refer to qcom,apr.txt for details of the common apr service bindings
used by the apr service device.
- but must contain the following property:
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be "qcom,q6asm-v<MAJOR-NUMBER>.<MINOR-NUMBER>".
Or "qcom,q6asm" where the version number can be queried
from DSP.
example "qcom,q6asm-v2.0"
= ASM DAIs (Digial Audio Interface)
"dais" subnode of the ASM node represents dai specific configuration
- #sound-dai-cells
Usage: required
Value type: <u32>
Definition: Must be 1
= EXAMPLE
q6asm@7 {
compatible = "qcom,q6asm";
reg = <APR_SVC_ASM>;
q6asmdai: dais {
#sound-dai-cells = <1>;
};
};

View file

@ -0,0 +1,21 @@
Qualcomm ADSP Core service binding
Q6CORE is one of the APR audio service on Q6DSP.
Please refer to qcom,apr.txt for details of the common apr service bindings
used by the apr service device.
- but must contain the following property:
- compatible:
Usage: required
Value type: <stringlist>
Definition: must be "qcom,q6core-v<MAJOR-NUMBER>.<MINOR-NUMBER>".
Or "qcom,q6core" where the version number can be queried
from DSP.
example "qcom,q6core-v2.0"
= EXAMPLE
q6core@3 {
compatible = "qcom,q6core";
reg = <APR_SVC_ADSP_CORE>;
};

View file

@ -26,7 +26,7 @@ Pins on the device (for linking into audio routes) for RT274:
Example:
codec: rt274@1c {
rt274: codec@1c {
compatible = "realtek,rt274";
reg = <0x1c>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;

View file

@ -32,7 +32,7 @@ Pins on the device (for linking into audio routes) for I2C:
Example:
codec: rt5514@57 {
rt5514: codec@57 {
compatible = "realtek,rt5514";
reg = <0x57>;
};

View file

@ -26,7 +26,7 @@ Pins on the device (for linking into audio routes) for RT5616:
Example:
codec: rt5616@1b {
rt5616: codec@1b {
compatible = "realtek,rt5616";
reg = <0x1b>;
};

View file

@ -22,6 +22,41 @@ Optional properties:
- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
- realtek,dmic1-data-pin
0: dmic1 is not used
1: using IN1P pin as dmic1 data pin
2: using GPIO3 pin as dmic1 data pin
- realtek,dmic2-data-pin
0: dmic2 is not used
1: using IN1N pin as dmic2 data pin
2: using GPIO4 pin as dmic2 data pin
- realtek,jack-detect-source
u32. Valid values:
0: jack-detect is not used
1: Use GPIO1 for jack-detect
2: Use JD1_IN4P for jack-detect
3: Use JD2_IN4N for jack-detect
4: Use GPIO2 for jack-detect
5: Use GPIO3 for jack-detect
6: Use GPIO4 for jack-detect
- realtek,jack-detect-not-inverted
bool. Normal jack-detect switches give an inverted signal, set this bool
in the rare case you've a jack-detect switch which is not inverted.
- realtek,over-current-threshold-microamp
u32, micbias over-current detection threshold in µA, valid values are
600, 1500 and 2000µA.
- realtek,over-current-scale-factor
u32, micbias over-current detection scale-factor, valid values are:
0: Scale current by 0.5
1: Scale current by 0.75
2: Scale current by 1.0
3: Scale current by 1.5
Pins on the device (for linking into audio routes) for RT5639/RT5640:
* DMIC1

View file

@ -69,4 +69,4 @@ codec: rt5650@1a {
realtek,dmic-en = "true";
realtek,en-jd-func = "true";
realtek,jd-mode = <3>;
};
};

View file

@ -50,7 +50,7 @@ Pins on the device (for linking into audio routes) for RT5651:
Example:
codec: rt5651@1a {
rt5651: codec@1a {
compatible = "realtek,rt5651";
reg = <0x1a>;
realtek,dmic-en = "true";

View file

@ -47,7 +47,7 @@ Pins on the device (for linking into audio routes) for RT5663:
Example:
codec: rt5663@12 {
rt5663: codec@12 {
compatible = "realtek,rt5663";
reg = <0x12>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;

View file

@ -0,0 +1,50 @@
RT5668B audio CODEC
This device supports I2C only.
Required properties:
- compatible : "realtek,rt5668b"
- reg : The I2C address of the device.
Optional properties:
- interrupts : The CODEC's interrupt output.
- realtek,dmic1-data-pin
0: dmic1 is not used
1: using GPIO2 pin as dmic1 data pin
2: using GPIO5 pin as dmic1 data pin
- realtek,dmic1-clk-pin
0: using GPIO1 pin as dmic1 clock pin
1: using GPIO3 pin as dmic1 clock pin
- realtek,jd-src
0: No JD is used
1: using JD1 as JD source
- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
Pins on the device (for linking into audio routes) for RT5668B:
* DMIC L1
* DMIC R1
* IN1P
* HPOL
* HPOR
Example:
rt5668 {
compatible = "realtek,rt5668b";
reg = <0x1a>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(U, 6) GPIO_ACTIVE_HIGH>;
realtek,ldo1-en-gpios =
<&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>;
realtek,dmic1-data-pin = <1>;
realtek,dmic1-clk-pin = <1>;
realtek,jd-src = <1>;
};

View file

@ -39,7 +39,7 @@ VDDIO 1.8V 2.5V 3.3V
Example:
codec: sgtl5000@a {
sgtl5000: codec@a {
compatible = "fsl,sgtl5000";
reg = <0x0a>;
#sound-dai-cells = <0>;

View file

@ -86,6 +86,11 @@ Optional CPU/CODEC subnodes properties:
in dai startup() and disabled with
clk_disable_unprepare() in dai
shutdown().
If a clock is specified and a
multiplication factor is given with
mclk-fs, the clock will be set to the
calculated mclk frequency when the
stream starts.
- system-clock-direction-out : specifies clock direction as 'out' on
initialization. It is useful for some aCPUs with
fixed clocks.

View file

@ -6,6 +6,8 @@ Required properties:
- compatible: "ti,tas6424" - TAS6424
- reg: I2C slave address
- sound-dai-cells: must be equal to 0
- standby-gpios: GPIO used to shut the TAS6424 down.
- mute-gpios: GPIO used to mute all the outputs
Example:

View file

@ -8,9 +8,15 @@ Required Properties:
- reg : <0x71> for analog mic
<0x69> for digital mic
- clock-names: Must one of the following "mclk1", "xtal", "mclk2"
- clocks: phandle of the clock that provides the codec sysclk
Example:
wookie: codec@69 {
compatible = "tempo,tscs42A2";
reg = <0x69>;
clock-names = "xtal";
clocks = <&audio_xtal>;
};

View file

@ -0,0 +1,23 @@
TSCS454 Audio CODEC
Required Properties:
- compatible : "tempo,tscs454"
- reg : <0x69>
- clock-names: Must one of the following "xtal", "mclk1", "mclk2"
- clocks: phandle of the clock that provides the codec sysclk
Note: If clock is not provided then bit clock is assumed
Example:
redwood: codec@69 {
#sound-dai-cells = <1>;
compatible = "tempo,tscs454";
reg = <0x69>;
clock-names = "mclk1";
clocks = <&audio_mclk>;
};

View file

@ -12,7 +12,7 @@ Required properties:
Example:
codec: wm8510@1a {
wm8510: codec@1a {
compatible = "wlf,wm8510";
reg = <0x1a>;
};

View file

@ -10,7 +10,7 @@ Required properties:
Example:
codec: wm8523@1a {
wm8523: codec@1a {
compatible = "wlf,wm8523";
reg = <0x1a>;
};

View file

@ -10,7 +10,7 @@ Required properties:
Example:
codec: wm8524 {
wm8524: codec {
compatible = "wlf,wm8524";
wlf,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
};

View file

@ -10,7 +10,7 @@ Required properties:
Example:
codec: wm8580@1a {
wm8580: codec@1a {
compatible = "wlf,wm8580";
reg = <0x1a>;
};

View file

@ -12,7 +12,7 @@ Required properties:
Example:
codec: wm8711@1a {
wm8711: codec@1a {
compatible = "wlf,wm8711";
reg = <0x1a>;
};

View file

@ -12,7 +12,7 @@ Required properties:
Example:
codec: wm8728@1a {
wm8728: codec@1a {
compatible = "wlf,wm8728";
reg = <0x1a>;
};

View file

@ -12,7 +12,7 @@ Required properties:
Example:
codec: wm8731@1a {
wm8731: codec@1a {
compatible = "wlf,wm8731";
reg = <0x1a>;
};

View file

@ -12,7 +12,7 @@ Required properties:
Example:
codec: wm8737@1a {
wm8737: codec@1a {
compatible = "wlf,wm8737";
reg = <0x1a>;
};

View file

@ -21,7 +21,7 @@ Optional properties:
Example:
codec: wm8741@1a {
wm8741: codec@1a {
compatible = "wlf,wm8741";
reg = <0x1a>;

View file

@ -12,7 +12,7 @@ Required properties:
Example:
codec: wm8750@1a {
wm8750: codec@1a {
compatible = "wlf,wm8750";
reg = <0x1a>;
};

View file

@ -34,7 +34,7 @@ Pins on the device (for linking into audio routes):
Example:
codec: wm8753@1a {
wm8753: codec@1a {
compatible = "wlf,wm8753";
reg = <0x1a>;
};

View file

@ -10,7 +10,7 @@ Required properties:
Example:
codec: wm8770@1 {
wm8770: codec@1 {
compatible = "wlf,wm8770";
reg = <1>;
};

View file

@ -12,7 +12,7 @@ Required properties:
Example:
codec: wm8776@1a {
wm8776: codec@1a {
compatible = "wlf,wm8776";
reg = <0x1a>;
};

View file

@ -19,7 +19,7 @@ Optional properties:
Example:
codec: wm8804@1a {
wm8804: codec@1a {
compatible = "wlf,wm8804";
reg = <0x1a>;
};

View file

@ -57,7 +57,7 @@ Pins on the device (for linking into audio routes):
Example:
codec: wm8903@1a {
wm8903: codec@1a {
compatible = "wlf,wm8903";
reg = <0x1a>;
interrupts = < 347 >;

View file

@ -23,7 +23,7 @@ Optional properties:
Example:
codec: wm8960@1a {
wm8960: codec@1a {
compatible = "wlf,wm8960";
reg = <0x1a>;

View file

@ -24,7 +24,7 @@ Optional properties:
Example:
codec: wm8962@1a {
wm8962: codec@1a {
compatible = "wlf,wm8962";
reg = <0x1a>;

View file

@ -59,7 +59,7 @@ Optional properties:
Example:
codec: wm8994@1a {
wm8994: codec@1a {
compatible = "wlf,wm8994";
reg = <0x1a>;

View file

@ -179,12 +179,12 @@ i.e.
static int wm8974_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = snd_soc_read(codec, WM8974_DAC) & 0xffbf;
struct snd_soc_component *component = dai->component;
u16 mute_reg = snd_soc_component_read32(component, WM8974_DAC) & 0xffbf;
if (mute)
snd_soc_write(codec, WM8974_DAC, mute_reg | 0x40);
snd_soc_component_write(component, WM8974_DAC, mute_reg | 0x40);
else
snd_soc_write(codec, WM8974_DAC, mute_reg);
snd_soc_component_write(component, WM8974_DAC, mute_reg);
return 0;
}

View file

@ -23,30 +23,26 @@ The platform DMA driver optionally supports the following ALSA operations:-
};
The platform driver exports its DMA functionality via struct
snd_soc_platform_driver:-
snd_soc_component_driver:-
::
struct snd_soc_platform_driver {
char *name;
struct snd_soc_component_driver {
const char *name;
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);
...
int (*probe)(struct snd_soc_component *);
void (*remove)(struct snd_soc_component *);
int (*suspend)(struct snd_soc_component *);
int (*resume)(struct snd_soc_component *);
/* pcm creation and destruction */
int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *);
int (*pcm_new)(struct snd_soc_pcm_runtime *);
void (*pcm_free)(struct snd_pcm *);
/*
* For platform caused delay reporting.
* Optional.
*/
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
struct snd_soc_dai *);
/* platform stream ops */
struct snd_pcm_ops *pcm_ops;
...
const struct snd_pcm_ops *ops;
const struct snd_compr_ops *compr_ops;
...
};
Please refer to the ALSA driver documentation for details of audio DMA.

View file

@ -635,6 +635,7 @@ EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
*************************************************************************/
static struct resource ep93xx_i2s_resource[] = {
DEFINE_RES_MEM(EP93XX_I2S_PHYS_BASE, 0x100),
DEFINE_RES_IRQ(IRQ_EP93XX_SAI),
};
static struct platform_device ep93xx_i2s_device = {

View file

@ -2444,7 +2444,7 @@ static int tda1997x_pcm_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct tda1997x_state *state = snd_soc_dai_get_drvdata(dai);
struct snd_soc_codec *codec = dai->codec;
struct snd_soc_component *component = dai->component;
struct snd_pcm_runtime *rtd = substream->runtime;
int rate, err;
@ -2452,11 +2452,11 @@ static int tda1997x_pcm_startup(struct snd_pcm_substream *substream,
err = snd_pcm_hw_constraint_minmax(rtd, SNDRV_PCM_HW_PARAM_RATE,
rate, rate);
if (err < 0) {
dev_err(codec->dev, "failed to constrain samplerate to %dHz\n",
dev_err(component->dev, "failed to constrain samplerate to %dHz\n",
rate);
return err;
}
dev_info(codec->dev, "set samplerate constraint to %dHz\n", rate);
dev_info(component->dev, "set samplerate constraint to %dHz\n", rate);
return 0;
}
@ -2479,20 +2479,22 @@ static struct snd_soc_dai_driver tda1997x_audio_dai = {
.ops = &tda1997x_dai_ops,
};
static int tda1997x_codec_probe(struct snd_soc_codec *codec)
static int tda1997x_codec_probe(struct snd_soc_component *component)
{
return 0;
}
static int tda1997x_codec_remove(struct snd_soc_codec *codec)
static void tda1997x_codec_remove(struct snd_soc_component *component)
{
return 0;
}
static struct snd_soc_codec_driver tda1997x_codec_driver = {
.probe = tda1997x_codec_probe,
.remove = tda1997x_codec_remove,
.reg_word_size = sizeof(u16),
static struct snd_soc_component_driver tda1997x_codec_driver = {
.probe = tda1997x_codec_probe,
.remove = tda1997x_codec_remove,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static int tda1997x_probe(struct i2c_client *client,
@ -2737,7 +2739,7 @@ static int tda1997x_probe(struct i2c_client *client,
else
formats = SNDRV_PCM_FMTBIT_S16_LE;
tda1997x_audio_dai.capture.formats = formats;
ret = snd_soc_register_codec(&state->client->dev,
ret = devm_snd_soc_register_component(&state->client->dev,
&tda1997x_codec_driver,
&tda1997x_audio_dai, 1);
if (ret) {
@ -2782,7 +2784,6 @@ static int tda1997x_remove(struct i2c_client *client)
struct tda1997x_platform_data *pdata = &state->pdata;
if (pdata->audout_format) {
snd_soc_unregister_codec(&client->dev);
mutex_destroy(&state->audio_lock);
}

View file

@ -108,4 +108,13 @@ config QCOM_WCNSS_CTRL
Client driver for the WCNSS_CTRL SMD channel, used to download nv
firmware to a newly booted WCNSS chip.
config QCOM_APR
tristate "Qualcomm APR Bus (Asynchronous Packet Router)"
depends on ARCH_QCOM
depends on RPMSG
help
Enable APR IPC protocol support between
application processor and QDSP6. APR is
used by audio driver to configure QDSP6
ASM, ADM and AFE modules.
endmenu

View file

@ -12,3 +12,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
obj-$(CONFIG_QCOM_APR) += apr.o

378
drivers/soc/qcom/apr.c Normal file
View file

@ -0,0 +1,378 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/soc/qcom/apr.h>
#include <linux/rpmsg.h>
#include <linux/of.h>
struct apr {
struct rpmsg_endpoint *ch;
struct device *dev;
spinlock_t svcs_lock;
struct idr svcs_idr;
int dest_domain_id;
};
/**
* apr_send_pkt() - Send a apr message from apr device
*
* @adev: Pointer to previously registered apr device.
* @pkt: Pointer to apr packet to send
*
* Return: Will be an negative on packet size on success.
*/
int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt)
{
struct apr *apr = dev_get_drvdata(adev->dev.parent);
struct apr_hdr *hdr;
unsigned long flags;
int ret;
spin_lock_irqsave(&adev->lock, flags);
hdr = &pkt->hdr;
hdr->src_domain = APR_DOMAIN_APPS;
hdr->src_svc = adev->svc_id;
hdr->dest_domain = adev->domain_id;
hdr->dest_svc = adev->svc_id;
ret = rpmsg_trysend(apr->ch, pkt, hdr->pkt_size);
spin_unlock_irqrestore(&adev->lock, flags);
return ret ? ret : hdr->pkt_size;
}
EXPORT_SYMBOL_GPL(apr_send_pkt);
static void apr_dev_release(struct device *dev)
{
struct apr_device *adev = to_apr_device(dev);
kfree(adev);
}
static int apr_callback(struct rpmsg_device *rpdev, void *buf,
int len, void *priv, u32 addr)
{
struct apr *apr = dev_get_drvdata(&rpdev->dev);
uint16_t hdr_size, msg_type, ver, svc_id;
struct apr_device *svc = NULL;
struct apr_driver *adrv = NULL;
struct apr_resp_pkt resp;
struct apr_hdr *hdr;
unsigned long flags;
if (len <= APR_HDR_SIZE) {
dev_err(apr->dev, "APR: Improper apr pkt received:%p %d\n",
buf, len);
return -EINVAL;
}
hdr = buf;
ver = APR_HDR_FIELD_VER(hdr->hdr_field);
if (ver > APR_PKT_VER + 1)
return -EINVAL;
hdr_size = APR_HDR_FIELD_SIZE_BYTES(hdr->hdr_field);
if (hdr_size < APR_HDR_SIZE) {
dev_err(apr->dev, "APR: Wrong hdr size:%d\n", hdr_size);
return -EINVAL;
}
if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) {
dev_err(apr->dev, "APR: Wrong paket size\n");
return -EINVAL;
}
msg_type = APR_HDR_FIELD_MT(hdr->hdr_field);
if (msg_type >= APR_MSG_TYPE_MAX) {
dev_err(apr->dev, "APR: Wrong message type: %d\n", msg_type);
return -EINVAL;
}
if (hdr->src_domain >= APR_DOMAIN_MAX ||
hdr->dest_domain >= APR_DOMAIN_MAX ||
hdr->src_svc >= APR_SVC_MAX ||
hdr->dest_svc >= APR_SVC_MAX) {
dev_err(apr->dev, "APR: Wrong APR header\n");
return -EINVAL;
}
svc_id = hdr->dest_svc;
spin_lock_irqsave(&apr->svcs_lock, flags);
svc = idr_find(&apr->svcs_idr, svc_id);
if (svc && svc->dev.driver)
adrv = to_apr_driver(svc->dev.driver);
spin_unlock_irqrestore(&apr->svcs_lock, flags);
if (!adrv) {
dev_err(apr->dev, "APR: service is not registered\n");
return -EINVAL;
}
resp.hdr = *hdr;
resp.payload_size = hdr->pkt_size - hdr_size;
/*
* NOTE: hdr_size is not same as APR_HDR_SIZE as remote can include
* optional headers in to apr_hdr which should be ignored
*/
if (resp.payload_size > 0)
resp.payload = buf + hdr_size;
adrv->callback(svc, &resp);
return 0;
}
static int apr_device_match(struct device *dev, struct device_driver *drv)
{
struct apr_device *adev = to_apr_device(dev);
struct apr_driver *adrv = to_apr_driver(drv);
const struct apr_device_id *id = adrv->id_table;
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
if (!id)
return 0;
while (id->domain_id != 0 || id->svc_id != 0) {
if (id->domain_id == adev->domain_id &&
id->svc_id == adev->svc_id)
return 1;
id++;
}
return 0;
}
static int apr_device_probe(struct device *dev)
{
struct apr_device *adev = to_apr_device(dev);
struct apr_driver *adrv = to_apr_driver(dev->driver);
return adrv->probe(adev);
}
static int apr_device_remove(struct device *dev)
{
struct apr_device *adev = to_apr_device(dev);
struct apr_driver *adrv;
struct apr *apr = dev_get_drvdata(adev->dev.parent);
if (dev->driver) {
adrv = to_apr_driver(dev->driver);
if (adrv->remove)
adrv->remove(adev);
spin_lock(&apr->svcs_lock);
idr_remove(&apr->svcs_idr, adev->svc_id);
spin_unlock(&apr->svcs_lock);
}
return 0;
}
static int apr_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct apr_device *adev = to_apr_device(dev);
int ret;
ret = of_device_uevent_modalias(dev, env);
if (ret != -ENODEV)
return ret;
return add_uevent_var(env, "MODALIAS=apr:%s", adev->name);
}
struct bus_type aprbus = {
.name = "aprbus",
.match = apr_device_match,
.probe = apr_device_probe,
.uevent = apr_uevent,
.remove = apr_device_remove,
};
EXPORT_SYMBOL_GPL(aprbus);
static int apr_add_device(struct device *dev, struct device_node *np,
const struct apr_device_id *id)
{
struct apr *apr = dev_get_drvdata(dev);
struct apr_device *adev = NULL;
int ret;
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
if (!adev)
return -ENOMEM;
spin_lock_init(&adev->lock);
adev->svc_id = id->svc_id;
adev->domain_id = id->domain_id;
adev->version = id->svc_version;
if (np)
strncpy(adev->name, np->name, APR_NAME_SIZE);
else
strncpy(adev->name, id->name, APR_NAME_SIZE);
dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name,
id->domain_id, id->svc_id);
adev->dev.bus = &aprbus;
adev->dev.parent = dev;
adev->dev.of_node = np;
adev->dev.release = apr_dev_release;
adev->dev.driver = NULL;
spin_lock(&apr->svcs_lock);
idr_alloc(&apr->svcs_idr, adev, id->svc_id,
id->svc_id + 1, GFP_ATOMIC);
spin_unlock(&apr->svcs_lock);
dev_info(dev, "Adding APR dev: %s\n", dev_name(&adev->dev));
ret = device_register(&adev->dev);
if (ret) {
dev_err(dev, "device_register failed: %d\n", ret);
put_device(&adev->dev);
}
return ret;
}
static void of_register_apr_devices(struct device *dev)
{
struct apr *apr = dev_get_drvdata(dev);
struct device_node *node;
for_each_child_of_node(dev->of_node, node) {
struct apr_device_id id = { {0} };
if (of_property_read_u32(node, "reg", &id.svc_id))
continue;
id.domain_id = apr->dest_domain_id;
if (apr_add_device(dev, node, &id))
dev_err(dev, "Failed to add apr %d svc\n", id.svc_id);
}
}
static int apr_probe(struct rpmsg_device *rpdev)
{
struct device *dev = &rpdev->dev;
struct apr *apr;
int ret;
apr = devm_kzalloc(dev, sizeof(*apr), GFP_KERNEL);
if (!apr)
return -ENOMEM;
ret = of_property_read_u32(dev->of_node, "reg", &apr->dest_domain_id);
if (ret) {
dev_err(dev, "APR Domain ID not specified in DT\n");
return ret;
}
dev_set_drvdata(dev, apr);
apr->ch = rpdev->ept;
apr->dev = dev;
spin_lock_init(&apr->svcs_lock);
idr_init(&apr->svcs_idr);
of_register_apr_devices(dev);
return 0;
}
static int apr_remove_device(struct device *dev, void *null)
{
struct apr_device *adev = to_apr_device(dev);
device_unregister(&adev->dev);
return 0;
}
static void apr_remove(struct rpmsg_device *rpdev)
{
device_for_each_child(&rpdev->dev, NULL, apr_remove_device);
}
/*
* __apr_driver_register() - Client driver registration with aprbus
*
* @drv:Client driver to be associated with client-device.
* @owner: owning module/driver
*
* This API will register the client driver with the aprbus
* It is called from the driver's module-init function.
*/
int __apr_driver_register(struct apr_driver *drv, struct module *owner)
{
drv->driver.bus = &aprbus;
drv->driver.owner = owner;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(__apr_driver_register);
/*
* apr_driver_unregister() - Undo effect of apr_driver_register
*
* @drv: Client driver to be unregistered
*/
void apr_driver_unregister(struct apr_driver *drv)
{
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(apr_driver_unregister);
static const struct of_device_id apr_of_match[] = {
{ .compatible = "qcom,apr"},
{ .compatible = "qcom,apr-v2"},
{}
};
MODULE_DEVICE_TABLE(of, apr_of_match);
static struct rpmsg_driver apr_driver = {
.probe = apr_probe,
.remove = apr_remove,
.callback = apr_callback,
.drv = {
.name = "qcom,apr",
.of_match_table = apr_of_match,
},
};
static int __init apr_init(void)
{
int ret;
ret = bus_register(&aprbus);
if (!ret)
ret = register_rpmsg_driver(&apr_driver);
else
bus_unregister(&aprbus);
return ret;
}
static void __exit apr_exit(void)
{
bus_unregister(&aprbus);
unregister_rpmsg_driver(&apr_driver);
}
subsys_initcall(apr_init);
module_exit(apr_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Qualcomm APR Bus");

View file

@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DT_BINDINGS_QCOM_APR_H
#define __DT_BINDINGS_QCOM_APR_H
/* Domain IDs */
#define APR_DOMAIN_SIM 0x1
#define APR_DOMAIN_PC 0x2
#define APR_DOMAIN_MODEM 0x3
#define APR_DOMAIN_ADSP 0x4
#define APR_DOMAIN_APPS 0x5
#define APR_DOMAIN_MAX 0x6
/* ADSP service IDs */
#define APR_SVC_ADSP_CORE 0x3
#define APR_SVC_AFE 0x4
#define APR_SVC_VSM 0x5
#define APR_SVC_VPM 0x6
#define APR_SVC_ASM 0x7
#define APR_SVC_ADM 0x8
#define APR_SVC_ADSP_MVM 0x09
#define APR_SVC_ADSP_CVS 0x0A
#define APR_SVC_ADSP_CVP 0x0B
#define APR_SVC_USM 0x0C
#define APR_SVC_LSM 0x0D
#define APR_SVC_VIDC 0x16
#define APR_SVC_MAX 0x17
#endif /* __DT_BINDINGS_QCOM_APR_H */

View file

@ -25,6 +25,13 @@
#define MX51_AUDMUX_PORT6 5
#define MX51_AUDMUX_PORT7 6
/*
* TFCSEL/RFCSEL (i.MX27) or TFSEL/TCSEL/RFSEL/RCSEL (i.MX31/51/53/6Q)
* can be sourced from Rx/Tx.
*/
#define IMX_AUDMUX_RXFS 0x8
#define IMX_AUDMUX_RXCLK 0x8
/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */
#define IMX_AUDMUX_V1_PCR_INMMASK(x) ((x) & 0xff)
#define IMX_AUDMUX_V1_PCR_INMEN (1 << 8)

View file

@ -0,0 +1,111 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DT_BINDINGS_Q6_AFE_H__
#define __DT_BINDINGS_Q6_AFE_H__
/* Audio Front End (AFE) virtual ports IDs */
#define HDMI_RX 1
#define SLIMBUS_0_RX 2
#define SLIMBUS_0_TX 3
#define SLIMBUS_1_RX 4
#define SLIMBUS_1_TX 5
#define SLIMBUS_2_RX 6
#define SLIMBUS_2_TX 7
#define SLIMBUS_3_RX 8
#define SLIMBUS_3_TX 9
#define SLIMBUS_4_RX 10
#define SLIMBUS_4_TX 11
#define SLIMBUS_5_RX 12
#define SLIMBUS_5_TX 13
#define SLIMBUS_6_RX 14
#define SLIMBUS_6_TX 15
#define PRIMARY_MI2S_RX 16
#define PRIMARY_MI2S_TX 17
#define SECONDARY_MI2S_RX 18
#define SECONDARY_MI2S_TX 19
#define TERTIARY_MI2S_RX 20
#define TERTIARY_MI2S_TX 21
#define QUATERNARY_MI2S_RX 22
#define QUATERNARY_MI2S_TX 23
#define PRIMARY_TDM_RX_0 24
#define PRIMARY_TDM_TX_0 25
#define PRIMARY_TDM_RX_1 26
#define PRIMARY_TDM_TX_1 27
#define PRIMARY_TDM_RX_2 28
#define PRIMARY_TDM_TX_2 29
#define PRIMARY_TDM_RX_3 30
#define PRIMARY_TDM_TX_3 31
#define PRIMARY_TDM_RX_4 32
#define PRIMARY_TDM_TX_4 33
#define PRIMARY_TDM_RX_5 34
#define PRIMARY_TDM_TX_5 35
#define PRIMARY_TDM_RX_6 36
#define PRIMARY_TDM_TX_6 37
#define PRIMARY_TDM_RX_7 38
#define PRIMARY_TDM_TX_7 39
#define SECONDARY_TDM_RX_0 40
#define SECONDARY_TDM_TX_0 41
#define SECONDARY_TDM_RX_1 42
#define SECONDARY_TDM_TX_1 43
#define SECONDARY_TDM_RX_2 44
#define SECONDARY_TDM_TX_2 45
#define SECONDARY_TDM_RX_3 46
#define SECONDARY_TDM_TX_3 47
#define SECONDARY_TDM_RX_4 48
#define SECONDARY_TDM_TX_4 49
#define SECONDARY_TDM_RX_5 50
#define SECONDARY_TDM_TX_5 51
#define SECONDARY_TDM_RX_6 52
#define SECONDARY_TDM_TX_6 53
#define SECONDARY_TDM_RX_7 54
#define SECONDARY_TDM_TX_7 55
#define TERTIARY_TDM_RX_0 56
#define TERTIARY_TDM_TX_0 57
#define TERTIARY_TDM_RX_1 58
#define TERTIARY_TDM_TX_1 59
#define TERTIARY_TDM_RX_2 60
#define TERTIARY_TDM_TX_2 61
#define TERTIARY_TDM_RX_3 62
#define TERTIARY_TDM_TX_3 63
#define TERTIARY_TDM_RX_4 64
#define TERTIARY_TDM_TX_4 65
#define TERTIARY_TDM_RX_5 66
#define TERTIARY_TDM_TX_5 67
#define TERTIARY_TDM_RX_6 68
#define TERTIARY_TDM_TX_6 69
#define TERTIARY_TDM_RX_7 70
#define TERTIARY_TDM_TX_7 71
#define QUATERNARY_TDM_RX_0 72
#define QUATERNARY_TDM_TX_0 73
#define QUATERNARY_TDM_RX_1 74
#define QUATERNARY_TDM_TX_1 75
#define QUATERNARY_TDM_RX_2 76
#define QUATERNARY_TDM_TX_2 77
#define QUATERNARY_TDM_RX_3 78
#define QUATERNARY_TDM_TX_3 79
#define QUATERNARY_TDM_RX_4 80
#define QUATERNARY_TDM_TX_4 81
#define QUATERNARY_TDM_RX_5 82
#define QUATERNARY_TDM_TX_5 83
#define QUATERNARY_TDM_RX_6 84
#define QUATERNARY_TDM_TX_6 85
#define QUATERNARY_TDM_RX_7 86
#define QUATERNARY_TDM_TX_7 87
#define QUINARY_TDM_RX_0 88
#define QUINARY_TDM_TX_0 89
#define QUINARY_TDM_RX_1 90
#define QUINARY_TDM_TX_1 91
#define QUINARY_TDM_RX_2 92
#define QUINARY_TDM_TX_2 93
#define QUINARY_TDM_RX_3 94
#define QUINARY_TDM_TX_3 95
#define QUINARY_TDM_RX_4 96
#define QUINARY_TDM_TX_4 97
#define QUINARY_TDM_RX_5 98
#define QUINARY_TDM_TX_5 99
#define QUINARY_TDM_RX_6 100
#define QUINARY_TDM_TX_6 101
#define QUINARY_TDM_RX_7 102
#define QUINARY_TDM_TX_7 103
#endif /* __DT_BINDINGS_Q6_AFE_H__ */

View file

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DT_BINDINGS_Q6_ASM_H__
#define __DT_BINDINGS_Q6_ASM_H__
#define MSM_FRONTEND_DAI_MULTIMEDIA1 0
#define MSM_FRONTEND_DAI_MULTIMEDIA2 1
#define MSM_FRONTEND_DAI_MULTIMEDIA3 2
#define MSM_FRONTEND_DAI_MULTIMEDIA4 3
#define MSM_FRONTEND_DAI_MULTIMEDIA5 4
#define MSM_FRONTEND_DAI_MULTIMEDIA6 5
#define MSM_FRONTEND_DAI_MULTIMEDIA7 6
#define MSM_FRONTEND_DAI_MULTIMEDIA8 7
#define MSM_FRONTEND_DAI_MULTIMEDIA9 8
#define MSM_FRONTEND_DAI_MULTIMEDIA10 9
#define MSM_FRONTEND_DAI_MULTIMEDIA11 10
#define MSM_FRONTEND_DAI_MULTIMEDIA12 11
#define MSM_FRONTEND_DAI_MULTIMEDIA13 12
#define MSM_FRONTEND_DAI_MULTIMEDIA14 13
#define MSM_FRONTEND_DAI_MULTIMEDIA15 14
#define MSM_FRONTEND_DAI_MULTIMEDIA16 15
#endif /* __DT_BINDINGS_Q6_ASM_H__ */

View file

@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DT_RT5640_H
#define __DT_RT5640_H
#define RT5640_DMIC1_DATA_PIN_NONE 0
#define RT5640_DMIC1_DATA_PIN_IN1P 1
#define RT5640_DMIC1_DATA_PIN_GPIO3 2
#define RT5640_DMIC2_DATA_PIN_NONE 0
#define RT5640_DMIC2_DATA_PIN_IN1N 1
#define RT5640_DMIC2_DATA_PIN_GPIO4 2
#define RT5640_JD_SRC_GPIO1 1
#define RT5640_JD_SRC_JD1_IN4P 2
#define RT5640_JD_SRC_JD2_IN4N 3
#define RT5640_JD_SRC_GPIO2 4
#define RT5640_JD_SRC_GPIO3 5
#define RT5640_JD_SRC_GPIO4 6
#define RT5640_OVCD_SF_0P5 0
#define RT5640_OVCD_SF_0P75 1
#define RT5640_OVCD_SF_1P0 2
#define RT5640_OVCD_SF_1P5 3
#endif /* __DT_RT5640_H */

View file

@ -617,11 +617,8 @@ struct wm8350_audio_platform_data {
u32 codec_current_charge:2; /* codec current @ vmid charge */
};
struct snd_soc_codec;
struct wm8350_codec {
struct platform_device *pdev;
struct snd_soc_codec *codec;
struct wm8350_audio_platform_data *platform_data;
};

View file

@ -471,6 +471,17 @@ struct slim_device_id {
kernel_ulong_t driver_data;
};
#define APR_NAME_SIZE 32
#define APR_MODULE_PREFIX "apr:"
struct apr_device_id {
char name[APR_NAME_SIZE];
__u32 domain_id;
__u32 svc_id;
__u32 svc_version;
kernel_ulong_t driver_data; /* Data private to the driver */
};
#define SPMI_NAME_SIZE 32
#define SPMI_MODULE_PREFIX "spmi:"

View file

@ -0,0 +1,128 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __QCOM_APR_H_
#define __QCOM_APR_H_
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <dt-bindings/soc/qcom,apr.h>
extern struct bus_type aprbus;
#define APR_HDR_LEN(hdr_len) ((hdr_len)/4)
/*
* HEADER field
* version:0:3
* header_size : 4:7
* message_type : 8:9
* reserved: 10:15
*/
#define APR_HDR_FIELD(msg_type, hdr_len, ver)\
(((msg_type & 0x3) << 8) | ((hdr_len & 0xF) << 4) | (ver & 0xF))
#define APR_HDR_SIZE sizeof(struct apr_hdr)
#define APR_SEQ_CMD_HDR_FIELD APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
APR_HDR_LEN(APR_HDR_SIZE), \
APR_PKT_VER)
/* Version */
#define APR_PKT_VER 0x0
/* Command and Response Types */
#define APR_MSG_TYPE_EVENT 0x0
#define APR_MSG_TYPE_CMD_RSP 0x1
#define APR_MSG_TYPE_SEQ_CMD 0x2
#define APR_MSG_TYPE_NSEQ_CMD 0x3
#define APR_MSG_TYPE_MAX 0x04
/* APR Basic Response Message */
#define APR_BASIC_RSP_RESULT 0x000110E8
#define APR_RSP_ACCEPTED 0x000100BE
struct aprv2_ibasic_rsp_result_t {
uint32_t opcode;
uint32_t status;
};
/* hdr field Ver [0:3], Size [4:7], Message type [8:10] */
#define APR_HDR_FIELD_VER(h) (h & 0x000F)
#define APR_HDR_FIELD_SIZE(h) ((h & 0x00F0) >> 4)
#define APR_HDR_FIELD_SIZE_BYTES(h) (((h & 0x00F0) >> 4) * 4)
#define APR_HDR_FIELD_MT(h) ((h & 0x0300) >> 8)
struct apr_hdr {
uint16_t hdr_field;
uint16_t pkt_size;
uint8_t src_svc;
uint8_t src_domain;
uint16_t src_port;
uint8_t dest_svc;
uint8_t dest_domain;
uint16_t dest_port;
uint32_t token;
uint32_t opcode;
} __packed;
struct apr_pkt {
struct apr_hdr hdr;
uint8_t payload[];
};
struct apr_resp_pkt {
struct apr_hdr hdr;
void *payload;
int payload_size;
};
/* Bits 0 to 15 -- Minor version, Bits 16 to 31 -- Major version */
#define APR_SVC_MAJOR_VERSION(v) ((v >> 16) & 0xFF)
#define APR_SVC_MINOR_VERSION(v) (v & 0xFF)
struct apr_device {
struct device dev;
uint16_t svc_id;
uint16_t domain_id;
uint32_t version;
char name[APR_NAME_SIZE];
spinlock_t lock;
struct list_head node;
};
#define to_apr_device(d) container_of(d, struct apr_device, dev)
struct apr_driver {
int (*probe)(struct apr_device *sl);
int (*remove)(struct apr_device *sl);
int (*callback)(struct apr_device *a,
struct apr_resp_pkt *d);
struct device_driver driver;
const struct apr_device_id *id_table;
};
#define to_apr_driver(d) container_of(d, struct apr_driver, driver)
/*
* use a macro to avoid include chaining to get THIS_MODULE
*/
#define apr_driver_register(drv) __apr_driver_register(drv, THIS_MODULE)
int __apr_driver_register(struct apr_driver *drv, struct module *owner);
void apr_driver_unregister(struct apr_driver *drv);
/**
* module_apr_driver() - Helper macro for registering a aprbus driver
* @__aprbus_driver: aprbus_driver struct
*
* Helper macro for aprbus drivers which do not do anything special in
* module init/exit. This eliminates a lot of boilerplate. Each module
* may only use this macro once, and calling it replaces module_init()
* and module_exit()
*/
#define module_apr_driver(__apr_driver) \
module_driver(__apr_driver, apr_driver_register, \
apr_driver_unregister)
int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt);
#endif /* __QCOM_APR_H_ */

View file

@ -1,30 +0,0 @@
/*
* omap-pcm.h - OMAP PCM driver
*
* Copyright (C) 2014 Texas Instruments, Inc.
*
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef __OMAP_PCM_H__
#define __OMAP_PCM_H__
#if IS_ENABLED(CONFIG_SND_OMAP_SOC)
int omap_pcm_platform_register(struct device *dev);
#else
static inline int omap_pcm_platform_register(struct device *dev)
{
return 0;
}
#endif /* CONFIG_SND_OMAP_SOC */
#endif /* __OMAP_PCM_H__ */

View file

@ -1,27 +0,0 @@
/*
* linux/sound/rt5640.h -- Platform data for RT5640
*
* Copyright 2011 Realtek Microelectronics
*
* 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 __LINUX_SND_RT5640_H
#define __LINUX_SND_RT5640_H
struct rt5640_platform_data {
/* IN1 & IN2 & IN3 can optionally be differential */
bool in1_diff;
bool in2_diff;
bool in3_diff;
bool dmic_en;
bool dmic1_data_pin; /* 0 = IN1P; 1 = GPIO3 */
bool dmic2_data_pin; /* 0 = IN1N; 1 = GPIO4 */
int ldo1_en; /* GPIO for LDO1_EN */
};
#endif

40
include/sound/rt5668.h Normal file
View file

@ -0,0 +1,40 @@
/*
* linux/sound/rt5668.h -- Platform data for RT5668
*
* Copyright 2018 Realtek Microelectronics
*
* 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 __LINUX_SND_RT5668_H
#define __LINUX_SND_RT5668_H
enum rt5668_dmic1_data_pin {
RT5668_DMIC1_NULL,
RT5668_DMIC1_DATA_GPIO2,
RT5668_DMIC1_DATA_GPIO5,
};
enum rt5668_dmic1_clk_pin {
RT5668_DMIC1_CLK_GPIO1,
RT5668_DMIC1_CLK_GPIO3,
};
enum rt5668_jd_src {
RT5668_JD_NULL,
RT5668_JD1,
};
struct rt5668_platform_data {
int ldo1_en; /* GPIO for LDO1_EN */
enum rt5668_dmic1_data_pin dmic1_data_pin;
enum rt5668_dmic1_clk_pin dmic1_clk_pin;
enum rt5668_jd_src jd_src;
};
#endif

View file

@ -313,7 +313,6 @@ struct snd_soc_dai {
unsigned int sample_bits;
/* parent platform/codec */
struct snd_soc_codec *codec;
struct snd_soc_component *component;
/* CODEC TDM slot masks and params (for fixup) */

View file

@ -401,11 +401,7 @@ struct snd_soc_ops;
struct snd_soc_pcm_runtime;
struct snd_soc_dai;
struct snd_soc_dai_driver;
struct snd_soc_platform;
struct snd_soc_dai_link;
struct snd_soc_platform_driver;
struct snd_soc_codec;
struct snd_soc_codec_driver;
struct snd_soc_component;
struct snd_soc_component_driver;
struct soc_enum;
@ -430,13 +426,6 @@ enum snd_soc_card_subclass {
SND_SOC_CARD_CLASS_RUNTIME = 1,
};
int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir);
int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out);
int snd_soc_codec_set_jack(struct snd_soc_codec *codec,
struct snd_soc_jack *jack, void *data);
int snd_soc_register_card(struct snd_soc_card *card);
int snd_soc_unregister_card(struct snd_soc_card *card);
int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card);
@ -455,19 +444,6 @@ static inline int snd_soc_resume(struct device *dev)
}
#endif
int snd_soc_poweroff(struct device *dev);
int snd_soc_register_platform(struct device *dev,
const struct snd_soc_platform_driver *platform_drv);
int devm_snd_soc_register_platform(struct device *dev,
const struct snd_soc_platform_driver *platform_drv);
void snd_soc_unregister_platform(struct device *dev);
int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
const struct snd_soc_platform_driver *platform_drv);
void snd_soc_remove_platform(struct snd_soc_platform *platform);
struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev);
int snd_soc_register_codec(struct device *dev,
const struct snd_soc_codec_driver *codec_drv,
struct snd_soc_dai_driver *dai_drv, int num_dai);
void snd_soc_unregister_codec(struct device *dev);
int snd_soc_add_component(struct device *dev,
struct snd_soc_component *component,
const struct snd_soc_component_driver *component_driver,
@ -482,16 +458,15 @@ int devm_snd_soc_register_component(struct device *dev,
void snd_soc_unregister_component(struct device *dev);
struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
const char *driver_name);
int snd_soc_cache_init(struct snd_soc_codec *codec);
int snd_soc_cache_exit(struct snd_soc_codec *codec);
int snd_soc_platform_read(struct snd_soc_platform *platform,
unsigned int reg);
int snd_soc_platform_write(struct snd_soc_platform *platform,
unsigned int reg, unsigned int val);
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
#ifdef CONFIG_SND_SOC_COMPRESS
int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
#else
static inline int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
{
return 0;
}
#endif
void snd_soc_disconnect_sync(struct device *dev);
@ -576,23 +551,7 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
}
#endif
/* codec register bit access */
int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned int reg,
unsigned int mask, unsigned int value);
int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
unsigned int reg, unsigned int mask,
unsigned int value);
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
unsigned int mask, unsigned int value);
#ifdef CONFIG_SND_SOC_AC97_BUS
#define snd_soc_alloc_ac97_codec(codec) \
snd_soc_alloc_ac97_component(&codec->component)
#define snd_soc_new_ac97_codec(codec, id, id_mask) \
snd_soc_new_ac97_component(&codec->component, id, id_mask)
#define snd_soc_free_ac97_codec(ac97) \
snd_soc_free_ac97_component(ac97)
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);
@ -626,10 +585,6 @@ struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
const char *name);
int snd_soc_add_component_controls(struct snd_soc_component *component,
const struct snd_kcontrol_new *controls, unsigned int num_controls);
int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
const struct snd_kcontrol_new *controls, unsigned int num_controls);
int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
const struct snd_kcontrol_new *controls, unsigned int num_controls);
int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
const struct snd_kcontrol_new *controls, int num_controls);
int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
@ -862,8 +817,6 @@ struct snd_soc_component {
unsigned int active;
unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
unsigned int registered_as_component:1;
unsigned int suspended:1; /* is in suspend PM state */
struct list_head list;
@ -875,9 +828,6 @@ struct snd_soc_component {
struct list_head dai_list;
int num_dai;
int (*read)(struct snd_soc_component *, unsigned int, unsigned int *);
int (*write)(struct snd_soc_component *, unsigned int, unsigned int);
struct regmap *regmap;
int val_bytes;
@ -886,10 +836,6 @@ struct snd_soc_component {
/* attached dynamic objects */
struct list_head dobj_list;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
#endif
/*
* DO NOT use any of the fields below in drivers, they are temporary and
* are going to be removed again soon. If you use them in driver code the
@ -899,29 +845,11 @@ struct snd_soc_component {
/* Don't use these, use snd_soc_component_get_dapm() */
struct snd_soc_dapm_context dapm;
struct snd_soc_codec *codec;
int (*probe)(struct snd_soc_component *);
void (*remove)(struct snd_soc_component *);
int (*suspend)(struct snd_soc_component *);
int (*resume)(struct snd_soc_component *);
int (*pcm_new)(struct snd_soc_component *, struct snd_soc_pcm_runtime *);
void (*pcm_free)(struct snd_soc_component *, struct snd_pcm *);
int (*set_sysclk)(struct snd_soc_component *component,
int clk_id, int source, unsigned int freq, int dir);
int (*set_pll)(struct snd_soc_component *component, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out);
int (*set_jack)(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *data);
int (*set_bias_level)(struct snd_soc_component *component,
enum snd_soc_bias_level level);
/* machine specific init */
int (*init)(struct snd_soc_component *component);
#ifdef CONFIG_DEBUG_FS
void (*init_debugfs)(struct snd_soc_component *component);
struct dentry *debugfs_root;
const char *debugfs_prefix;
#endif
};
@ -938,97 +866,12 @@ snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd,
#define for_each_rtdcom_safe(rtd, rtdcom1, rtdcom2) \
list_for_each_entry_safe(rtdcom1, rtdcom2, &(rtd)->component_list, list)
/* SoC Audio Codec device */
struct snd_soc_codec {
struct device *dev;
const struct snd_soc_codec_driver *driver;
struct list_head list;
/* runtime */
unsigned int cache_init:1; /* codec cache has been initialized */
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
hw_write_t hw_write;
void *reg_cache;
/* component */
struct snd_soc_component component;
};
/* codec driver */
struct snd_soc_codec_driver {
/* driver ops */
int (*probe)(struct snd_soc_codec *);
int (*remove)(struct snd_soc_codec *);
int (*suspend)(struct snd_soc_codec *);
int (*resume)(struct snd_soc_codec *);
struct snd_soc_component_driver component_driver;
/* codec wide operations */
int (*set_sysclk)(struct snd_soc_codec *codec,
int clk_id, int source, unsigned int freq, int dir);
int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out);
int (*set_jack)(struct snd_soc_codec *codec,
struct snd_soc_jack *jack, void *data);
/* codec IO */
struct regmap *(*get_regmap)(struct device *);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
unsigned int reg_cache_size;
short reg_cache_step;
short reg_word_size;
const void *reg_cache_default;
/* codec bias level */
int (*set_bias_level)(struct snd_soc_codec *,
enum snd_soc_bias_level level);
bool idle_bias_off;
bool suspend_bias_off;
void (*seq_notifier)(struct snd_soc_dapm_context *,
enum snd_soc_dapm_type, int);
bool ignore_pmdown_time; /* Doesn't benefit from pmdown delay */
};
/* SoC platform interface */
struct snd_soc_platform_driver {
int (*probe)(struct snd_soc_platform *);
int (*remove)(struct snd_soc_platform *);
struct snd_soc_component_driver component_driver;
/* pcm creation and destruction */
int (*pcm_new)(struct snd_soc_pcm_runtime *);
void (*pcm_free)(struct snd_pcm *);
/* platform stream pcm ops */
const struct snd_pcm_ops *ops;
/* platform stream compress ops */
const struct snd_compr_ops *compr_ops;
};
struct snd_soc_dai_link_component {
const char *name;
struct device_node *of_node;
const char *dai_name;
};
struct snd_soc_platform {
struct device *dev;
const struct snd_soc_platform_driver *driver;
struct list_head list;
struct snd_soc_component component;
};
struct snd_soc_dai_link {
/* config - must be set by machine driver */
const char *name; /* Codec name */
@ -1276,8 +1119,6 @@ struct snd_soc_pcm_runtime {
/* runtime devices */
struct snd_pcm *pcm;
struct snd_compr *compr;
struct snd_soc_codec *codec;
struct snd_soc_platform *platform; /* will be removed */
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai;
@ -1345,32 +1186,6 @@ struct soc_enum {
struct snd_soc_dobj dobj;
};
/**
* snd_soc_component_to_codec() - Casts a component to the CODEC it is embedded in
* @component: The component to cast to a CODEC
*
* This function must only be used on components that are known to be CODECs.
* Otherwise the behavior is undefined.
*/
static inline struct snd_soc_codec *snd_soc_component_to_codec(
struct snd_soc_component *component)
{
return container_of(component, struct snd_soc_codec, component);
}
/**
* snd_soc_component_to_platform() - Casts a component to the platform it is embedded in
* @component: The component to cast to a platform
*
* This function must only be used on components that are known to be platforms.
* Otherwise the behavior is undefined.
*/
static inline struct snd_soc_platform *snd_soc_component_to_platform(
struct snd_soc_component *component)
{
return container_of(component, struct snd_soc_platform, component);
}
/**
* snd_soc_dapm_to_component() - Casts a DAPM context to the component it is
* embedded in
@ -1386,33 +1201,6 @@ static inline struct snd_soc_component *snd_soc_dapm_to_component(
return container_of(dapm, struct snd_soc_component, dapm);
}
/**
* snd_soc_dapm_to_codec() - Casts a DAPM context to the CODEC it is embedded in
* @dapm: The DAPM context to cast to the CODEC
*
* This function must only be used on DAPM contexts that are known to be part of
* a CODEC (e.g. in a CODEC driver). Otherwise the behavior is undefined.
*/
static inline struct snd_soc_codec *snd_soc_dapm_to_codec(
struct snd_soc_dapm_context *dapm)
{
return snd_soc_component_to_codec(snd_soc_dapm_to_component(dapm));
}
/**
* snd_soc_dapm_to_platform() - Casts a DAPM context to the platform it is
* embedded in
* @dapm: The DAPM context to cast to the platform.
*
* This function must only be used on DAPM contexts that are known to be part of
* a platform (e.g. in a platform driver). Otherwise the behavior is undefined.
*/
static inline struct snd_soc_platform *snd_soc_dapm_to_platform(
struct snd_soc_dapm_context *dapm)
{
return snd_soc_component_to_platform(snd_soc_dapm_to_component(dapm));
}
/**
* snd_soc_component_get_dapm() - Returns the DAPM context associated with a
* component
@ -1424,31 +1212,6 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
return &component->dapm;
}
/**
* snd_soc_codec_get_dapm() - Returns the DAPM context for the CODEC
* @codec: The CODEC for which to get the DAPM context
*
* Note: Use this function instead of directly accessing the CODEC's dapm field
*/
static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm(
struct snd_soc_codec *codec)
{
return snd_soc_component_get_dapm(&codec->component);
}
/**
* snd_soc_dapm_init_bias_level() - Initialize CODEC DAPM bias level
* @codec: The CODEC for which to initialize the DAPM bias level
* @level: The DAPM level to initialize to
*
* Initializes the CODEC DAPM bias level. See snd_soc_dapm_init_bias_level().
*/
static inline void snd_soc_codec_init_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
snd_soc_dapm_init_bias_level(snd_soc_codec_get_dapm(codec), level);
}
/**
* snd_soc_component_init_bias_level() - Initialize COMPONENT DAPM bias level
* @component: The COMPONENT for which to initialize the DAPM bias level
@ -1464,18 +1227,6 @@ snd_soc_component_init_bias_level(struct snd_soc_component *component,
snd_soc_component_get_dapm(component), level);
}
/**
* snd_soc_dapm_get_bias_level() - Get current CODEC DAPM bias level
* @codec: The CODEC for which to get the DAPM bias level
*
* Returns: The current DAPM bias level of the CODEC.
*/
static inline enum snd_soc_bias_level snd_soc_codec_get_bias_level(
struct snd_soc_codec *codec)
{
return snd_soc_dapm_get_bias_level(snd_soc_codec_get_dapm(codec));
}
/**
* snd_soc_component_get_bias_level() - Get current COMPONENT DAPM bias level
* @component: The COMPONENT for which to get the DAPM bias level
@ -1489,21 +1240,6 @@ snd_soc_component_get_bias_level(struct snd_soc_component *component)
snd_soc_component_get_dapm(component));
}
/**
* snd_soc_codec_force_bias_level() - Set the CODEC DAPM bias level
* @codec: The CODEC for which to set the level
* @level: The level to set to
*
* Forces the CODEC bias level to a specific state. See
* snd_soc_dapm_force_bias_level().
*/
static inline int snd_soc_codec_force_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
return snd_soc_dapm_force_bias_level(snd_soc_codec_get_dapm(codec),
level);
}
/**
* snd_soc_component_force_bias_level() - Set the COMPONENT DAPM bias level
* @component: The COMPONENT for which to set the level
@ -1521,19 +1257,6 @@ snd_soc_component_force_bias_level(struct snd_soc_component *component,
level);
}
/**
* snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
* @kcontrol: The kcontrol
*
* This function must only be used on DAPM contexts that are known to be part of
* a CODEC (e.g. in a CODEC driver). Otherwise the behavior is undefined.
*/
static inline struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(
struct snd_kcontrol *kcontrol)
{
return snd_soc_dapm_to_codec(snd_soc_dapm_kcontrol_dapm(kcontrol));
}
/**
* snd_soc_dapm_kcontrol_component() - Returns the component associated to a kcontrol
* @kcontrol: The kcontrol
@ -1547,22 +1270,6 @@ static inline struct snd_soc_component *snd_soc_dapm_kcontrol_component(
return snd_soc_dapm_to_component(snd_soc_dapm_kcontrol_dapm(kcontrol));
}
/* codec IO */
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val);
/**
* snd_soc_cache_sync() - Sync the register cache with the hardware
* @codec: CODEC to sync
*
* Note: This function will call regcache_sync()
*/
static inline int snd_soc_cache_sync(struct snd_soc_codec *codec)
{
return regcache_sync(codec->component.regmap);
}
/**
* snd_soc_component_cache_sync() - Sync the register cache with the hardware
* @component: COMPONENT to sync
@ -1605,37 +1312,6 @@ void snd_soc_component_init_regmap(struct snd_soc_component *component,
struct regmap *regmap);
void snd_soc_component_exit_regmap(struct snd_soc_component *component);
/**
* snd_soc_codec_init_regmap() - Initialize regmap instance for the CODEC
* @codec: The CODEC for which to initialize the regmap instance
* @regmap: The regmap instance that should be used by the CODEC
*
* This function allows deferred assignment of the regmap instance that is
* associated with the CODEC. Only use this if the regmap instance is not yet
* ready when the CODEC is registered. The function must also be called before
* the first IO attempt of the CODEC.
*/
static inline void snd_soc_codec_init_regmap(struct snd_soc_codec *codec,
struct regmap *regmap)
{
snd_soc_component_init_regmap(&codec->component, regmap);
}
/**
* snd_soc_codec_exit_regmap() - De-initialize regmap instance for the CODEC
* @codec: The CODEC for which to de-initialize the regmap instance
*
* Calls regmap_exit() on the regmap instance associated to the CODEC and
* removes the regmap instance from the CODEC.
*
* This function should only be used if snd_soc_codec_init_regmap() was used to
* initialize the regmap instance.
*/
static inline void snd_soc_codec_exit_regmap(struct snd_soc_codec *codec)
{
snd_soc_component_exit_regmap(&codec->component);
}
#endif
/* device driver data */
@ -1662,28 +1338,6 @@ static inline void *snd_soc_component_get_drvdata(struct snd_soc_component *c)
return dev_get_drvdata(c->dev);
}
static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
void *data)
{
snd_soc_component_set_drvdata(&codec->component, data);
}
static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
{
return snd_soc_component_get_drvdata(&codec->component);
}
static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
void *data)
{
snd_soc_component_set_drvdata(&platform->component, data);
}
static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
{
return snd_soc_component_get_drvdata(&platform->component);
}
static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
{
INIT_LIST_HEAD(&card->widgets);
@ -1735,20 +1389,15 @@ static inline bool snd_soc_component_is_active(
return component->active != 0;
}
static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec)
{
return snd_soc_component_is_active(&codec->component);
}
/**
* snd_soc_kcontrol_component() - Returns the component that registered the
* control
* @kcontrol: The control for which to get the component
*
* Note: This function will work correctly if the control has been registered
* for a component. Either with snd_soc_add_codec_controls() or
* snd_soc_add_platform_controls() or via table based setup for either a
* CODEC, a platform or component driver. Otherwise the behavior is undefined.
* for a component. With snd_soc_add_codec_controls() or via table based
* setup for either a CODEC or component driver. Otherwise the behavior is
* undefined.
*/
static inline struct snd_soc_component *snd_soc_kcontrol_component(
struct snd_kcontrol *kcontrol)
@ -1756,34 +1405,6 @@ static inline struct snd_soc_component *snd_soc_kcontrol_component(
return snd_kcontrol_chip(kcontrol);
}
/**
* snd_soc_kcontrol_codec() - Returns the CODEC that registered the control
* @kcontrol: The control for which to get the CODEC
*
* Note: This function will only work correctly if the control has been
* registered with snd_soc_add_codec_controls() or via table based setup of
* snd_soc_codec_driver. Otherwise the behavior is undefined.
*/
static inline struct snd_soc_codec *snd_soc_kcontrol_codec(
struct snd_kcontrol *kcontrol)
{
return snd_soc_component_to_codec(snd_soc_kcontrol_component(kcontrol));
}
/**
* snd_soc_kcontrol_platform() - Returns the platform that registered the control
* @kcontrol: The control for which to get the platform
*
* Note: This function will only work correctly if the control has been
* registered with snd_soc_add_platform_controls() or via table based setup of
* a snd_soc_platform_driver. Otherwise the behavior is undefined.
*/
static inline struct snd_soc_platform *snd_soc_kcontrol_platform(
struct snd_kcontrol *kcontrol)
{
return snd_soc_component_to_platform(snd_soc_kcontrol_component(kcontrol));
}
int snd_soc_util_init(void);
void snd_soc_util_exit(void);

View file

@ -12,7 +12,6 @@
#define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-")
struct snd_soc_jack;
struct snd_soc_codec;
struct snd_soc_card;
struct snd_soc_dapm_widget;
struct snd_soc_dapm_path;

View file

@ -139,6 +139,15 @@
#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS (1 << 1)
#define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2)
/* DAI clock gating */
#define SND_SOC_TPLG_DAI_CLK_GATE_UNDEFINED 0
#define SND_SOC_TPLG_DAI_CLK_GATE_GATED 1
#define SND_SOC_TPLG_DAI_CLK_GATE_CONT 2
/* DAI mclk_direction */
#define SND_SOC_TPLG_MCLK_CO 0 /* for codec, mclk is output */
#define SND_SOC_TPLG_MCLK_CI 1 /* for codec, mclk is input */
/* DAI physical PCM data formats.
* Add new formats to the end of the list.
*/
@ -160,6 +169,18 @@
#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2)
#define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3)
/* DAI topology BCLK parameter
* For the backwards capability, by default codec is bclk master
*/
#define SND_SOC_TPLG_BCLK_CM 0 /* codec is bclk master */
#define SND_SOC_TPLG_BCLK_CS 1 /* codec is bclk slave */
/* DAI topology FSYNC parameter
* For the backwards capability, by default codec is fsync master
*/
#define SND_SOC_TPLG_FSYNC_CM 0 /* codec is fsync master */
#define SND_SOC_TPLG_FSYNC_CS 1 /* codec is fsync slave */
/*
* Block Header.
* This header precedes all object and object arrays below.
@ -312,12 +333,12 @@ struct snd_soc_tplg_hw_config {
__le32 size; /* in bytes of this structure */
__le32 id; /* unique ID - - used to match */
__le32 fmt; /* SND_SOC_DAI_FORMAT_ format value */
__u8 clock_gated; /* 1 if clock can be gated to save power */
__u8 clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */
__u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */
__u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */
__u8 bclk_master; /* 1 for master of BCLK, 0 for slave */
__u8 fsync_master; /* 1 for master of FSYNC, 0 for slave */
__u8 mclk_direction; /* 0 for input, 1 for output */
__u8 bclk_master; /* SND_SOC_TPLG_BCLK_ value */
__u8 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */
__u8 mclk_direction; /* SND_SOC_TPLG_MCLK_ value */
__le16 reserved; /* for 32bit alignment */
__le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */
__le32 bclk_rate; /* BCLK freqency in Hz */
@ -552,4 +573,61 @@ struct snd_soc_tplg_dai {
__le32 flags; /* SND_SOC_TPLG_DAI_FLGBIT_* */
struct snd_soc_tplg_private priv;
} __attribute__((packed));
/*
* Old version of ABI structs, supported for backward compatibility.
*/
/* Manifest v4 */
struct snd_soc_tplg_manifest_v4 {
__le32 size; /* in bytes of this structure */
__le32 control_elems; /* number of control elements */
__le32 widget_elems; /* number of widget elements */
__le32 graph_elems; /* number of graph elements */
__le32 pcm_elems; /* number of PCM elements */
__le32 dai_link_elems; /* number of DAI link elements */
struct snd_soc_tplg_private priv;
} __packed;
/* Stream Capabilities v4 */
struct snd_soc_tplg_stream_caps_v4 {
__le32 size; /* in bytes of this structure */
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
__le64 formats; /* supported formats SNDRV_PCM_FMTBIT_* */
__le32 rates; /* supported rates SNDRV_PCM_RATE_* */
__le32 rate_min; /* min rate */
__le32 rate_max; /* max rate */
__le32 channels_min; /* min channels */
__le32 channels_max; /* max channels */
__le32 periods_min; /* min number of periods */
__le32 periods_max; /* max number of periods */
__le32 period_size_min; /* min period size bytes */
__le32 period_size_max; /* max period size bytes */
__le32 buffer_size_min; /* min buffer size bytes */
__le32 buffer_size_max; /* max buffer size bytes */
} __packed;
/* PCM v4 */
struct snd_soc_tplg_pcm_v4 {
__le32 size; /* in bytes of this structure */
char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
__le32 pcm_id; /* unique ID - used to match with DAI link */
__le32 dai_id; /* unique ID - used to match */
__le32 playback; /* supports playback mode */
__le32 capture; /* supports capture mode */
__le32 compress; /* 1 = compressed; 0 = PCM */
struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */
__le32 num_streams; /* number of streams */
struct snd_soc_tplg_stream_caps_v4 caps[2]; /* playback and capture for DAI */
} __packed;
/* Physical link config v4 */
struct snd_soc_tplg_link_config_v4 {
__le32 size; /* in bytes of this structure */
__le32 id; /* unique ID - used to match */
struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */
__le32 num_streams; /* number of streams */
} __packed;
#endif

View file

@ -1,19 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* skl-tplg-interface.h - Intel DSP FW private data interface
*
* Copyright (C) 2015 Intel Corp
* Author: Jeeja KP <jeeja.kp@intel.com>
* Nilofer, Samreen <samreen.nilofer@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef __HDA_TPLG_INTERFACE_H__
@ -169,4 +160,78 @@ enum skl_tuple_type {
SKL_TYPE_DATA
};
/* v4 configuration data */
struct skl_dfw_v4_module_pin {
u16 module_id;
u16 instance_id;
} __packed;
struct skl_dfw_v4_module_fmt {
u32 channels;
u32 freq;
u32 bit_depth;
u32 valid_bit_depth;
u32 ch_cfg;
u32 interleaving_style;
u32 sample_type;
u32 ch_map;
} __packed;
struct skl_dfw_v4_module_caps {
u32 set_params:2;
u32 rsvd:30;
u32 param_id;
u32 caps_size;
u32 caps[HDA_SST_CFG_MAX];
} __packed;
struct skl_dfw_v4_pipe {
u8 pipe_id;
u8 pipe_priority;
u16 conn_type:4;
u16 rsvd:4;
u16 memory_pages:8;
} __packed;
struct skl_dfw_v4_module {
char uuid[SKL_UUID_STR_SZ];
u16 module_id;
u16 instance_id;
u32 max_mcps;
u32 mem_pages;
u32 obs;
u32 ibs;
u32 vbus_id;
u32 max_in_queue:8;
u32 max_out_queue:8;
u32 time_slot:8;
u32 core_id:4;
u32 rsvd1:4;
u32 module_type:8;
u32 conn_type:4;
u32 dev_type:4;
u32 hw_conn_type:4;
u32 rsvd2:12;
u32 params_fixup:8;
u32 converter:8;
u32 input_pin_type:1;
u32 output_pin_type:1;
u32 is_dynamic_in_pin:1;
u32 is_dynamic_out_pin:1;
u32 is_loadable:1;
u32 rsvd3:11;
struct skl_dfw_v4_pipe pipe;
struct skl_dfw_v4_module_fmt in_fmt[MAX_IN_QUEUE];
struct skl_dfw_v4_module_fmt out_fmt[MAX_OUT_QUEUE];
struct skl_dfw_v4_module_pin in_pin[MAX_IN_QUEUE];
struct skl_dfw_v4_module_pin out_pin[MAX_OUT_QUEUE];
struct skl_dfw_v4_module_caps caps;
} __packed;
#endif

View file

@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o
snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o
snd-soc-core-$(CONFIG_SND_SOC_COMPRESS) += soc-compress.o

View file

@ -33,17 +33,19 @@
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/acpi.h>
#include "acp.h"
#include "../codecs/da7219.h"
#include "../codecs/da7219-aad.h"
#define CZ_PLAT_CLK 24000000
#define MCLK_RATE 24576000
#define CZ_PLAT_CLK 25000000
#define DUAL_CHANNEL 2
static struct snd_soc_jack cz_jack;
static struct clk *da7219_dai_clk;
extern int bt_uart_enable;
static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
{
@ -62,7 +64,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
}
ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL,
CZ_PLAT_CLK, MCLK_RATE);
CZ_PLAT_CLK, DA7219_PLL_FREQ_OUT_98304);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
return ret;
@ -80,13 +82,17 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
da7219_aad_jack_det(component, &cz_jack);
return 0;
}
static int cz_da7219_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
static int da7219_clk_enable(struct snd_pcm_substream *substream)
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@ -100,11 +106,9 @@ static int cz_da7219_hw_params(struct snd_pcm_substream *substream,
return ret;
}
static int cz_da7219_hw_free(struct snd_pcm_substream *substream)
static void da7219_clk_disable(void)
{
clk_disable_unprepare(da7219_dai_clk);
return 0;
}
static const unsigned int channels[] = {
@ -127,9 +131,12 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
.mask = 0,
};
static int cz_fe_startup(struct snd_pcm_substream *substream)
static int cz_da7219_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
/*
* On this platform for PCM device we support stereo
@ -141,23 +148,58 @@ static int cz_fe_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
return 0;
machine->i2s_instance = I2S_BT_INSTANCE;
return da7219_clk_enable(substream);
}
static struct snd_soc_ops cz_da7219_cap_ops = {
.hw_params = cz_da7219_hw_params,
.hw_free = cz_da7219_hw_free,
.startup = cz_fe_startup,
static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
{
da7219_clk_disable();
}
static int cz_max_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->i2s_instance = I2S_SP_INSTANCE;
return da7219_clk_enable(substream);
}
static void cz_max_shutdown(struct snd_pcm_substream *substream)
{
da7219_clk_disable();
}
static int cz_dmic_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->i2s_instance = I2S_SP_INSTANCE;
return da7219_clk_enable(substream);
}
static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
{
da7219_clk_disable();
}
static const struct snd_soc_ops cz_da7219_cap_ops = {
.startup = cz_da7219_startup,
.shutdown = cz_da7219_shutdown,
};
static struct snd_soc_ops cz_max_play_ops = {
.hw_params = cz_da7219_hw_params,
.hw_free = cz_da7219_hw_free,
static const struct snd_soc_ops cz_max_play_ops = {
.startup = cz_max_startup,
.shutdown = cz_max_shutdown,
};
static struct snd_soc_ops cz_dmic_cap_ops = {
.hw_params = cz_da7219_hw_params,
.hw_free = cz_da7219_hw_free,
static const struct snd_soc_ops cz_dmic_cap_ops = {
.startup = cz_dmic_startup,
.shutdown = cz_dmic_shutdown,
};
static struct snd_soc_dai_link cz_dai_7219_98357[] = {
@ -240,10 +282,16 @@ static int cz_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card;
struct acp_platform_info *machine;
machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info),
GFP_KERNEL);
if (!machine)
return -ENOMEM;
card = &cz_card;
cz_card.dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
if (ret) {
dev_err(&pdev->dev,
@ -251,6 +299,8 @@ static int cz_probe(struct platform_device *pdev)
cz_card.name, ret);
return ret;
}
bt_uart_enable = !device_property_read_bool(&pdev->dev,
"bt-pad-enable");
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -10,17 +10,30 @@
#define ACP_PLAYBACK_PTE_OFFSET 10
#define ACP_CAPTURE_PTE_OFFSET 0
/* Playback and Capture Offset for Stoney */
#define ACP_ST_PLAYBACK_PTE_OFFSET 0x04
#define ACP_ST_CAPTURE_PTE_OFFSET 0x00
#define ACP_ST_BT_PLAYBACK_PTE_OFFSET 0x08
#define ACP_ST_BT_CAPTURE_PTE_OFFSET 0x0c
#define ACP_GARLIC_CNTL_DEFAULT 0x00000FB4
#define ACP_ONION_CNTL_DEFAULT 0x00000FB4
#define ACP_PHYSICAL_BASE 0x14000
/* Playback SRAM address (as a destination in dma descriptor) */
#define ACP_SHARED_RAM_BANK_1_ADDRESS 0x4002000
/* Capture SRAM address (as a source in dma descriptor) */
#define ACP_SHARED_RAM_BANK_5_ADDRESS 0x400A000
#define ACP_SHARED_RAM_BANK_3_ADDRESS 0x4006000
/*
* In case of I2S SP controller instance, Stoney uses SRAM bank 1 for
* playback and SRAM Bank 2 for capture where as in case of BT I2S
* Instance, Stoney uses SRAM Bank 3 for playback & SRAM Bank 4 will
* be used for capture. Carrizo uses I2S SP controller instance. SRAM Banks
* 1, 2, 3, 4 will be used for playback & SRAM Banks 5, 6, 7, 8 will be used
* for capture scenario.
*/
#define ACP_SRAM_BANK_1_ADDRESS 0x4002000
#define ACP_SRAM_BANK_2_ADDRESS 0x4004000
#define ACP_SRAM_BANK_3_ADDRESS 0x4006000
#define ACP_SRAM_BANK_4_ADDRESS 0x4008000
#define ACP_SRAM_BANK_5_ADDRESS 0x400A000
#define ACP_DMA_RESET_TIME 10000
#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF
@ -35,8 +48,13 @@
#define TO_ACP_I2S_1 0x2
#define TO_ACP_I2S_2 0x4
#define TO_BLUETOOTH 0x3
#define FROM_ACP_I2S_1 0xa
#define FROM_ACP_I2S_2 0xb
#define FROM_BLUETOOTH 0xb
#define I2S_SP_INSTANCE 0x01
#define I2S_BT_INSTANCE 0x02
#define ACP_TILE_ON_MASK 0x03
#define ACP_TILE_OFF_MASK 0x02
@ -57,6 +75,14 @@
#define ACP_TO_SYSRAM_CH_NUM 14
#define I2S_TO_ACP_DMA_CH_NUM 15
/* Playback DMA Channels for I2S BT instance */
#define SYSRAM_TO_ACP_BT_INSTANCE_CH_NUM 8
#define ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM 9
/* Capture DMA Channels for I2S BT Instance */
#define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 10
#define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 11
#define NUM_DSCRS_PER_CHANNEL 2
#define PLAYBACK_START_DMA_DESCR_CH12 0
@ -69,9 +95,23 @@
#define CAPTURE_START_DMA_DESCR_CH15 6
#define CAPTURE_END_DMA_DESCR_CH15 7
/* I2S BT Instance DMA Descriptors */
#define PLAYBACK_START_DMA_DESCR_CH8 8
#define PLAYBACK_END_DMA_DESCR_CH8 9
#define PLAYBACK_START_DMA_DESCR_CH9 10
#define PLAYBACK_END_DMA_DESCR_CH9 11
#define CAPTURE_START_DMA_DESCR_CH10 12
#define CAPTURE_END_DMA_DESCR_CH10 13
#define CAPTURE_START_DMA_DESCR_CH11 14
#define CAPTURE_END_DMA_DESCR_CH11 15
#define mmACP_I2S_16BIT_RESOLUTION_EN 0x5209
#define ACP_I2S_MIC_16BIT_RESOLUTION_EN 0x01
#define ACP_I2S_SP_16BIT_RESOLUTION_EN 0x02
#define ACP_I2S_BT_16BIT_RESOLUTION_EN 0x04
#define ACP_BT_UART_PAD_SELECT_MASK 0x1
enum acp_dma_priority_level {
/* 0x0 Specifies the DMA channel is given normal priority */
ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
@ -84,20 +124,39 @@ struct audio_substream_data {
struct page *pg;
unsigned int order;
u16 num_of_pages;
u16 i2s_instance;
u16 direction;
u16 ch1;
u16 ch2;
u16 destination;
u16 dma_dscr_idx_1;
u16 dma_dscr_idx_2;
u32 pte_offset;
u32 sram_bank;
u32 byte_cnt_high_reg_offset;
u32 byte_cnt_low_reg_offset;
uint64_t size;
u64 i2ssp_renderbytescount;
u64 i2ssp_capturebytescount;
u64 bytescount;
void __iomem *acp_mmio;
};
struct audio_drv_data {
struct snd_pcm_substream *play_i2ssp_stream;
struct snd_pcm_substream *capture_i2ssp_stream;
struct snd_pcm_substream *play_i2sbt_stream;
struct snd_pcm_substream *capture_i2sbt_stream;
void __iomem *acp_mmio;
u32 asic_type;
};
/*
* this structure used for platform data transfer between machine driver
* and dma driver
*/
struct acp_platform_info {
u16 i2s_instance;
};
union acp_dma_count {
struct {
u32 low;
@ -115,23 +174,25 @@ enum {
};
enum {
ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0,
ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8,
ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM = 0x9,
ACP_DMA_ATTRIBUTES_FORCE_SIZE = 0xF
ACP_DMA_ATTR_SHAREDMEM_TO_DAGB_ONION = 0x0,
ACP_DMA_ATTR_SHARED_MEM_TO_DAGB_GARLIC = 0x1,
ACP_DMA_ATTR_DAGB_ONION_TO_SHAREDMEM = 0x8,
ACP_DMA_ATTR_DAGB_GARLIC_TO_SHAREDMEM = 0x9,
ACP_DMA_ATTR_FORCE_SIZE = 0xF
};
typedef struct acp_dma_dscr_transfer {
/* Specifies the source memory location for the DMA data transfer. */
u32 src;
/* Specifies the destination memory location to where the data will
/*
* Specifies the destination memory location to where the data will
* be transferred.
*/
*/
u32 dest;
/* Specifies the number of bytes need to be transferred
* from source to destination memory.Transfer direction & IOC enable
*/
/*
* Specifies the number of bytes need to be transferred
* from source to destination memory.Transfer direction & IOC enable
*/
u32 xfer_val;
/* Reserved for future use */
u32 reserved;

View file

@ -88,4 +88,13 @@ config SND_ATMEL_SOC_TSE850_PCM5142
help
Say Y if you want to add support for the ASoC driver for the
Axentia TSE-850 with a PCM5142 codec.
config SND_ATMEL_SOC_I2S
tristate "Atmel ASoC driver for boards using I2S"
depends on OF && (ARCH_AT91 || COMPILE_TEST)
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
help
Say Y or M if you want to add support for Atmel ASoc driver for boards
using I2S.
endif

View file

@ -3,10 +3,12 @@
snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o
snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
snd-soc-atmel-i2s-objs := atmel-i2s.o
obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
obj-$(CONFIG_SND_ATMEL_SOC_I2S) += snd-soc-atmel-i2s.o
# AT91 Machine Support
snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o

765
sound/soc/atmel/atmel-i2s.c Normal file
View file

@ -0,0 +1,765 @@
/*
* Driver for Atmel I2S controller
*
* Copyright (C) 2015 Atmel Corporation
*
* Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#define ATMEL_I2SC_MAX_TDM_CHANNELS 8
/*
* ---- I2S Controller Register map ----
*/
#define ATMEL_I2SC_CR 0x0000 /* Control Register */
#define ATMEL_I2SC_MR 0x0004 /* Mode Register */
#define ATMEL_I2SC_SR 0x0008 /* Status Register */
#define ATMEL_I2SC_SCR 0x000c /* Status Clear Register */
#define ATMEL_I2SC_SSR 0x0010 /* Status Set Register */
#define ATMEL_I2SC_IER 0x0014 /* Interrupt Enable Register */
#define ATMEL_I2SC_IDR 0x0018 /* Interrupt Disable Register */
#define ATMEL_I2SC_IMR 0x001c /* Interrupt Mask Register */
#define ATMEL_I2SC_RHR 0x0020 /* Receiver Holding Register */
#define ATMEL_I2SC_THR 0x0024 /* Transmitter Holding Register */
#define ATMEL_I2SC_VERSION 0x0028 /* Version Register */
/*
* ---- Control Register (Write-only) ----
*/
#define ATMEL_I2SC_CR_RXEN BIT(0) /* Receiver Enable */
#define ATMEL_I2SC_CR_RXDIS BIT(1) /* Receiver Disable */
#define ATMEL_I2SC_CR_CKEN BIT(2) /* Clock Enable */
#define ATMEL_I2SC_CR_CKDIS BIT(3) /* Clock Disable */
#define ATMEL_I2SC_CR_TXEN BIT(4) /* Transmitter Enable */
#define ATMEL_I2SC_CR_TXDIS BIT(5) /* Transmitter Disable */
#define ATMEL_I2SC_CR_SWRST BIT(7) /* Software Reset */
/*
* ---- Mode Register (Read/Write) ----
*/
#define ATMEL_I2SC_MR_MODE_MASK GENMASK(0, 0)
#define ATMEL_I2SC_MR_MODE_SLAVE (0 << 0)
#define ATMEL_I2SC_MR_MODE_MASTER (1 << 0)
#define ATMEL_I2SC_MR_DATALENGTH_MASK GENMASK(4, 2)
#define ATMEL_I2SC_MR_DATALENGTH_32_BITS (0 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_24_BITS (1 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_20_BITS (2 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_18_BITS (3 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_16_BITS (4 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_16_BITS_COMPACT (5 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_8_BITS (6 << 2)
#define ATMEL_I2SC_MR_DATALENGTH_8_BITS_COMPACT (7 << 2)
#define ATMEL_I2SC_MR_FORMAT_MASK GENMASK(7, 6)
#define ATMEL_I2SC_MR_FORMAT_I2S (0 << 6)
#define ATMEL_I2SC_MR_FORMAT_LJ (1 << 6) /* Left Justified */
#define ATMEL_I2SC_MR_FORMAT_TDM (2 << 6)
#define ATMEL_I2SC_MR_FORMAT_TDMLJ (3 << 6)
/* Left audio samples duplicated to right audio channel */
#define ATMEL_I2SC_MR_RXMONO BIT(8)
/* Receiver uses one DMA channel ... */
#define ATMEL_I2SC_MR_RXDMA_MASK GENMASK(9, 9)
#define ATMEL_I2SC_MR_RXDMA_SINGLE (0 << 9) /* for all audio channels */
#define ATMEL_I2SC_MR_RXDMA_MULTIPLE (1 << 9) /* per audio channel */
/* I2SDO output of I2SC is internally connected to I2SDI input */
#define ATMEL_I2SC_MR_RXLOOP BIT(10)
/* Left audio samples duplicated to right audio channel */
#define ATMEL_I2SC_MR_TXMONO BIT(12)
/* Transmitter uses one DMA channel ... */
#define ATMEL_I2SC_MR_TXDMA_MASK GENMASK(13, 13)
#define ATMEL_I2SC_MR_TXDMA_SINGLE (0 << 13) /* for all audio channels */
#define ATMEL_I2SC_MR_TXDME_MULTIPLE (1 << 13) /* per audio channel */
/* x sample transmitted when underrun */
#define ATMEL_I2SC_MR_TXSAME_MASK GENMASK(14, 14)
#define ATMEL_I2SC_MR_TXSAME_ZERO (0 << 14) /* Zero sample */
#define ATMEL_I2SC_MR_TXSAME_PREVIOUS (1 << 14) /* Previous sample */
/* Audio Clock to I2SC Master Clock ratio */
#define ATMEL_I2SC_MR_IMCKDIV_MASK GENMASK(21, 16)
#define ATMEL_I2SC_MR_IMCKDIV(div) \
(((div) << 16) & ATMEL_I2SC_MR_IMCKDIV_MASK)
/* Master Clock to fs ratio */
#define ATMEL_I2SC_MR_IMCKFS_MASK GENMASK(29, 24)
#define ATMEL_I2SC_MR_IMCKFS(fs) \
(((fs) << 24) & ATMEL_I2SC_MR_IMCKFS_MASK)
/* Master Clock mode */
#define ATMEL_I2SC_MR_IMCKMODE_MASK GENMASK(30, 30)
/* 0: No master clock generated (selected clock drives I2SCK pin) */
#define ATMEL_I2SC_MR_IMCKMODE_I2SCK (0 << 30)
/* 1: master clock generated (internally generated clock drives I2SMCK pin) */
#define ATMEL_I2SC_MR_IMCKMODE_I2SMCK (1 << 30)
/* Slot Width */
/* 0: slot is 32 bits wide for DATALENGTH = 18/20/24 bits. */
/* 1: slot is 24 bits wide for DATALENGTH = 18/20/24 bits. */
#define ATMEL_I2SC_MR_IWS BIT(31)
/*
* ---- Status Registers ----
*/
#define ATMEL_I2SC_SR_RXEN BIT(0) /* Receiver Enabled */
#define ATMEL_I2SC_SR_RXRDY BIT(1) /* Receive Ready */
#define ATMEL_I2SC_SR_RXOR BIT(2) /* Receive Overrun */
#define ATMEL_I2SC_SR_TXEN BIT(4) /* Transmitter Enabled */
#define ATMEL_I2SC_SR_TXRDY BIT(5) /* Transmit Ready */
#define ATMEL_I2SC_SR_TXUR BIT(6) /* Transmit Underrun */
/* Receive Overrun Channel */
#define ATMEL_I2SC_SR_RXORCH_MASK GENMASK(15, 8)
#define ATMEL_I2SC_SR_RXORCH(ch) (1 << (((ch) & 0x7) + 8))
/* Transmit Underrun Channel */
#define ATMEL_I2SC_SR_TXURCH_MASK GENMASK(27, 20)
#define ATMEL_I2SC_SR_TXURCH(ch) (1 << (((ch) & 0x7) + 20))
/*
* ---- Interrupt Enable/Disable/Mask Registers ----
*/
#define ATMEL_I2SC_INT_RXRDY ATMEL_I2SC_SR_RXRDY
#define ATMEL_I2SC_INT_RXOR ATMEL_I2SC_SR_RXOR
#define ATMEL_I2SC_INT_TXRDY ATMEL_I2SC_SR_TXRDY
#define ATMEL_I2SC_INT_TXUR ATMEL_I2SC_SR_TXUR
static const struct regmap_config atmel_i2s_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = ATMEL_I2SC_VERSION,
};
struct atmel_i2s_gck_param {
int fs;
unsigned long mck;
int imckdiv;
int imckfs;
};
#define I2S_MCK_12M288 12288000UL
#define I2S_MCK_11M2896 11289600UL
/* mck = (32 * (imckfs+1) / (imckdiv+1)) * fs */
static const struct atmel_i2s_gck_param gck_params[] = {
/* mck = 12.288MHz */
{ 8000, I2S_MCK_12M288, 0, 47}, /* mck = 1536 fs */
{ 16000, I2S_MCK_12M288, 1, 47}, /* mck = 768 fs */
{ 24000, I2S_MCK_12M288, 3, 63}, /* mck = 512 fs */
{ 32000, I2S_MCK_12M288, 3, 47}, /* mck = 384 fs */
{ 48000, I2S_MCK_12M288, 7, 63}, /* mck = 256 fs */
{ 64000, I2S_MCK_12M288, 7, 47}, /* mck = 192 fs */
{ 96000, I2S_MCK_12M288, 7, 31}, /* mck = 128 fs */
{192000, I2S_MCK_12M288, 7, 15}, /* mck = 64 fs */
/* mck = 11.2896MHz */
{ 11025, I2S_MCK_11M2896, 1, 63}, /* mck = 1024 fs */
{ 22050, I2S_MCK_11M2896, 3, 63}, /* mck = 512 fs */
{ 44100, I2S_MCK_11M2896, 7, 63}, /* mck = 256 fs */
{ 88200, I2S_MCK_11M2896, 7, 31}, /* mck = 128 fs */
{176400, I2S_MCK_11M2896, 7, 15}, /* mck = 64 fs */
};
struct atmel_i2s_dev;
struct atmel_i2s_caps {
int (*mck_init)(struct atmel_i2s_dev *, struct device_node *np);
};
struct atmel_i2s_dev {
struct device *dev;
struct regmap *regmap;
struct clk *pclk;
struct clk *gclk;
struct clk *aclk;
struct snd_dmaengine_dai_dma_data playback;
struct snd_dmaengine_dai_dma_data capture;
unsigned int fmt;
const struct atmel_i2s_gck_param *gck_param;
const struct atmel_i2s_caps *caps;
};
static irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id)
{
struct atmel_i2s_dev *dev = dev_id;
unsigned int sr, imr, pending, ch, mask;
irqreturn_t ret = IRQ_NONE;
regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr);
regmap_read(dev->regmap, ATMEL_I2SC_IMR, &imr);
pending = sr & imr;
if (!pending)
return IRQ_NONE;
if (pending & ATMEL_I2SC_INT_RXOR) {
mask = ATMEL_I2SC_SR_RXOR;
for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
if (sr & ATMEL_I2SC_SR_RXORCH(ch)) {
mask |= ATMEL_I2SC_SR_RXORCH(ch);
dev_err(dev->dev,
"RX overrun on channel %d\n", ch);
}
}
regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);
ret = IRQ_HANDLED;
}
if (pending & ATMEL_I2SC_INT_TXUR) {
mask = ATMEL_I2SC_SR_TXUR;
for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
if (sr & ATMEL_I2SC_SR_TXURCH(ch)) {
mask |= ATMEL_I2SC_SR_TXURCH(ch);
dev_err(dev->dev,
"TX underrun on channel %d\n", ch);
}
}
regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);
ret = IRQ_HANDLED;
}
return ret;
}
#define ATMEL_I2S_RATES SNDRV_PCM_RATE_8000_192000
#define ATMEL_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S18_3LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
static int atmel_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
dev->fmt = fmt;
return 0;
}
static int atmel_i2s_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
unsigned int rhr, sr = 0;
if (is_playback) {
regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr);
if (sr & ATMEL_I2SC_SR_RXRDY) {
/*
* The RX Ready flag should not be set. However if here,
* we flush (read) the Receive Holding Register to start
* from a clean state.
*/
dev_dbg(dev->dev, "RXRDY is set\n");
regmap_read(dev->regmap, ATMEL_I2SC_RHR, &rhr);
}
}
return 0;
}
static int atmel_i2s_get_gck_param(struct atmel_i2s_dev *dev, int fs)
{
int i, best;
if (!dev->gclk || !dev->aclk) {
dev_err(dev->dev, "cannot generate the I2S Master Clock\n");
return -EINVAL;
}
/*
* Find the best possible settings to generate the I2S Master Clock
* from the PLL Audio.
*/
dev->gck_param = NULL;
best = INT_MAX;
for (i = 0; i < ARRAY_SIZE(gck_params); ++i) {
const struct atmel_i2s_gck_param *gck_param = &gck_params[i];
int val = abs(fs - gck_param->fs);
if (val < best) {
best = val;
dev->gck_param = gck_param;
}
}
return 0;
}
static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
unsigned int mr = 0;
int ret;
switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
mr |= ATMEL_I2SC_MR_FORMAT_I2S;
break;
default:
dev_err(dev->dev, "unsupported bus format\n");
return -EINVAL;
}
switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* codec is slave, so cpu is master */
mr |= ATMEL_I2SC_MR_MODE_MASTER;
ret = atmel_i2s_get_gck_param(dev, params_rate(params));
if (ret)
return ret;
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* codec is master, so cpu is slave */
mr |= ATMEL_I2SC_MR_MODE_SLAVE;
dev->gck_param = NULL;
break;
default:
dev_err(dev->dev, "unsupported master/slave mode\n");
return -EINVAL;
}
switch (params_channels(params)) {
case 1:
if (is_playback)
mr |= ATMEL_I2SC_MR_TXMONO;
else
mr |= ATMEL_I2SC_MR_RXMONO;
break;
case 2:
break;
default:
dev_err(dev->dev, "unsupported number of audio channels\n");
return -EINVAL;
}
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
mr |= ATMEL_I2SC_MR_DATALENGTH_8_BITS;
break;
case SNDRV_PCM_FORMAT_S16_LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_16_BITS;
break;
case SNDRV_PCM_FORMAT_S18_3LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_18_BITS | ATMEL_I2SC_MR_IWS;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_20_BITS | ATMEL_I2SC_MR_IWS;
break;
case SNDRV_PCM_FORMAT_S24_3LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS | ATMEL_I2SC_MR_IWS;
break;
case SNDRV_PCM_FORMAT_S24_LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS;
break;
case SNDRV_PCM_FORMAT_S32_LE:
mr |= ATMEL_I2SC_MR_DATALENGTH_32_BITS;
break;
default:
dev_err(dev->dev, "unsupported size/endianness for audio samples\n");
return -EINVAL;
}
return regmap_write(dev->regmap, ATMEL_I2SC_MR, mr);
}
static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
bool enabled)
{
unsigned int mr, mr_mask;
unsigned long aclk_rate;
int ret;
mr = 0;
mr_mask = (ATMEL_I2SC_MR_IMCKDIV_MASK |
ATMEL_I2SC_MR_IMCKFS_MASK |
ATMEL_I2SC_MR_IMCKMODE_MASK);
if (!enabled) {
/* Disable the I2S Master Clock generator. */
ret = regmap_write(dev->regmap, ATMEL_I2SC_CR,
ATMEL_I2SC_CR_CKDIS);
if (ret)
return ret;
/* Reset the I2S Master Clock generator settings. */
ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR,
mr_mask, mr);
if (ret)
return ret;
/* Disable/unprepare the PMC generated clock. */
clk_disable_unprepare(dev->gclk);
/* Disable/unprepare the PLL audio clock. */
clk_disable_unprepare(dev->aclk);
return 0;
}
if (!dev->gck_param)
return -EINVAL;
aclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
/* Fist change the PLL audio clock frequency ... */
ret = clk_set_rate(dev->aclk, aclk_rate);
if (ret)
return ret;
/*
* ... then set the PMC generated clock rate to the very same frequency
* to set the gclk parent to aclk.
*/
ret = clk_set_rate(dev->gclk, aclk_rate);
if (ret)
return ret;
/* Prepare and enable the PLL audio clock first ... */
ret = clk_prepare_enable(dev->aclk);
if (ret)
return ret;
/* ... then prepare and enable the PMC generated clock. */
ret = clk_prepare_enable(dev->gclk);
if (ret)
return ret;
/* Update the Mode Register to generate the I2S Master Clock. */
mr |= ATMEL_I2SC_MR_IMCKDIV(dev->gck_param->imckdiv);
mr |= ATMEL_I2SC_MR_IMCKFS(dev->gck_param->imckfs);
mr |= ATMEL_I2SC_MR_IMCKMODE_I2SMCK;
ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr);
if (ret)
return ret;
/* Finally enable the I2S Master Clock generator. */
return regmap_write(dev->regmap, ATMEL_I2SC_CR,
ATMEL_I2SC_CR_CKEN);
}
static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
bool is_master, mck_enabled;
unsigned int cr, mr;
int err;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
cr = is_playback ? ATMEL_I2SC_CR_TXEN : ATMEL_I2SC_CR_RXEN;
mck_enabled = true;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
cr = is_playback ? ATMEL_I2SC_CR_TXDIS : ATMEL_I2SC_CR_RXDIS;
mck_enabled = false;
break;
default:
return -EINVAL;
}
/* Read the Mode Register to retrieve the master/slave state. */
err = regmap_read(dev->regmap, ATMEL_I2SC_MR, &mr);
if (err)
return err;
is_master = (mr & ATMEL_I2SC_MR_MODE_MASK) == ATMEL_I2SC_MR_MODE_MASTER;
/* If master starts, enable the audio clock. */
if (is_master && mck_enabled)
err = atmel_i2s_switch_mck_generator(dev, true);
if (err)
return err;
err = regmap_write(dev->regmap, ATMEL_I2SC_CR, cr);
if (err)
return err;
/* If master stops, disable the audio clock. */
if (is_master && !mck_enabled)
err = atmel_i2s_switch_mck_generator(dev, false);
return err;
}
static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
.prepare = atmel_i2s_prepare,
.trigger = atmel_i2s_trigger,
.hw_params = atmel_i2s_hw_params,
.set_fmt = atmel_i2s_set_dai_fmt,
};
static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture);
return 0;
}
static struct snd_soc_dai_driver atmel_i2s_dai = {
.probe = atmel_i2s_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 2,
.rates = ATMEL_I2S_RATES,
.formats = ATMEL_I2S_FORMATS,
},
.capture = {
.channels_min = 1,
.channels_max = 2,
.rates = ATMEL_I2S_RATES,
.formats = ATMEL_I2S_FORMATS,
},
.ops = &atmel_i2s_dai_ops,
.symmetric_rates = 1,
};
static const struct snd_soc_component_driver atmel_i2s_component = {
.name = "atmel-i2s",
};
static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev,
struct device_node *np)
{
struct clk *muxclk;
int err;
if (!dev->gclk)
return 0;
/* muxclk is optional, so we return error for probe defer only */
muxclk = devm_clk_get(dev->dev, "muxclk");
if (IS_ERR(muxclk)) {
err = PTR_ERR(muxclk);
if (err == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_warn(dev->dev,
"failed to get the I2S clock control: %d\n", err);
return 0;
}
return clk_set_parent(muxclk, dev->gclk);
}
static const struct atmel_i2s_caps atmel_i2s_sama5d2_caps = {
.mck_init = atmel_i2s_sama5d2_mck_init,
};
static const struct of_device_id atmel_i2s_dt_ids[] = {
{
.compatible = "atmel,sama5d2-i2s",
.data = (void *)&atmel_i2s_sama5d2_caps,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_i2s_dt_ids);
static int atmel_i2s_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct atmel_i2s_dev *dev;
struct resource *mem;
struct regmap *regmap;
void __iomem *base;
int irq;
int err = -ENXIO;
unsigned int pcm_flags = 0;
unsigned int version;
/* Get memory for driver data. */
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
/* Get hardware capabilities. */
match = of_match_node(atmel_i2s_dt_ids, np);
if (match)
dev->caps = match->data;
/* Map I/O registers. */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(base))
return PTR_ERR(base);
regmap = devm_regmap_init_mmio(&pdev->dev, base,
&atmel_i2s_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
/* Request IRQ. */
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0,
dev_name(&pdev->dev), dev);
if (err)
return err;
/* Get the peripheral clock. */
dev->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(dev->pclk)) {
err = PTR_ERR(dev->pclk);
dev_err(&pdev->dev,
"failed to get the peripheral clock: %d\n", err);
return err;
}
/* Get audio clocks to generate the I2S Master Clock (I2S_MCK) */
dev->aclk = devm_clk_get(&pdev->dev, "aclk");
dev->gclk = devm_clk_get(&pdev->dev, "gclk");
if (IS_ERR(dev->aclk) && IS_ERR(dev->gclk)) {
if (PTR_ERR(dev->aclk) == -EPROBE_DEFER ||
PTR_ERR(dev->gclk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
/* Master Mode not supported */
dev->aclk = NULL;
dev->gclk = NULL;
} else if (IS_ERR(dev->gclk)) {
err = PTR_ERR(dev->gclk);
dev_err(&pdev->dev,
"failed to get the PMC generated clock: %d\n", err);
return err;
} else if (IS_ERR(dev->aclk)) {
err = PTR_ERR(dev->aclk);
dev_err(&pdev->dev,
"failed to get the PLL audio clock: %d\n", err);
return err;
}
dev->dev = &pdev->dev;
dev->regmap = regmap;
platform_set_drvdata(pdev, dev);
/* Do hardware specific settings to initialize I2S_MCK generator */
if (dev->caps && dev->caps->mck_init) {
err = dev->caps->mck_init(dev, np);
if (err)
return err;
}
/* Enable the peripheral clock. */
err = clk_prepare_enable(dev->pclk);
if (err)
return err;
/* Get IP version. */
regmap_read(dev->regmap, ATMEL_I2SC_VERSION, &version);
dev_info(&pdev->dev, "hw version: %#x\n", version);
/* Enable error interrupts. */
regmap_write(dev->regmap, ATMEL_I2SC_IER,
ATMEL_I2SC_INT_RXOR | ATMEL_I2SC_INT_TXUR);
err = devm_snd_soc_register_component(&pdev->dev,
&atmel_i2s_component,
&atmel_i2s_dai, 1);
if (err) {
dev_err(&pdev->dev, "failed to register DAI: %d\n", err);
clk_disable_unprepare(dev->pclk);
return err;
}
/* Prepare DMA config. */
dev->playback.addr = (dma_addr_t)mem->start + ATMEL_I2SC_THR;
dev->playback.maxburst = 1;
dev->capture.addr = (dma_addr_t)mem->start + ATMEL_I2SC_RHR;
dev->capture.maxburst = 1;
if (of_property_match_string(np, "dma-names", "rx-tx") == 0)
pcm_flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX;
err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, pcm_flags);
if (err) {
dev_err(&pdev->dev, "failed to register PCM: %d\n", err);
clk_disable_unprepare(dev->pclk);
return err;
}
return 0;
}
static int atmel_i2s_remove(struct platform_device *pdev)
{
struct atmel_i2s_dev *dev = platform_get_drvdata(pdev);
clk_disable_unprepare(dev->pclk);
return 0;
}
static struct platform_driver atmel_i2s_driver = {
.driver = {
.name = "atmel_i2s",
.of_match_table = of_match_ptr(atmel_i2s_dt_ids),
},
.probe = atmel_i2s_probe,
.remove = atmel_i2s_remove,
};
module_platform_driver(atmel_i2s_driver);
MODULE_DESCRIPTION("Atmel I2S Controller driver");
MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@atmel.com>");
MODULE_LICENSE("GPL v2");

View file

@ -820,7 +820,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
if (ret < 0) {
printk(KERN_WARNING
"atmel_ssc_dai: request_irq failure\n");
pr_debug("Atmel_ssc_dai: Stoping clock\n");
pr_debug("Atmel_ssc_dai: Stopping clock\n");
clk_disable(ssc_p->ssc->clk);
return ret;
}
@ -1002,8 +1002,7 @@ static const struct snd_soc_component_driver atmel_ssc_component = {
static int asoc_ssc_init(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ssc_device *ssc = platform_get_drvdata(pdev);
struct ssc_device *ssc = dev_get_drvdata(dev);
int ret;
ret = snd_soc_register_component(dev, &atmel_ssc_component,
@ -1033,8 +1032,7 @@ err:
static void asoc_ssc_exit(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ssc_device *ssc = platform_get_drvdata(pdev);
struct ssc_device *ssc = dev_get_drvdata(dev);
if (ssc->pdata->use_dma)
atmel_pcm_dma_platform_unregister(dev);

View file

@ -11,9 +11,8 @@ config SND_BCM2835_SOC_I2S
config SND_SOC_CYGNUS
tristate "SoC platform audio for Broadcom Cygnus chips"
depends on ARCH_BCM_CYGNUS || COMPILE_TEST
depends on HAS_DMA
help
Say Y if you want to add support for ASoC audio on Broadcom
Cygnus chips (bcm958300, bcm958305, bcm911360)
If you don't know what to do here, say N.
If you don't know what to do here, say N.

View file

@ -9,6 +9,23 @@ config SND_EP93XX_SOC
config SND_EP93XX_SOC_I2S
tristate
if SND_EP93XX_SOC_I2S
config SND_EP93XX_SOC_I2S_WATCHDOG
bool "IRQ based underflow watchdog workaround"
default y
help
I2S controller on EP93xx seems to have undocumented HW issue.
Underflow of internal I2S controller FIFO could confuse the
state machine and the whole stream can be shifted by one byte
until I2S is disabled. This option enables IRQ based watchdog
which disables and re-enables I2S in case of underflow and
fills FIFO with zeroes.
If you are unsure how to answer this question, answer Y.
endif # if SND_EP93XX_SOC_I2S
config SND_EP93XX_SOC_AC97
tristate
select AC97_BUS

View file

@ -35,8 +35,12 @@
#define EP93XX_I2S_TXCLKCFG 0x00
#define EP93XX_I2S_RXCLKCFG 0x04
#define EP93XX_I2S_GLSTS 0x08
#define EP93XX_I2S_GLCTRL 0x0C
#define EP93XX_I2S_I2STX0LFT 0x10
#define EP93XX_I2S_I2STX0RT 0x14
#define EP93XX_I2S_TXLINCTRLDATA 0x28
#define EP93XX_I2S_TXCTRL 0x2C
#define EP93XX_I2S_TXWRDLEN 0x30
@ -55,12 +59,22 @@
#define EP93XX_I2S_TXLINCTRLDATA_R_JUST BIT(2) /* Right justify */
/*
* Transmit empty interrupt level select:
* 0 - Generate interrupt when FIFO is half empty
* 1 - Generate interrupt when FIFO is empty
*/
#define EP93XX_I2S_TXCTRL_TXEMPTY_LVL BIT(0)
#define EP93XX_I2S_TXCTRL_TXUFIE BIT(1) /* Transmit interrupt enable */
#define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */
#define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */
#define EP93XX_I2S_CLKCFG_REL (1 << 2) /* First bit transition */
#define EP93XX_I2S_CLKCFG_MASTER (1 << 3) /* Master mode */
#define EP93XX_I2S_CLKCFG_NBCG (1 << 4) /* Not bit clock gating */
#define EP93XX_I2S_GLSTS_TX0_FIFO_FULL BIT(12)
struct ep93xx_i2s_info {
struct clk *mclk;
struct clk *sclk;
@ -98,7 +112,6 @@ static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
{
unsigned base_reg;
int i;
if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
(ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
@ -111,27 +124,36 @@ static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
}
/* Enable fifos */
/* Enable fifo */
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
base_reg = EP93XX_I2S_TX0EN;
else
base_reg = EP93XX_I2S_RX0EN;
for (i = 0; i < 3; i++)
ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
ep93xx_i2s_write_reg(info, base_reg, 1);
/* Enable TX IRQs (FIFO empty or underflow) */
if (IS_ENABLED(CONFIG_SND_EP93XX_SOC_I2S_WATCHDOG) &&
stream == SNDRV_PCM_STREAM_PLAYBACK)
ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL,
EP93XX_I2S_TXCTRL_TXEMPTY_LVL |
EP93XX_I2S_TXCTRL_TXUFIE);
}
static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
{
unsigned base_reg;
int i;
/* Disable fifos */
/* Disable IRQs */
if (IS_ENABLED(CONFIG_SND_EP93XX_SOC_I2S_WATCHDOG) &&
stream == SNDRV_PCM_STREAM_PLAYBACK)
ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCTRL, 0);
/* Disable fifo */
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
base_reg = EP93XX_I2S_TX0EN;
else
base_reg = EP93XX_I2S_RX0EN;
for (i = 0; i < 3; i++)
ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
ep93xx_i2s_write_reg(info, base_reg, 0);
if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
(ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
@ -145,6 +167,37 @@ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
}
}
/*
* According to documentation I2S controller can handle underflow conditions
* just fine, but in reality the state machine is sometimes confused so that
* the whole stream is shifted by one byte. The watchdog below disables the TX
* FIFO, fills the buffer with zeroes and re-enables the FIFO. State machine
* is being reset and by filling the buffer we get some time before next
* underflow happens.
*/
static irqreturn_t ep93xx_i2s_interrupt(int irq, void *dev_id)
{
struct ep93xx_i2s_info *info = dev_id;
/* Disable FIFO */
ep93xx_i2s_write_reg(info, EP93XX_I2S_TX0EN, 0);
/*
* Fill TX FIFO with zeroes, this way we can defer next IRQs as much as
* possible and get more time for DMA to catch up. Actually there are
* only 8 samples in this FIFO, so even on 8kHz maximum deferral here is
* 1ms.
*/
while (!(ep93xx_i2s_read_reg(info, EP93XX_I2S_GLSTS) &
EP93XX_I2S_GLSTS_TX0_FIFO_FULL)) {
ep93xx_i2s_write_reg(info, EP93XX_I2S_I2STX0LFT, 0);
ep93xx_i2s_write_reg(info, EP93XX_I2S_I2STX0RT, 0);
}
/* Re-enable FIFO */
ep93xx_i2s_write_reg(info, EP93XX_I2S_TX0EN, 1);
return IRQ_HANDLED;
}
static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
@ -394,6 +447,17 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
if (IS_ENABLED(CONFIG_SND_EP93XX_SOC_I2S_WATCHDOG)) {
int irq = platform_get_irq(pdev, 0);
if (irq <= 0)
return irq < 0 ? irq : -ENODEV;
err = devm_request_irq(&pdev->dev, irq, ep93xx_i2s_interrupt, 0,
pdev->name, info);
if (err)
return err;
}
info->mclk = clk_get(&pdev->dev, "mclk");
if (IS_ERR(info->mclk)) {
err = PTR_ERR(info->mclk);

View file

@ -106,6 +106,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX9877 if I2C
select SND_SOC_MC13783 if MFD_MC13XXX
select SND_SOC_ML26124 if I2C
select SND_SOC_MT6351 if MTK_PMIC_WRAP
select SND_SOC_NAU8540 if I2C
select SND_SOC_NAU8810 if I2C
select SND_SOC_NAU8824 if I2C
@ -126,6 +127,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT274 if I2C
select SND_SOC_RT286 if I2C
select SND_SOC_RT298 if I2C
select SND_SOC_RT1305 if I2C
select SND_SOC_RT5514 if I2C
select SND_SOC_RT5616 if I2C
select SND_SOC_RT5631 if I2C
@ -136,12 +138,14 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT5660 if I2C
select SND_SOC_RT5663 if I2C
select SND_SOC_RT5665 if I2C
select SND_SOC_RT5668 if I2C
select SND_SOC_RT5670 if I2C
select SND_SOC_RT5677 if I2C && SPI_MASTER
select SND_SOC_SGTL5000 if I2C
select SND_SOC_SI476X if MFD_SI476X_CORE
select SND_SOC_SIRF_AUDIO_CODEC
select SND_SOC_SPDIF
select SND_SOC_SSM2305
select SND_SOC_SSM2518 if I2C
select SND_SOC_SSM2602_SPI if SPI_MASTER
select SND_SOC_SSM2602_I2C if I2C
@ -168,6 +172,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C
select SND_SOC_TSCS42XX if I2C
select SND_SOC_TSCS454 if I2C
select SND_SOC_TS3A227E if I2C
select SND_SOC_TWL4030 if TWL4030_CORE
select SND_SOC_TWL6040 if TWL6040_CORE
@ -770,8 +775,10 @@ config SND_SOC_RL6231
default y if SND_SOC_RT5660=y
default y if SND_SOC_RT5663=y
default y if SND_SOC_RT5665=y
default y if SND_SOC_RT5668=y
default y if SND_SOC_RT5670=y
default y if SND_SOC_RT5677=y
default y if SND_SOC_RT1305=y
default m if SND_SOC_RT5514=m
default m if SND_SOC_RT5616=m
default m if SND_SOC_RT5640=m
@ -781,8 +788,10 @@ config SND_SOC_RL6231
default m if SND_SOC_RT5660=m
default m if SND_SOC_RT5663=m
default m if SND_SOC_RT5665=m
default m if SND_SOC_RT5668=m
default m if SND_SOC_RT5670=m
default m if SND_SOC_RT5677=m
default m if SND_SOC_RT1305=m
config SND_SOC_RL6347A
tristate
@ -805,6 +814,9 @@ config SND_SOC_RT298
tristate
depends on I2C
config SND_SOC_RT1305
tristate
config SND_SOC_RT5514
tristate
@ -844,6 +856,9 @@ config SND_SOC_RT5663
config SND_SOC_RT5665
tristate
config SND_SOC_RT5668
tristate
config SND_SOC_RT5670
tristate
@ -883,6 +898,12 @@ config SND_SOC_SIRF_AUDIO_CODEC
config SND_SOC_SPDIF
tristate "S/PDIF CODEC"
config SND_SOC_SSM2305
tristate "Analog Devices SSM2305 Class-D Amplifier"
help
Enable support for Analog Devices SSM2305 filterless
high-efficiency mono Class-D audio power amplifiers.
config SND_SOC_SSM2518
tristate
@ -1011,6 +1032,13 @@ config SND_SOC_TSCS42XX
help
Add support for Tempo Semiconductor's TSCS42xx audio CODEC.
config SND_SOC_TSCS454
tristate "Tempo Semiconductor TSCS454 CODEC"
depends on I2C
select REGMAP_I2C
help
Add support for Tempo Semiconductor's TSCS454 audio CODEC.
config SND_SOC_TWL4030
select MFD_TWL4030_AUDIO
tristate
@ -1111,7 +1139,7 @@ config SND_SOC_WM8776
depends on SND_SOC_I2C_AND_SPI
config SND_SOC_WM8782
tristate
tristate "Wolfson Microelectronics WM8782 ADC"
config SND_SOC_WM8804
tristate
@ -1247,6 +1275,9 @@ config SND_SOC_MC13783
config SND_SOC_ML26124
tristate
config SND_SOC_MT6351
tristate "MediaTek MT6351 Codec"
config SND_SOC_NAU8540
tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
depends on I2C

View file

@ -102,6 +102,7 @@ snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o
snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
snd-soc-mt6351-objs := mt6351.o
snd-soc-nau8540-objs := nau8540.o
snd-soc-nau8810-objs := nau8810.o
snd-soc-nau8824-objs := nau8824.o
@ -126,6 +127,7 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o
snd-soc-rt1305-objs := rt1305.o
snd-soc-rt274-objs := rt274.o
snd-soc-rt286-objs := rt286.o
snd-soc-rt298-objs := rt298.o
@ -140,6 +142,7 @@ snd-soc-rt5659-objs := rt5659.o
snd-soc-rt5660-objs := rt5660.o
snd-soc-rt5663-objs := rt5663.o
snd-soc-rt5665-objs := rt5665.o
snd-soc-rt5668-objs := rt5668.o
snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o
snd-soc-rt5677-spi-objs := rt5677-spi.o
@ -153,6 +156,7 @@ snd-soc-si476x-objs := si476x.o
snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
snd-soc-spdif-tx-objs := spdif_transmitter.o
snd-soc-spdif-rx-objs := spdif_receiver.o
snd-soc-ssm2305-objs := ssm2305.o
snd-soc-ssm2518-objs := ssm2518.o
snd-soc-ssm2602-objs := ssm2602.o
snd-soc-ssm2602-spi-objs := ssm2602-spi.o
@ -180,6 +184,7 @@ snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-tscs42xx-objs := tscs42xx.o
snd-soc-tscs454-objs := tscs454.o
snd-soc-ts3a227e-objs := ts3a227e.o
snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
@ -355,6 +360,7 @@ obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o
obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o
obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o
@ -379,6 +385,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o
@ -394,6 +401,7 @@ obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o
obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o
obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o
obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o
obj-$(CONFIG_SND_SOC_RT5668) += snd-soc-rt5668.o
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
@ -404,6 +412,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o
obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o
obj-$(CONFIG_SND_SOC_SSM2305) += snd-soc-ssm2305.o
obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o
@ -432,6 +441,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TSCS42XX) += snd-soc-tscs42xx.o
obj-$(CONFIG_SND_SOC_TSCS454) += snd-soc-tscs454.o
obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o

View file

@ -843,6 +843,15 @@ int adau17x1_setup_firmware(struct snd_soc_component *component,
struct adau *adau = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
/* Check if sample rate is the same as before. If it is there is no
* point in performing the below steps as the call to
* sigmadsp_setup(...) will return directly when it finds the sample
* rate to be the same as before. By checking this we can prevent an
* audiable popping noise which occours when toggling DSP_RUN.
*/
if (adau->sigmadsp->current_samplerate == rate)
return 0;
snd_soc_dapm_mutex_lock(dapm);
ret = regmap_read(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, &dspsr);

View file

@ -1382,15 +1382,12 @@ static const char *eq_mode_name[] = {"EQ1 Mode", "EQ2 Mode"};
static int max98088_get_channel(struct snd_soc_component *component, const char *name)
{
int i;
int ret;
for (i = 0; i < ARRAY_SIZE(eq_mode_name); i++)
if (strcmp(name, eq_mode_name[i]) == 0)
return i;
/* Shouldn't happen */
dev_err(component->dev, "Bad EQ channel name '%s'\n", name);
return -EINVAL;
ret = match_string(eq_mode_name, ARRAY_SIZE(eq_mode_name), name);
if (ret < 0)
dev_err(component->dev, "Bad EQ channel name '%s'\n", name);
return ret;
}
static void max98088_setup_eq1(struct snd_soc_component *component)

View file

@ -1634,15 +1634,12 @@ static const char *bq_mode_name[] = {"Biquad1 Mode", "Biquad2 Mode"};
static int max98095_get_bq_channel(struct snd_soc_component *component,
const char *name)
{
int i;
int ret;
for (i = 0; i < ARRAY_SIZE(bq_mode_name); i++)
if (strcmp(name, bq_mode_name[i]) == 0)
return i;
/* Shouldn't happen */
dev_err(component->dev, "Bad biquad channel name '%s'\n", name);
return -EINVAL;
ret = match_string(bq_mode_name, ARRAY_SIZE(bq_mode_name), name);
if (ret < 0)
dev_err(component->dev, "Bad biquad channel name '%s'\n", name);
return ret;
}
static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,

View file

@ -1,23 +1,14 @@
/*
* Driver for the MAX9860 Mono Audio Voice Codec
*
* https://datasheets.maximintegrated.com/en/ds/MAX9860.pdf
*
* The driver does not support sidetone since the DVST register field is
* backwards with the mute near the maximum level instead of the minimum.
*
* Author: Peter Rosin <peda@axentia.s>
* Copyright 2016 Axentia Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
// SPDX-License-Identifier: GPL-2.0
//
// Driver for the MAX9860 Mono Audio Voice Codec
//
// https://datasheets.maximintegrated.com/en/ds/MAX9860.pdf
//
// The driver does not support sidetone since the DVST register field is
// backwards with the mute near the maximum level instead of the minimum.
//
// Author: Peter Rosin <peda@axentia.s>
// Copyright 2016 Axentia Technologies
#include <linux/init.h>
#include <linux/module.h>
@ -443,7 +434,8 @@ static int max9860_hw_params(struct snd_pcm_substream *substream,
ret = regmap_update_bits(max9860->regmap, MAX9860_AUDIOCLKHIGH,
MAX9860_PLL, MAX9860_PLL);
if (ret) {
dev_err(component->dev, "Failed to enable PLL: %d\n", ret);
dev_err(component->dev, "Failed to enable PLL: %d\n",
ret);
return ret;
}
}
@ -515,7 +507,8 @@ static int max9860_set_bias_level(struct snd_soc_component *component,
ret = regmap_update_bits(max9860->regmap, MAX9860_PWRMAN,
MAX9860_SHDN, MAX9860_SHDN);
if (ret) {
dev_err(component->dev, "Failed to remove SHDN: %d\n", ret);
dev_err(component->dev, "Failed to remove SHDN: %d\n",
ret);
return ret;
}
break;
@ -598,8 +591,7 @@ static const struct dev_pm_ops max9860_pm_ops = {
SET_RUNTIME_PM_OPS(max9860_suspend, max9860_resume, NULL)
};
static int max9860_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
static int max9860_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct max9860_priv *max9860;
@ -698,7 +690,7 @@ static int max9860_probe(struct i2c_client *i2c,
pm_runtime_idle(dev);
ret = devm_snd_soc_register_component(dev, &max9860_component_driver,
&max9860_dai, 1);
&max9860_dai, 1);
if (ret) {
dev_err(dev, "Failed to register CODEC: %d\n", ret);
goto err_pm;
@ -736,7 +728,7 @@ static const struct of_device_id max9860_of_match[] = {
MODULE_DEVICE_TABLE(of, max9860_of_match);
static struct i2c_driver max9860_i2c_driver = {
.probe = max9860_probe,
.probe_new = max9860_probe,
.remove = max9860_remove,
.id_table = max9860_i2c_id,
.driver = {

View file

@ -1,17 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for the MAX9860 Mono Audio Voice Codec
*
* Author: Peter Rosin <peda@axentia.s>
* Copyright 2016 Axentia Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef _SND_SOC_MAX9860

1505
sound/soc/codecs/mt6351.c Normal file

File diff suppressed because it is too large Load diff

105
sound/soc/codecs/mt6351.h Normal file
View file

@ -0,0 +1,105 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* mt6351.h -- mt6351 ALSA SoC audio codec driver
*
* Copyright (c) 2018 MediaTek Inc.
* Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
*/
#ifndef __MT6351_H__
#define __MT6351_H__
#define MT6351_AFE_UL_DL_CON0 (0x2000 + 0x0000)
#define MT6351_AFE_DL_SRC2_CON0_H (0x2000 + 0x0002)
#define MT6351_AFE_DL_SRC2_CON0_L (0x2000 + 0x0004)
#define MT6351_AFE_DL_SDM_CON0 (0x2000 + 0x0006)
#define MT6351_AFE_DL_SDM_CON1 (0x2000 + 0x0008)
#define MT6351_AFE_UL_SRC_CON0_H (0x2000 + 0x000a)
#define MT6351_AFE_UL_SRC_CON0_L (0x2000 + 0x000c)
#define MT6351_AFE_UL_SRC_CON1_H (0x2000 + 0x000e)
#define MT6351_AFE_UL_SRC_CON1_L (0x2000 + 0x0010)
#define MT6351_AFE_TOP_CON0 (0x2000 + 0x0012)
#define MT6351_AUDIO_TOP_CON0 (0x2000 + 0x0014)
#define MT6351_AFE_DL_SRC_MON0 (0x2000 + 0x0016)
#define MT6351_AFE_DL_SDM_TEST0 (0x2000 + 0x0018)
#define MT6351_AFE_MON_DEBUG0 (0x2000 + 0x001a)
#define MT6351_AFUNC_AUD_CON0 (0x2000 + 0x001c)
#define MT6351_AFUNC_AUD_CON1 (0x2000 + 0x001e)
#define MT6351_AFUNC_AUD_CON2 (0x2000 + 0x0020)
#define MT6351_AFUNC_AUD_CON3 (0x2000 + 0x0022)
#define MT6351_AFUNC_AUD_CON4 (0x2000 + 0x0024)
#define MT6351_AFUNC_AUD_MON0 (0x2000 + 0x0026)
#define MT6351_AFUNC_AUD_MON1 (0x2000 + 0x0028)
#define MT6351_AFE_UP8X_FIFO_CFG0 (0x2000 + 0x002c)
#define MT6351_AFE_UP8X_FIFO_LOG_MON0 (0x2000 + 0x002e)
#define MT6351_AFE_UP8X_FIFO_LOG_MON1 (0x2000 + 0x0030)
#define MT6351_AFE_DL_DC_COMP_CFG0 (0x2000 + 0x0032)
#define MT6351_AFE_DL_DC_COMP_CFG1 (0x2000 + 0x0034)
#define MT6351_AFE_DL_DC_COMP_CFG2 (0x2000 + 0x0036)
#define MT6351_AFE_PMIC_NEWIF_CFG0 (0x2000 + 0x0038)
#define MT6351_AFE_PMIC_NEWIF_CFG1 (0x2000 + 0x003a)
#define MT6351_AFE_PMIC_NEWIF_CFG2 (0x2000 + 0x003c)
#define MT6351_AFE_PMIC_NEWIF_CFG3 (0x2000 + 0x003e)
#define MT6351_AFE_SGEN_CFG0 (0x2000 + 0x0040)
#define MT6351_AFE_SGEN_CFG1 (0x2000 + 0x0042)
#define MT6351_AFE_ADDA2_UP8X_FIFO_LOG_MON0 (0x2000 + 0x004c)
#define MT6351_AFE_ADDA2_UP8X_FIFO_LOG_MON1 (0x2000 + 0x004e)
#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG0 (0x2000 + 0x0050)
#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG1 (0x2000 + 0x0052)
#define MT6351_AFE_ADDA2_PMIC_NEWIF_CFG2 (0x2000 + 0x0054)
#define MT6351_AFE_DCCLK_CFG0 (0x2000 + 0x0090)
#define MT6351_AFE_DCCLK_CFG1 (0x2000 + 0x0092)
#define MT6351_AFE_HPANC_CFG0 (0x2000 + 0x0094)
#define MT6351_AFE_NCP_CFG0 (0x2000 + 0x0096)
#define MT6351_AFE_NCP_CFG1 (0x2000 + 0x0098)
#define MT6351_TOP_CKPDN_CON0 0x023A
#define MT6351_TOP_CKPDN_CON0_SET 0x023C
#define MT6351_TOP_CKPDN_CON0_CLR 0x023E
#define MT6351_TOP_CLKSQ 0x029A
#define MT6351_TOP_CLKSQ_SET 0x029C
#define MT6351_TOP_CLKSQ_CLR 0x029E
#define MT6351_ZCD_CON0 0x0800
#define MT6351_ZCD_CON1 0x0802
#define MT6351_ZCD_CON2 0x0804
#define MT6351_ZCD_CON3 0x0806
#define MT6351_ZCD_CON4 0x0808
#define MT6351_ZCD_CON5 0x080A
#define MT6351_LDO_VA18_CON0 0x0A00
#define MT6351_LDO_VA18_CON1 0x0A02
#define MT6351_LDO_VUSB33_CON0 0x0A16
#define MT6351_LDO_VUSB33_CON1 0x0A18
#define MT6351_AUDDEC_ANA_CON0 0x0CF2
#define MT6351_AUDDEC_ANA_CON1 0x0CF4
#define MT6351_AUDDEC_ANA_CON2 0x0CF6
#define MT6351_AUDDEC_ANA_CON3 0x0CF8
#define MT6351_AUDDEC_ANA_CON4 0x0CFA
#define MT6351_AUDDEC_ANA_CON5 0x0CFC
#define MT6351_AUDDEC_ANA_CON6 0x0CFE
#define MT6351_AUDDEC_ANA_CON7 0x0D00
#define MT6351_AUDDEC_ANA_CON8 0x0D02
#define MT6351_AUDDEC_ANA_CON9 0x0D04
#define MT6351_AUDDEC_ANA_CON10 0x0D06
#define MT6351_AUDENC_ANA_CON0 0x0D08
#define MT6351_AUDENC_ANA_CON1 0x0D0A
#define MT6351_AUDENC_ANA_CON2 0x0D0C
#define MT6351_AUDENC_ANA_CON3 0x0D0E
#define MT6351_AUDENC_ANA_CON4 0x0D10
#define MT6351_AUDENC_ANA_CON5 0x0D12
#define MT6351_AUDENC_ANA_CON6 0x0D14
#define MT6351_AUDENC_ANA_CON7 0x0D16
#define MT6351_AUDENC_ANA_CON8 0x0D18
#define MT6351_AUDENC_ANA_CON9 0x0D1A
#define MT6351_AUDENC_ANA_CON10 0x0D1C
#define MT6351_AUDENC_ANA_CON11 0x0D1E
#define MT6351_AUDENC_ANA_CON12 0x0D20
#define MT6351_AUDENC_ANA_CON13 0x0D22
#define MT6351_AUDENC_ANA_CON14 0x0D24
#define MT6351_AUDENC_ANA_CON15 0x0D26
#define MT6351_AUDENC_ANA_CON16 0x0D28
#endif

View file

@ -373,9 +373,11 @@ static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = {
};
/* PGA Mute */
static const struct snd_kcontrol_new nau8810_inpga_mute[] = {
static const struct snd_kcontrol_new nau8810_pgaboost_mixer_controls[] = {
SOC_DAPM_SINGLE("PGA Mute Switch", NAU8810_REG_PGAGAIN,
NAU8810_PGAMT_SFT, 1, 0),
NAU8810_PGAMT_SFT, 1, 1),
SOC_DAPM_SINGLE("PMIC PGA Switch", NAU8810_REG_ADCBOOST,
NAU8810_PMICBSTGAIN_SFT, 0x7, 0),
};
/* Input PGA */
@ -386,11 +388,6 @@ static const struct snd_kcontrol_new nau8810_inpga[] = {
NAU8810_PMICPGA_SFT, 1, 0),
};
/* Mic Input boost vol */
static const struct snd_kcontrol_new nau8810_mic_boost_controls =
SOC_DAPM_SINGLE("Mic Volume", NAU8810_REG_ADCBOOST,
NAU8810_PMICBSTGAIN_SFT, 0x7, 0);
/* Loopback Switch */
static const struct snd_kcontrol_new nau8810_loopback =
SOC_DAPM_SINGLE("Switch", NAU8810_REG_COMP,
@ -429,8 +426,8 @@ static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = {
NAU8810_PGA_EN_SFT, 0, nau8810_inpga,
ARRAY_SIZE(nau8810_inpga)),
SND_SOC_DAPM_MIXER("Input Boost Stage", NAU8810_REG_POWER2,
NAU8810_BST_EN_SFT, 0, nau8810_inpga_mute,
ARRAY_SIZE(nau8810_inpga_mute)),
NAU8810_BST_EN_SFT, 0, nau8810_pgaboost_mixer_controls,
ARRAY_SIZE(nau8810_pgaboost_mixer_controls)),
SND_SOC_DAPM_SUPPLY("Mic Bias", NAU8810_REG_POWER1,
NAU8810_MICBIAS_EN_SFT, 0, NULL, 0),
@ -469,8 +466,8 @@ static const struct snd_soc_dapm_route nau8810_dapm_routes[] = {
/* Input Boost Stage */
{"ADC", NULL, "Input Boost Stage"},
{"ADC", NULL, "PLL", check_mclk_select_pll},
{"Input Boost Stage", NULL, "Input PGA"},
{"Input Boost Stage", NULL, "MICP"},
{"Input Boost Stage", "PGA Mute Switch", "Input PGA"},
{"Input Boost Stage", "PMIC PGA Switch", "MICP"},
/* Input PGA */
{"Input PGA", NULL, "Mic Bias"},

View file

@ -205,11 +205,11 @@ static int nau8824_sema_acquire(struct nau8824 *nau8824, long timeout)
if (timeout) {
ret = down_timeout(&nau8824->jd_sem, timeout);
if (ret < 0)
dev_warn(nau8824->dev, "Acquire semaphone timeout\n");
dev_warn(nau8824->dev, "Acquire semaphore timeout\n");
} else {
ret = down_interruptible(&nau8824->jd_sem);
if (ret < 0)
dev_warn(nau8824->dev, "Acquire semaphone fail\n");
dev_warn(nau8824->dev, "Acquire semaphore fail\n");
}
return ret;
@ -409,6 +409,15 @@ static const struct snd_kcontrol_new nau8824_snd_controls[] = {
SOC_SINGLE("DACL LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 0, 1, 0),
SOC_SINGLE("DACR LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 1, 1, 0),
SOC_SINGLE("THD for key media",
NAU8824_REG_VDET_THRESHOLD_1, 8, 0xff, 0),
SOC_SINGLE("THD for key voice command",
NAU8824_REG_VDET_THRESHOLD_1, 0, 0xff, 0),
SOC_SINGLE("THD for key volume up",
NAU8824_REG_VDET_THRESHOLD_2, 8, 0xff, 0),
SOC_SINGLE("THD for key volume down",
NAU8824_REG_VDET_THRESHOLD_2, 0, 0xff, 0),
};
static int nau8824_output_dac_event(struct snd_soc_dapm_widget *w,

View file

@ -3,7 +3,7 @@
// Copyright (C) 2018 Bootlin
// Mylène Josserand <mylene.josserand@bootlin.com>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/workqueue.h>

View file

@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include "pcm512x.h"
@ -52,6 +53,7 @@ static const struct i2c_device_id pcm512x_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id pcm512x_of_match[] = {
{ .compatible = "ti,pcm5121", },
{ .compatible = "ti,pcm5122", },
@ -60,6 +62,18 @@ static const struct of_device_id pcm512x_of_match[] = {
{ }
};
MODULE_DEVICE_TABLE(of, pcm512x_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id pcm512x_acpi_match[] = {
{ "104C5121", 0 },
{ "104C5122", 0 },
{ "104C5141", 0 },
{ "104C5142", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, pcm512x_acpi_match);
#endif
static struct i2c_driver pcm512x_i2c_driver = {
.probe = pcm512x_i2c_probe,
@ -67,7 +81,8 @@ static struct i2c_driver pcm512x_i2c_driver = {
.id_table = pcm512x_i2c_id,
.driver = {
.name = "pcm512x",
.of_match_table = pcm512x_of_match,
.of_match_table = of_match_ptr(pcm512x_of_match),
.acpi_match_table = ACPI_PTR(pcm512x_acpi_match),
.pm = &pcm512x_pm_ops,
},
};

1191
sound/soc/codecs/rt1305.c Normal file

File diff suppressed because it is too large Load diff

276
sound/soc/codecs/rt1305.h Normal file
View file

@ -0,0 +1,276 @@
/*
* RT1305.h -- RT1305 ALSA SoC amplifier component driver
*
* Copyright 2018 Realtek Semiconductor Corp.
* Author: Shuming Fan <shumingf@realtek.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 _RT1305_H_
#define _RT1305_H_
#define RT1305_DEVICE_ID_NUM 0x6251
#define RT1305_RESET 0x00
#define RT1305_CLK_1 0x04
#define RT1305_CLK_2 0x05
#define RT1305_CLK_3 0x06
#define RT1305_DFLL_REG 0x07
#define RT1305_CAL_EFUSE_CLOCK 0x08
#define RT1305_PLL0_1 0x0a
#define RT1305_PLL0_2 0x0b
#define RT1305_PLL1_1 0x0c
#define RT1305_PLL1_2 0x0d
#define RT1305_MIXER_CTRL_1 0x10
#define RT1305_MIXER_CTRL_2 0x11
#define RT1305_DAC_SET_1 0x12
#define RT1305_DAC_SET_2 0x14
#define RT1305_ADC_SET_1 0x16
#define RT1305_ADC_SET_2 0x17
#define RT1305_ADC_SET_3 0x18
#define RT1305_PATH_SET 0x20
#define RT1305_SPDIF_IN_SET_1 0x22
#define RT1305_SPDIF_IN_SET_2 0x24
#define RT1305_SPDIF_IN_SET_3 0x26
#define RT1305_SPDIF_OUT_SET_1 0x28
#define RT1305_SPDIF_OUT_SET_2 0x2a
#define RT1305_SPDIF_OUT_SET_3 0x2b
#define RT1305_I2S_SET_1 0x2d
#define RT1305_I2S_SET_2 0x2e
#define RT1305_PBTL_MONO_MODE_SRC 0x2f
#define RT1305_MANUALLY_I2C_DEVICE 0x32
#define RT1305_POWER_STATUS 0x39
#define RT1305_POWER_CTRL_1 0x3a
#define RT1305_POWER_CTRL_2 0x3b
#define RT1305_POWER_CTRL_3 0x3c
#define RT1305_POWER_CTRL_4 0x3d
#define RT1305_POWER_CTRL_5 0x3e
#define RT1305_CLOCK_DETECT 0x3f
#define RT1305_BIQUAD_SET_1 0x40
#define RT1305_BIQUAD_SET_2 0x42
#define RT1305_ADJUSTED_HPF_1 0x46
#define RT1305_ADJUSTED_HPF_2 0x47
#define RT1305_EQ_SET_1 0x4b
#define RT1305_EQ_SET_2 0x4c
#define RT1305_SPK_TEMP_PROTECTION_0 0x4f
#define RT1305_SPK_TEMP_PROTECTION_1 0x50
#define RT1305_SPK_TEMP_PROTECTION_2 0x51
#define RT1305_SPK_TEMP_PROTECTION_3 0x52
#define RT1305_SPK_DC_DETECT_1 0x53
#define RT1305_SPK_DC_DETECT_2 0x54
#define RT1305_LOUDNESS 0x58
#define RT1305_THERMAL_FOLD_BACK_1 0x5e
#define RT1305_THERMAL_FOLD_BACK_2 0x5f
#define RT1305_SILENCE_DETECT 0x60
#define RT1305_ALC_DRC_1 0x62
#define RT1305_ALC_DRC_2 0x63
#define RT1305_ALC_DRC_3 0x64
#define RT1305_ALC_DRC_4 0x65
#define RT1305_PRIV_INDEX 0x6a
#define RT1305_PRIV_DATA 0x6c
#define RT1305_SPK_EXCURSION_LIMITER_7 0x76
#define RT1305_VERSION_ID 0x7a
#define RT1305_VENDOR_ID 0x7c
#define RT1305_DEVICE_ID 0x7e
#define RT1305_EFUSE_1 0x80
#define RT1305_EFUSE_2 0x81
#define RT1305_EFUSE_3 0x82
#define RT1305_DC_CALIB_1 0x90
#define RT1305_DC_CALIB_2 0x91
#define RT1305_DC_CALIB_3 0x92
#define RT1305_DAC_OFFSET_1 0x93
#define RT1305_DAC_OFFSET_2 0x94
#define RT1305_DAC_OFFSET_3 0x95
#define RT1305_DAC_OFFSET_4 0x96
#define RT1305_DAC_OFFSET_5 0x97
#define RT1305_DAC_OFFSET_6 0x98
#define RT1305_DAC_OFFSET_7 0x99
#define RT1305_DAC_OFFSET_8 0x9a
#define RT1305_DAC_OFFSET_9 0x9b
#define RT1305_DAC_OFFSET_10 0x9c
#define RT1305_DAC_OFFSET_11 0x9d
#define RT1305_DAC_OFFSET_12 0x9e
#define RT1305_DAC_OFFSET_13 0x9f
#define RT1305_DAC_OFFSET_14 0xa0
#define RT1305_TRIM_1 0xb0
#define RT1305_TRIM_2 0xb1
#define RT1305_TUNE_INTERNAL_OSC 0xb2
#define RT1305_BIQUAD1_H0_L_28_16 0xc0
#define RT1305_BIQUAD3_A2_R_15_0 0xfb
#define RT1305_MAX_REG 0xff
/* CLOCK-1 (0x04) */
#define RT1305_SEL_PLL_SRC_2_MASK (0x1 << 15)
#define RT1305_SEL_PLL_SRC_2_SFT 15
#define RT1305_SEL_PLL_SRC_2_MCLK (0x0 << 15)
#define RT1305_SEL_PLL_SRC_2_RCCLK (0x1 << 15)
#define RT1305_DIV_PLL_SRC_2_MASK (0x3 << 13)
#define RT1305_DIV_PLL_SRC_2_SFT 13
#define RT1305_SEL_PLL_SRC_1_MASK (0x3 << 10)
#define RT1305_SEL_PLL_SRC_1_SFT 10
#define RT1305_SEL_PLL_SRC_1_PLL2 (0x0 << 10)
#define RT1305_SEL_PLL_SRC_1_BCLK (0x1 << 10)
#define RT1305_SEL_PLL_SRC_1_DFLL (0x2 << 10)
#define RT1305_SEL_FS_SYS_PRE_MASK (0x3 << 8)
#define RT1305_SEL_FS_SYS_PRE_SFT 8
#define RT1305_SEL_FS_SYS_PRE_MCLK (0x0 << 8)
#define RT1305_SEL_FS_SYS_PRE_PLL (0x1 << 8)
#define RT1305_SEL_FS_SYS_PRE_RCCLK (0x2 << 8)
#define RT1305_DIV_FS_SYS_MASK (0x7 << 4)
#define RT1305_DIV_FS_SYS_SFT 4
/* PLL1M/N/K Code-1 (0x0c) */
#define RT1305_PLL_1_M_SFT 12
#define RT1305_PLL_1_M_BYPASS_MASK (0x1 << 11)
#define RT1305_PLL_1_M_BYPASS_SFT 11
#define RT1305_PLL_1_M_BYPASS (0x1 << 11)
#define RT1305_PLL_1_N_MASK (0x1ff << 0)
/* DAC Setting (0x14) */
#define RT1305_DVOL_MUTE_L_EN_SFT 15
#define RT1305_DVOL_MUTE_R_EN_SFT 14
/* I2S Setting-1 (0x2d) */
#define RT1305_SEL_I2S_OUT_MODE_MASK (0x1 << 15)
#define RT1305_SEL_I2S_OUT_MODE_SFT 15
#define RT1305_SEL_I2S_OUT_MODE_S (0x0 << 15)
#define RT1305_SEL_I2S_OUT_MODE_M (0x1 << 15)
/* I2S Setting-2 (0x2e) */
#define RT1305_I2S_DF_SEL_MASK (0x3 << 12)
#define RT1305_I2S_DF_SEL_SFT 12
#define RT1305_I2S_DF_SEL_I2S (0x0 << 12)
#define RT1305_I2S_DF_SEL_LEFT (0x1 << 12)
#define RT1305_I2S_DF_SEL_PCM_A (0x2 << 12)
#define RT1305_I2S_DF_SEL_PCM_B (0x3 << 12)
#define RT1305_I2S_DL_SEL_MASK (0x3 << 10)
#define RT1305_I2S_DL_SEL_SFT 10
#define RT1305_I2S_DL_SEL_16B (0x0 << 10)
#define RT1305_I2S_DL_SEL_20B (0x1 << 10)
#define RT1305_I2S_DL_SEL_24B (0x2 << 10)
#define RT1305_I2S_DL_SEL_8B (0x3 << 10)
#define RT1305_I2S_BCLK_MASK (0x1 << 9)
#define RT1305_I2S_BCLK_SFT 9
#define RT1305_I2S_BCLK_NORMAL (0x0 << 9)
#define RT1305_I2S_BCLK_INV (0x1 << 9)
/* Power Control-1 (0x3a) */
#define RT1305_POW_PDB_JD_MASK (0x1 << 12)
#define RT1305_POW_PDB_JD (0x1 << 12)
#define RT1305_POW_PDB_JD_BIT 12
#define RT1305_POW_PLL0_EN (0x1 << 11)
#define RT1305_POW_PLL0_EN_BIT 11
#define RT1305_POW_PLL1_EN (0x1 << 10)
#define RT1305_POW_PLL1_EN_BIT 10
#define RT1305_POW_PDB_JD_POLARITY (0x1 << 9)
#define RT1305_POW_PDB_JD_POLARITY_BIT 9
#define RT1305_POW_MBIAS_LV (0x1 << 8)
#define RT1305_POW_MBIAS_LV_BIT 8
#define RT1305_POW_BG_MBIAS_LV (0x1 << 7)
#define RT1305_POW_BG_MBIAS_LV_BIT 7
#define RT1305_POW_LDO2 (0x1 << 6)
#define RT1305_POW_LDO2_BIT 6
#define RT1305_POW_BG2 (0x1 << 5)
#define RT1305_POW_BG2_BIT 5
#define RT1305_POW_LDO2_IB2 (0x1 << 4)
#define RT1305_POW_LDO2_IB2_BIT 4
#define RT1305_POW_VREF (0x1 << 3)
#define RT1305_POW_VREF_BIT 3
#define RT1305_POW_VREF1 (0x1 << 2)
#define RT1305_POW_VREF1_BIT 2
#define RT1305_POW_VREF2 (0x1 << 1)
#define RT1305_POW_VREF2_BIT 1
/* Power Control-2 (0x3b) */
#define RT1305_POW_DISC_VREF (1 << 15)
#define RT1305_POW_DISC_VREF_BIT 15
#define RT1305_POW_FASTB_VREF (1 << 14)
#define RT1305_POW_FASTB_VREF_BIT 14
#define RT1305_POW_ULTRA_FAST_VREF (1 << 13)
#define RT1305_POW_ULTRA_FAST_VREF_BIT 13
#define RT1305_POW_CKXEN_DAC (1 << 12)
#define RT1305_POW_CKXEN_DAC_BIT 12
#define RT1305_POW_EN_CKGEN_DAC (1 << 11)
#define RT1305_POW_EN_CKGEN_DAC_BIT 11
#define RT1305_POW_DAC1_L (1 << 10)
#define RT1305_POW_DAC1_L_BIT 10
#define RT1305_POW_DAC1_R (1 << 9)
#define RT1305_POW_DAC1_R_BIT 9
#define RT1305_POW_CLAMP (1 << 8)
#define RT1305_POW_CLAMP_BIT 8
#define RT1305_POW_BUFL (1 << 7)
#define RT1305_POW_BUFL_BIT 7
#define RT1305_POW_BUFR (1 << 6)
#define RT1305_POW_BUFR_BIT 6
#define RT1305_POW_EN_CKGEN_ADC (1 << 5)
#define RT1305_POW_EN_CKGEN_ADC_BIT 5
#define RT1305_POW_ADC3_L (1 << 4)
#define RT1305_POW_ADC3_L_BIT 4
#define RT1305_POW_ADC3_R (1 << 3)
#define RT1305_POW_ADC3_R_BIT 3
#define RT1305_POW_TRIOSC (1 << 2)
#define RT1305_POW_TRIOSC_BIT 2
#define RT1305_POR_AVDD1 (1 << 1)
#define RT1305_POR_AVDD1_BIT 1
#define RT1305_POR_AVDD2 (1 << 0)
#define RT1305_POR_AVDD2_BIT 0
/* Power Control-3 (0x3c) */
#define RT1305_POW_VSENSE_RCH (1 << 15)
#define RT1305_POW_VSENSE_RCH_BIT 15
#define RT1305_POW_VSENSE_LCH (1 << 14)
#define RT1305_POW_VSENSE_LCH_BIT 14
#define RT1305_POW_ISENSE_RCH (1 << 13)
#define RT1305_POW_ISENSE_RCH_BIT 13
#define RT1305_POW_ISENSE_LCH (1 << 12)
#define RT1305_POW_ISENSE_LCH_BIT 12
#define RT1305_POW_POR_AVDD1 (1 << 11)
#define RT1305_POW_POR_AVDD1_BIT 11
#define RT1305_POW_POR_AVDD2 (1 << 10)
#define RT1305_POW_POR_AVDD2_BIT 10
#define RT1305_EN_K_HV (1 << 9)
#define RT1305_EN_K_HV_BIT 9
#define RT1305_EN_PRE_K_HV (1 << 8)
#define RT1305_EN_PRE_K_HV_BIT 8
#define RT1305_EN_EFUSE_1P8V (1 << 7)
#define RT1305_EN_EFUSE_1P8V_BIT 7
#define RT1305_EN_EFUSE_5V (1 << 6)
#define RT1305_EN_EFUSE_5V_BIT 6
#define RT1305_EN_VCM_6172 (1 << 5)
#define RT1305_EN_VCM_6172_BIT 5
#define RT1305_POR_EFUSE (1 << 4)
#define RT1305_POR_EFUSE_BIT 4
/* Clock Detect (0x3f) */
#define RT1305_SEL_CLK_DET_SRC_MASK (0x1 << 12)
#define RT1305_SEL_CLK_DET_SRC_SFT 12
#define RT1305_SEL_CLK_DET_SRC_MCLK (0x0 << 12)
#define RT1305_SEL_CLK_DET_SRC_BCLK (0x1 << 12)
/* System Clock Source */
enum {
RT1305_FS_SYS_PRE_S_MCLK,
RT1305_FS_SYS_PRE_S_PLL1,
RT1305_FS_SYS_PRE_S_RCCLK, /* 98.304M Hz */
};
/* PLL Source 1/2 */
enum {
RT1305_PLL1_S_BCLK,
RT1305_PLL2_S_MCLK,
RT1305_PLL2_S_RCCLK, /* 98.304M Hz */
};
enum {
RT1305_AIF1,
RT1305_AIFS
};
#define R0_UPPER 0x2E8BA2 //5.5 ohm
#define R0_LOWER 0x666666 //2.5 ohm
#endif /* end of _RT1305_H_ */

View file

@ -24,6 +24,7 @@
#include <linux/spi/spi.h>
#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@ -476,20 +477,6 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
return idx;
}
static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
unsigned int val;
val = snd_soc_component_read32(component, RT5640_GLB_CLK);
val &= RT5640_SCLK_SRC_MASK;
if (val == RT5640_SCLK_SRC_PLL1)
return 1;
else
return 0;
}
static int is_using_asrc(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
@ -1071,9 +1058,6 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
}
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
RT5640_PWR_PLL_BIT, 0, NULL, 0),
/* ASRC */
SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1,
15, 0, NULL, 0),
@ -1427,22 +1411,18 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},
{"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},
{"Stereo ADC MIXL", NULL, "Stereo Filter"},
{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},
{"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},
{"Stereo ADC MIXR", NULL, "Stereo Filter"},
{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
{"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
{"Mono ADC MIXL", NULL, "Mono Left Filter"},
{"Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
{"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
{"Mono ADC MIXR", NULL, "Mono Right Filter"},
{"Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll},
{"IF2 ADC L", NULL, "Mono ADC MIXL"},
{"IF2 ADC R", NULL, "Mono ADC MIXR"},
@ -1512,10 +1492,8 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
{"DAC L1", NULL, "Stereo DAC MIXL"},
{"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},
{"DAC L1", NULL, "DAC L1 Power"},
{"DAC R1", NULL, "Stereo DAC MIXR"},
{"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},
{"DAC R1", NULL, "DAC R1 Power"},
{"SPK MIXL", "REC MIXL Switch", "RECMIXL"},
@ -1622,10 +1600,8 @@ static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = {
{"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
{"DAC L2", NULL, "Mono DAC MIXL"},
{"DAC L2", NULL, "PLL1", is_sys_clk_from_pll},
{"DAC L2", NULL, "DAC L2 Power"},
{"DAC R2", NULL, "Mono DAC MIXR"},
{"DAC R2", NULL, "PLL1", is_sys_clk_from_pll},
{"DAC R2", NULL, "DAC R2 Power"},
{"SPK MIXL", "DAC L2 Switch", "DAC L2"},
@ -1861,6 +1837,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
struct snd_soc_component *component = dai->component;
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
unsigned int reg_val = 0;
unsigned int pll_bit = 0;
if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src)
return 0;
@ -1871,6 +1848,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
break;
case RT5640_SCLK_S_PLL1:
reg_val |= RT5640_SCLK_SRC_PLL1;
pll_bit |= RT5640_PWR_PLL;
break;
case RT5640_SCLK_S_RCCLK:
reg_val |= RT5640_SCLK_SRC_RCCLK;
@ -1879,6 +1857,8 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
return -EINVAL;
}
snd_soc_component_update_bits(component, RT5640_PWR_ANLG2,
RT5640_PWR_PLL, pll_bit);
snd_soc_component_update_bits(component, RT5640_GLB_CLK,
RT5640_SCLK_SRC_MASK, reg_val);
rt5640->sysclk = freq;
@ -2114,10 +2094,376 @@ int rt5640_sel_asrc_clk_src(struct snd_soc_component *component,
}
EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);
static void rt5640_enable_micbias1_for_ovcd(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2");
snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS1");
/* OVCD is unreliable when used with RCCLK as sysclk-source */
snd_soc_dapm_force_enable_pin_unlocked(dapm, "Platform Clock");
snd_soc_dapm_sync_unlocked(dapm);
snd_soc_dapm_mutex_unlock(dapm);
}
static void rt5640_disable_micbias1_for_ovcd(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
snd_soc_dapm_mutex_lock(dapm);
snd_soc_dapm_disable_pin_unlocked(dapm, "Platform Clock");
snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS1");
snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2");
snd_soc_dapm_sync_unlocked(dapm);
snd_soc_dapm_mutex_unlock(dapm);
}
static void rt5640_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_NOR);
rt5640->ovcd_irq_enabled = true;
}
static void rt5640_disable_micbias1_ovcd_irq(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
RT5640_IRQ_MB1_OC_MASK, RT5640_IRQ_MB1_OC_BP);
rt5640->ovcd_irq_enabled = false;
}
static void rt5640_clear_micbias1_ovcd(struct snd_soc_component *component)
{
snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
RT5640_MB1_OC_STATUS, 0);
}
static bool rt5640_micbias1_ovcd(struct snd_soc_component *component)
{
int val;
val = snd_soc_component_read32(component, RT5640_IRQ_CTRL2);
dev_dbg(component->dev, "irq ctrl2 %#04x\n", val);
return (val & RT5640_MB1_OC_STATUS);
}
static bool rt5640_jack_inserted(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
int val;
val = snd_soc_component_read32(component, RT5640_INT_IRQ_ST);
dev_dbg(component->dev, "irq status %#04x\n", val);
if (rt5640->jd_inverted)
return !(val & RT5640_JD_STATUS);
else
return (val & RT5640_JD_STATUS);
}
/* Jack detect and button-press timings */
#define JACK_SETTLE_TIME 100 /* milli seconds */
#define JACK_DETECT_COUNT 5
#define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */
#define JACK_UNPLUG_TIME 80 /* milli seconds */
#define BP_POLL_TIME 10 /* milli seconds */
#define BP_POLL_MAXCOUNT 200 /* assume something is wrong after this */
#define BP_THRESHOLD 3
static void rt5640_start_button_press_work(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
rt5640->poll_count = 0;
rt5640->press_count = 0;
rt5640->release_count = 0;
rt5640->pressed = false;
rt5640->press_reported = false;
rt5640_clear_micbias1_ovcd(component);
schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME));
}
static void rt5640_button_press_work(struct work_struct *work)
{
struct rt5640_priv *rt5640 =
container_of(work, struct rt5640_priv, bp_work.work);
struct snd_soc_component *component = rt5640->component;
/* Check the jack was not removed underneath us */
if (!rt5640_jack_inserted(component))
return;
if (rt5640_micbias1_ovcd(component)) {
rt5640->release_count = 0;
rt5640->press_count++;
/* Remember till after JACK_UNPLUG_TIME wait */
if (rt5640->press_count >= BP_THRESHOLD)
rt5640->pressed = true;
rt5640_clear_micbias1_ovcd(component);
} else {
rt5640->press_count = 0;
rt5640->release_count++;
}
/*
* The pins get temporarily shorted on jack unplug, so we poll for
* at least JACK_UNPLUG_TIME milli-seconds before reporting a press.
*/
rt5640->poll_count++;
if (rt5640->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) {
schedule_delayed_work(&rt5640->bp_work,
msecs_to_jiffies(BP_POLL_TIME));
return;
}
if (rt5640->pressed && !rt5640->press_reported) {
dev_dbg(component->dev, "headset button press\n");
snd_soc_jack_report(rt5640->jack, SND_JACK_BTN_0,
SND_JACK_BTN_0);
rt5640->press_reported = true;
}
if (rt5640->release_count >= BP_THRESHOLD) {
if (rt5640->press_reported) {
dev_dbg(component->dev, "headset button release\n");
snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
}
/* Re-enable OVCD IRQ to detect next press */
rt5640_enable_micbias1_ovcd_irq(component);
return; /* Stop polling */
}
schedule_delayed_work(&rt5640->bp_work, msecs_to_jiffies(BP_POLL_TIME));
}
static int rt5640_detect_headset(struct snd_soc_component *component)
{
int i, headset_count = 0, headphone_count = 0;
/*
* We get the insertion event before the jack is fully inserted at which
* point the second ring on a TRRS connector may short the 2nd ring and
* sleeve contacts, also the overcurrent detection is not entirely
* reliable. So we try several times with a wait in between until we
* detect the same type JACK_DETECT_COUNT times in a row.
*/
for (i = 0; i < JACK_DETECT_MAXCOUNT; i++) {
/* Clear any previous over-current status flag */
rt5640_clear_micbias1_ovcd(component);
msleep(JACK_SETTLE_TIME);
/* Check the jack is still connected before checking ovcd */
if (!rt5640_jack_inserted(component))
return 0;
if (rt5640_micbias1_ovcd(component)) {
/*
* Over current detected, there is a short between the
* 2nd ring contact and the ground, so a TRS connector
* without a mic contact and thus plain headphones.
*/
dev_dbg(component->dev, "jack mic-gnd shorted\n");
headset_count = 0;
headphone_count++;
if (headphone_count == JACK_DETECT_COUNT)
return SND_JACK_HEADPHONE;
} else {
dev_dbg(component->dev, "jack mic-gnd open\n");
headphone_count = 0;
headset_count++;
if (headset_count == JACK_DETECT_COUNT)
return SND_JACK_HEADSET;
}
}
dev_err(component->dev, "Error detecting headset vs headphones, bad contact?, assuming headphones\n");
return SND_JACK_HEADPHONE;
}
static void rt5640_jack_work(struct work_struct *work)
{
struct rt5640_priv *rt5640 =
container_of(work, struct rt5640_priv, jack_work);
struct snd_soc_component *component = rt5640->component;
int status;
if (!rt5640_jack_inserted(component)) {
/* Jack removed, or spurious IRQ? */
if (rt5640->jack->status & SND_JACK_HEADPHONE) {
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
cancel_delayed_work_sync(&rt5640->bp_work);
rt5640_disable_micbias1_ovcd_irq(component);
rt5640_disable_micbias1_for_ovcd(component);
}
snd_soc_jack_report(rt5640->jack, 0,
SND_JACK_HEADSET | SND_JACK_BTN_0);
dev_dbg(component->dev, "jack unplugged\n");
}
} else if (!(rt5640->jack->status & SND_JACK_HEADPHONE)) {
/* Jack inserted */
WARN_ON(rt5640->ovcd_irq_enabled);
rt5640_enable_micbias1_for_ovcd(component);
status = rt5640_detect_headset(component);
if (status == SND_JACK_HEADSET) {
/* Enable ovcd IRQ for button press detect. */
rt5640_enable_micbias1_ovcd_irq(component);
} else {
/* No more need for overcurrent detect. */
rt5640_disable_micbias1_for_ovcd(component);
}
dev_dbg(component->dev, "detect status %#02x\n", status);
snd_soc_jack_report(rt5640->jack, status, SND_JACK_HEADSET);
} else if (rt5640->ovcd_irq_enabled && rt5640_micbias1_ovcd(component)) {
dev_dbg(component->dev, "OVCD IRQ\n");
/*
* The ovcd IRQ keeps firing while the button is pressed, so
* we disable it and start polling the button until released.
*
* The disable will make the IRQ pin 0 again and since we get
* IRQs on both edges (so as to detect both jack plugin and
* unplug) this means we will immediately get another IRQ.
* The ovcd_irq_enabled check above makes the 2ND IRQ a NOP.
*/
rt5640_disable_micbias1_ovcd_irq(component);
rt5640_start_button_press_work(component);
/*
* If the jack-detect IRQ flag goes high (unplug) after our
* above rt5640_jack_inserted() check and before we have
* disabled the OVCD IRQ, the IRQ pin will stay high and as
* we react to edges, we miss the unplug event -> recheck.
*/
queue_work(system_long_wq, &rt5640->jack_work);
}
}
static irqreturn_t rt5640_irq(int irq, void *data)
{
struct rt5640_priv *rt5640 = data;
if (rt5640->jack)
queue_work(system_long_wq, &rt5640->jack_work);
return IRQ_HANDLED;
}
static void rt5640_cancel_work(void *data)
{
struct rt5640_priv *rt5640 = data;
cancel_work_sync(&rt5640->jack_work);
cancel_delayed_work_sync(&rt5640->bp_work);
}
static void rt5640_enable_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
/* Select JD-source */
snd_soc_component_update_bits(component, RT5640_JD_CTRL,
RT5640_JD_MASK, rt5640->jd_src);
/* Selecting GPIO01 as an interrupt */
snd_soc_component_update_bits(component, RT5640_GPIO_CTRL1,
RT5640_GP1_PIN_MASK, RT5640_GP1_PIN_IRQ);
/* Set GPIO1 output */
snd_soc_component_update_bits(component, RT5640_GPIO_CTRL3,
RT5640_GP1_PF_MASK, RT5640_GP1_PF_OUT);
/* Enabling jd2 in general control 1 */
snd_soc_component_write(component, RT5640_DUMMY1, 0x3f41);
/* Enabling jd2 in general control 2 */
snd_soc_component_write(component, RT5640_DUMMY2, 0x4001);
snd_soc_component_write(component, RT5640_PR_BASE + RT5640_BIAS_CUR4,
0xa800 | rt5640->ovcd_sf);
snd_soc_component_update_bits(component, RT5640_MICBIAS,
RT5640_MIC1_OVTH_MASK | RT5640_MIC1_OVCD_MASK,
rt5640->ovcd_th | RT5640_MIC1_OVCD_EN);
/*
* The over-current-detect is only reliable in detecting the absence
* of over-current, when the mic-contact in the jack is short-circuited,
* the hardware periodically retries if it can apply the bias-current
* leading to the ovcd status flip-flopping 1-0-1 with it being 0 about
* 10% of the time, as we poll the ovcd status bit we might hit that
* 10%, so we enable sticky mode and when checking OVCD we clear the
* status, msleep() a bit and then check to get a reliable reading.
*/
snd_soc_component_update_bits(component, RT5640_IRQ_CTRL2,
RT5640_MB1_OC_STKY_MASK, RT5640_MB1_OC_STKY_EN);
/*
* All IRQs get or-ed together, so we need the jack IRQ to report 0
* when a jack is inserted so that the OVCD IRQ then toggles the IRQ
* pin 0/1 instead of it being stuck to 1. So we invert the JD polarity
* on systems where the hardware does not already do this.
*/
if (rt5640->jd_inverted)
snd_soc_component_write(component, RT5640_IRQ_CTRL1,
RT5640_IRQ_JD_NOR);
else
snd_soc_component_write(component, RT5640_IRQ_CTRL1,
RT5640_IRQ_JD_NOR | RT5640_JD_P_INV);
rt5640->jack = jack;
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
rt5640_enable_micbias1_for_ovcd(component);
rt5640_enable_micbias1_ovcd_irq(component);
}
enable_irq(rt5640->irq);
/* sync initial jack state */
queue_work(system_long_wq, &rt5640->jack_work);
}
static void rt5640_disable_jack_detect(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
disable_irq(rt5640->irq);
rt5640_cancel_work(rt5640);
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
rt5640_disable_micbias1_ovcd_irq(component);
rt5640_disable_micbias1_for_ovcd(component);
snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
}
rt5640->jack = NULL;
}
static int rt5640_set_jack(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *data)
{
if (jack)
rt5640_enable_jack_detect(component, jack);
else
rt5640_disable_jack_detect(component);
return 0;
}
static int rt5640_probe(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
u32 dmic1_data_pin = 0;
u32 dmic2_data_pin = 0;
bool dmic_en = false;
u32 val;
/* Check if MCLK provided */
rt5640->mclk = devm_clk_get(component->dev, "mclk");
@ -2159,9 +2505,86 @@ static int rt5640_probe(struct snd_soc_component *component)
return -ENODEV;
}
if (rt5640->pdata.dmic_en)
rt5640_dmic_enable(component, rt5640->pdata.dmic1_data_pin,
rt5640->pdata.dmic2_data_pin);
/*
* Note on some platforms the platform code may need to add device-props
* rather then relying only on properties set by the firmware.
* Therefor the property parsing MUST be done here, rather then from
* rt5640_i2c_probe(), so that the platform-code can attach extra
* properties before calling snd_soc_register_card().
*/
if (device_property_read_bool(component->dev, "realtek,in1-differential"))
snd_soc_component_update_bits(component, RT5640_IN1_IN2,
RT5640_IN_DF1, RT5640_IN_DF1);
if (device_property_read_bool(component->dev, "realtek,in2-differential"))
snd_soc_component_update_bits(component, RT5640_IN3_IN4,
RT5640_IN_DF2, RT5640_IN_DF2);
if (device_property_read_bool(component->dev, "realtek,in3-differential"))
snd_soc_component_update_bits(component, RT5640_IN1_IN2,
RT5640_IN_DF2, RT5640_IN_DF2);
if (device_property_read_u32(component->dev, "realtek,dmic1-data-pin",
&val) == 0 && val) {
dmic1_data_pin = val - 1;
dmic_en = true;
}
if (device_property_read_u32(component->dev, "realtek,dmic2-data-pin",
&val) == 0 && val) {
dmic2_data_pin = val - 1;
dmic_en = true;
}
if (dmic_en)
rt5640_dmic_enable(component, dmic1_data_pin, dmic2_data_pin);
if (device_property_read_u32(component->dev,
"realtek,jack-detect-source", &val) == 0) {
if (val <= RT5640_JD_SRC_GPIO4)
rt5640->jd_src = val << RT5640_JD_SFT;
else
dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n",
val);
}
if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted"))
rt5640->jd_inverted = true;
/*
* Testing on various boards has shown that good defaults for the OVCD
* threshold and scale-factor are 2000µA and 0.75. For an effective
* limit of 1500µA, this seems to be more reliable then 1500µA and 1.0.
*/
rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA;
rt5640->ovcd_sf = RT5640_MIC_OVCD_SF_0P75;
if (device_property_read_u32(component->dev,
"realtek,over-current-threshold-microamp", &val) == 0) {
switch (val) {
case 600:
rt5640->ovcd_th = RT5640_MIC1_OVTH_600UA;
break;
case 1500:
rt5640->ovcd_th = RT5640_MIC1_OVTH_1500UA;
break;
case 2000:
rt5640->ovcd_th = RT5640_MIC1_OVTH_2000UA;
break;
default:
dev_warn(component->dev, "Warning: Invalid over-current-threshold-microamp value: %d, defaulting to 2000uA\n",
val);
}
}
if (device_property_read_u32(component->dev,
"realtek,over-current-scale-factor", &val) == 0) {
if (val <= RT5640_OVCD_SF_1P5)
rt5640->ovcd_sf = val << RT5640_MIC_OVCD_SF_SFT;
else
dev_warn(component->dev, "Warning: Invalid over-current-scale-factor value: %d, defaulting to 0.75\n",
val);
}
return 0;
}
@ -2180,8 +2603,8 @@ static int rt5640_suspend(struct snd_soc_component *component)
rt5640_reset(component);
regcache_cache_only(rt5640->regmap, true);
regcache_mark_dirty(rt5640->regmap);
if (gpio_is_valid(rt5640->pdata.ldo1_en))
gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0);
if (gpio_is_valid(rt5640->ldo1_en))
gpio_set_value_cansleep(rt5640->ldo1_en, 0);
return 0;
}
@ -2190,8 +2613,8 @@ static int rt5640_resume(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1);
if (gpio_is_valid(rt5640->ldo1_en)) {
gpio_set_value_cansleep(rt5640->ldo1_en, 1);
msleep(400);
}
@ -2263,6 +2686,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = {
.suspend = rt5640_suspend,
.resume = rt5640_resume,
.set_bias_level = rt5640_set_bias_level,
.set_jack = rt5640_set_jack,
.controls = rt5640_snd_controls,
.num_controls = ARRAY_SIZE(rt5640_snd_controls),
.dapm_widgets = rt5640_dapm_widgets,
@ -2323,22 +2747,16 @@ MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
{
rt5640->pdata.in1_diff = of_property_read_bool(np,
"realtek,in1-differential");
rt5640->pdata.in2_diff = of_property_read_bool(np,
"realtek,in2-differential");
rt5640->pdata.ldo1_en = of_get_named_gpio(np,
"realtek,ldo1-en-gpios", 0);
rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0);
/*
* LDO1_EN is optional (it may be statically tied on the board).
* -ENOENT means that the property doesn't exist, i.e. there is no
* GPIO, so is not an error. Any other error code means the property
* exists, but could not be parsed.
*/
if (!gpio_is_valid(rt5640->pdata.ldo1_en) &&
(rt5640->pdata.ldo1_en != -ENOENT))
return rt5640->pdata.ldo1_en;
if (!gpio_is_valid(rt5640->ldo1_en) &&
(rt5640->ldo1_en != -ENOENT))
return rt5640->ldo1_en;
return 0;
}
@ -2346,7 +2764,6 @@ static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
static int rt5640_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct rt5640_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct rt5640_priv *rt5640;
int ret;
unsigned int val;
@ -2358,22 +2775,12 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, rt5640);
if (pdata) {
rt5640->pdata = *pdata;
/*
* Translate zero'd out (default) pdata value to an invalid
* GPIO ID. This makes the pdata and DT paths consistent in
* terms of the value left in this field when no GPIO is
* specified, but means we can't actually use GPIO 0.
*/
if (!rt5640->pdata.ldo1_en)
rt5640->pdata.ldo1_en = -EINVAL;
} else if (i2c->dev.of_node) {
if (i2c->dev.of_node) {
ret = rt5640_parse_dt(rt5640, i2c->dev.of_node);
if (ret)
return ret;
} else
rt5640->pdata.ldo1_en = -EINVAL;
rt5640->ldo1_en = -EINVAL;
rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap);
if (IS_ERR(rt5640->regmap)) {
@ -2383,13 +2790,13 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
return ret;
}
if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
ret = devm_gpio_request_one(&i2c->dev, rt5640->pdata.ldo1_en,
if (gpio_is_valid(rt5640->ldo1_en)) {
ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en,
GPIOF_OUT_INIT_HIGH,
"RT5640 LDO1_EN");
if (ret < 0) {
dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n",
rt5640->pdata.ldo1_en, ret);
rt5640->ldo1_en, ret);
return ret;
}
msleep(400);
@ -2412,19 +2819,27 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5640->regmap, RT5640_DUMMY1,
RT5640_MCLK_DET, RT5640_MCLK_DET);
if (rt5640->pdata.in1_diff)
regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
RT5640_IN_DF1, RT5640_IN_DF1);
if (rt5640->pdata.in2_diff)
regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
RT5640_IN_DF2, RT5640_IN_DF2);
if (rt5640->pdata.in3_diff)
regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
RT5640_IN_DF2, RT5640_IN_DF2);
rt5640->hp_mute = 1;
rt5640->irq = i2c->irq;
INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work);
INIT_WORK(&rt5640->jack_work, rt5640_jack_work);
/* Make sure work is stopped on probe-error / remove */
ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640);
if (ret)
return ret;
ret = devm_request_irq(&i2c->dev, rt5640->irq, rt5640_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5640", rt5640);
if (ret == 0) {
/* Gets re-enabled by rt5640_set_jack() */
disable_irq(rt5640->irq);
} else {
dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
rt5640->irq, ret);
rt5640->irq = -ENXIO;
}
return devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_rt5640,

View file

@ -13,7 +13,8 @@
#define _RT5640_H
#include <linux/clk.h>
#include <sound/rt5640.h>
#include <linux/workqueue.h>
#include <dt-bindings/sound/rt5640.h>
/* Info */
#define RT5640_RESET 0x00
@ -146,6 +147,7 @@
/* Index of Codec Private Register definition */
#define RT5640_BIAS_CUR4 0x15
#define RT5640_CHPUMP_INT_REG1 0x24
#define RT5640_MAMP_INT_REG2 0x37
#define RT5640_3D_SPK 0x63
@ -1607,10 +1609,17 @@
#define RT5640_MB2_OC_P_SFT 6
#define RT5640_MB2_OC_P_NOR (0x0 << 6)
#define RT5640_MB2_OC_P_INV (0x1 << 6)
#define RT5640_MB1_OC_CLR (0x1 << 3)
#define RT5640_MB1_OC_CLR_SFT 3
#define RT5640_MB2_OC_CLR (0x1 << 2)
#define RT5640_MB2_OC_CLR_SFT 2
#define RT5640_MB1_OC_STATUS (0x1 << 3)
#define RT5640_MB1_OC_STATUS_SFT 3
#define RT5640_MB2_OC_STATUS (0x1 << 2)
#define RT5640_MB2_OC_STATUS_SFT 2
/* GPIO and Internal Status (0xbf) */
#define RT5640_GPIO1_STATUS (0x1 << 8)
#define RT5640_GPIO2_STATUS (0x1 << 7)
#define RT5640_JD_STATUS (0x1 << 4)
#define RT5640_OVT_STATUS (0x1 << 3)
#define RT5640_CLS_D_OVCD_STATUS (0x1 << 0)
/* GPIO Control 1 (0xc0) */
#define RT5640_GP1_PIN_MASK (0x1 << 15)
@ -1978,6 +1987,15 @@
#define RT5640_MCLK_DET (0x1 << 11)
/* Codec Private Register definition */
/* MIC Over current threshold scale factor (0x15) */
#define RT5640_MIC_OVCD_SF_MASK (0x3 << 8)
#define RT5640_MIC_OVCD_SF_SFT 8
#define RT5640_MIC_OVCD_SF_0P5 (0x0 << 8)
#define RT5640_MIC_OVCD_SF_0P75 (0x1 << 8)
#define RT5640_MIC_OVCD_SF_1P0 (0x2 << 8)
#define RT5640_MIC_OVCD_SF_1P5 (0x3 << 8)
/* 3D Speaker Control (0x63) */
#define RT5640_3D_SPK_MASK (0x1 << 15)
#define RT5640_3D_SPK_SFT 15
@ -2103,10 +2121,11 @@ enum {
struct rt5640_priv {
struct snd_soc_component *component;
struct rt5640_platform_data pdata;
struct regmap *regmap;
struct clk *mclk;
int ldo1_en; /* GPIO for LDO1_EN */
int irq;
int sysclk;
int sysclk_src;
int lrck[RT5640_AIFS];
@ -2119,6 +2138,21 @@ struct rt5640_priv {
bool hp_mute;
bool asrc_en;
/* Jack and button detect data */
bool ovcd_irq_enabled;
bool pressed;
bool press_reported;
int press_count;
int release_count;
int poll_count;
struct delayed_work bp_work;
struct work_struct jack_work;
struct snd_soc_jack *jack;
unsigned int jd_src;
bool jd_inverted;
unsigned int ovcd_th;
unsigned int ovcd_sf;
};
int rt5640_dmic_enable(struct snd_soc_component *component,

View file

@ -3652,6 +3652,11 @@ static const struct rt5645_platform_data asus_t100ha_platform_data = {
.inv_jd1_1 = true,
};
static const struct rt5645_platform_data lenovo_ideapad_miix_310_pdata = {
.jd_mode = 3,
.in2_diff = true,
};
static const struct rt5645_platform_data jd_mode3_platform_data = {
.jd_mode = 3,
};
@ -3735,6 +3740,24 @@ static const struct dmi_system_id dmi_platform_data[] = {
},
.driver_data = (void *)&jd_mode3_platform_data,
},
{
.ident = "Lenovo Ideapad Miix 310",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80SG"),
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"),
},
.driver_data = (void *)&lenovo_ideapad_miix_310_pdata,
},
{
.ident = "Lenovo Ideapad Miix 320",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"),
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
},
.driver_data = (void *)&intel_braswell_platform_data,
},
{ }
};

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