forked from Minki/linux
Merge branch 'asoc-4.18' into asoc-next
This commit is contained in:
commit
5544717d41
84
Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt
Normal file
84
Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt
Normal 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>;
|
||||
...
|
||||
};
|
||||
};
|
14
Documentation/devicetree/bindings/sound/adi,ssm2305.txt
Normal file
14
Documentation/devicetree/bindings/sound/adi,ssm2305.txt
Normal 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>;
|
||||
};
|
47
Documentation/devicetree/bindings/sound/atmel-i2s.txt
Normal file
47
Documentation/devicetree/bindings/sound/atmel-i2s.txt
Normal 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>;
|
||||
};
|
@ -16,7 +16,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: cs42888@48 {
|
||||
cs42888: codec@48 {
|
||||
compatible = "cirrus,cs42888";
|
||||
reg = <0x48>;
|
||||
clocks = <&codec_mclk 0>;
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
16
Documentation/devicetree/bindings/sound/mt6351.txt
Normal file
16
Documentation/devicetree/bindings/sound/mt6351.txt
Normal 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";
|
||||
};
|
42
Documentation/devicetree/bindings/sound/mt6797-afe-pcm.txt
Normal file
42
Documentation/devicetree/bindings/sound/mt6797-afe-pcm.txt
Normal 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";
|
||||
};
|
14
Documentation/devicetree/bindings/sound/mt6797-mt6351.txt
Normal file
14
Documentation/devicetree/bindings/sound/mt6797-mt6351.txt
Normal 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>;
|
||||
};
|
109
Documentation/devicetree/bindings/sound/qcom,apq8096.txt
Normal file
109
Documentation/devicetree/bindings/sound/qcom,apq8096.txt
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
33
Documentation/devicetree/bindings/sound/qcom,q6adm.txt
Normal file
33
Documentation/devicetree/bindings/sound/qcom,q6adm.txt
Normal 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>;
|
||||
};
|
||||
};
|
172
Documentation/devicetree/bindings/sound/qcom,q6afe.txt
Normal file
172
Documentation/devicetree/bindings/sound/qcom,q6afe.txt
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
33
Documentation/devicetree/bindings/sound/qcom,q6asm.txt
Normal file
33
Documentation/devicetree/bindings/sound/qcom,q6asm.txt
Normal 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>;
|
||||
};
|
||||
};
|
21
Documentation/devicetree/bindings/sound/qcom,q6core.txt
Normal file
21
Documentation/devicetree/bindings/sound/qcom,q6core.txt
Normal 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>;
|
||||
};
|
@ -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>;
|
||||
|
@ -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>;
|
||||
};
|
||||
|
@ -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>;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -69,4 +69,4 @@ codec: rt5650@1a {
|
||||
realtek,dmic-en = "true";
|
||||
realtek,en-jd-func = "true";
|
||||
realtek,jd-mode = <3>;
|
||||
};
|
||||
};
|
||||
|
@ -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";
|
||||
|
@ -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>;
|
||||
|
50
Documentation/devicetree/bindings/sound/rt5668.txt
Normal file
50
Documentation/devicetree/bindings/sound/rt5668.txt
Normal 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>;
|
||||
};
|
@ -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>;
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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>;
|
||||
};
|
||||
|
23
Documentation/devicetree/bindings/sound/tscs454.txt
Normal file
23
Documentation/devicetree/bindings/sound/tscs454.txt
Normal 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>;
|
||||
};
|
@ -12,7 +12,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8510@1a {
|
||||
wm8510: codec@1a {
|
||||
compatible = "wlf,wm8510";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8523@1a {
|
||||
wm8523: codec@1a {
|
||||
compatible = "wlf,wm8523";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8524 {
|
||||
wm8524: codec {
|
||||
compatible = "wlf,wm8524";
|
||||
wlf,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8580@1a {
|
||||
wm8580: codec@1a {
|
||||
compatible = "wlf,wm8580";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -12,7 +12,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8711@1a {
|
||||
wm8711: codec@1a {
|
||||
compatible = "wlf,wm8711";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -12,7 +12,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8728@1a {
|
||||
wm8728: codec@1a {
|
||||
compatible = "wlf,wm8728";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -12,7 +12,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8731@1a {
|
||||
wm8731: codec@1a {
|
||||
compatible = "wlf,wm8731";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -12,7 +12,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8737@1a {
|
||||
wm8737: codec@1a {
|
||||
compatible = "wlf,wm8737";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -21,7 +21,7 @@ Optional properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8741@1a {
|
||||
wm8741: codec@1a {
|
||||
compatible = "wlf,wm8741";
|
||||
reg = <0x1a>;
|
||||
|
||||
|
@ -12,7 +12,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8750@1a {
|
||||
wm8750: codec@1a {
|
||||
compatible = "wlf,wm8750";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -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>;
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8770@1 {
|
||||
wm8770: codec@1 {
|
||||
compatible = "wlf,wm8770";
|
||||
reg = <1>;
|
||||
};
|
||||
|
@ -12,7 +12,7 @@ Required properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8776@1a {
|
||||
wm8776: codec@1a {
|
||||
compatible = "wlf,wm8776";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -19,7 +19,7 @@ Optional properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8804@1a {
|
||||
wm8804: codec@1a {
|
||||
compatible = "wlf,wm8804";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
@ -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 >;
|
||||
|
@ -23,7 +23,7 @@ Optional properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8960@1a {
|
||||
wm8960: codec@1a {
|
||||
compatible = "wlf,wm8960";
|
||||
reg = <0x1a>;
|
||||
|
||||
|
@ -24,7 +24,7 @@ Optional properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8962@1a {
|
||||
wm8962: codec@1a {
|
||||
compatible = "wlf,wm8962";
|
||||
reg = <0x1a>;
|
||||
|
||||
|
@ -59,7 +59,7 @@ Optional properties:
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8994@1a {
|
||||
wm8994: codec@1a {
|
||||
compatible = "wlf,wm8994";
|
||||
reg = <0x1a>;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
378
drivers/soc/qcom/apr.c
Normal 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");
|
28
include/dt-bindings/soc/qcom,apr.h
Normal file
28
include/dt-bindings/soc/qcom,apr.h
Normal 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 */
|
@ -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)
|
||||
|
111
include/dt-bindings/sound/qcom,q6afe.h
Normal file
111
include/dt-bindings/sound/qcom,q6afe.h
Normal 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__ */
|
||||
|
22
include/dt-bindings/sound/qcom,q6asm.h
Normal file
22
include/dt-bindings/sound/qcom,q6asm.h
Normal 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__ */
|
25
include/dt-bindings/sound/rt5640.h
Normal file
25
include/dt-bindings/sound/rt5640.h
Normal 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 */
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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:"
|
||||
|
||||
|
128
include/linux/soc/qcom/apr.h
Normal file
128
include/linux/soc/qcom/apr.h
Normal 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_ */
|
@ -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__ */
|
@ -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
40
include/sound/rt5668.h
Normal 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
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
765
sound/soc/atmel/atmel-i2s.c
Normal 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");
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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
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
105
sound/soc/codecs/mt6351.h
Normal 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
|
@ -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"},
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
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
276
sound/soc/codecs/rt1305.h
Normal 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_ */
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user