Merge remote-tracking branches 'asoc/fix/atmel', 'asoc/fix/intel', 'asoc/fix/rt5645', 'asoc/fix/rt5677' and 'asoc/fix/samsung' into asoc-linus
This commit is contained in:
Коммит
c52e5698ef
|
@ -0,0 +1,24 @@
|
|||
Audio Binding for Arndale boards
|
||||
|
||||
Required properties:
|
||||
- compatible : Can be the following,
|
||||
"samsung,arndale-rt5631"
|
||||
|
||||
- samsung,audio-cpu: The phandle of the Samsung I2S controller
|
||||
- samsung,audio-codec: The phandle of the audio codec
|
||||
|
||||
Optional:
|
||||
- samsung,model: The name of the sound-card
|
||||
|
||||
Arndale Boards has many audio daughter cards, one of them is
|
||||
rt5631/alc5631. Below example shows audio bindings for rt5631/
|
||||
alc5631 based codec.
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "samsung,arndale-rt5631";
|
||||
|
||||
samsung,audio-cpu = <&i2s0>
|
||||
samsung,audio-codec = <&rt5631>;
|
||||
};
|
|
@ -32,7 +32,7 @@ Optional properties:
|
|||
- rx-num-evt : FIFO levels.
|
||||
- sram-size-playback : size of sram to be allocated during playback
|
||||
- sram-size-capture : size of sram to be allocated during capture
|
||||
- interrupts : Interrupt numbers for McASP, currently not used by the driver
|
||||
- interrupts : Interrupt numbers for McASP
|
||||
- interrupt-names : Known interrupt names are "tx" and "rx"
|
||||
- pinctrl-0: Should specify pin control group used for this controller.
|
||||
- pinctrl-names: Should contain only one value - "default", for more details
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
Audio complex for Eukrea boards with tlv320aic23 codec.
|
||||
|
||||
Required properties:
|
||||
- compatible : "eukrea,asoc-tlv320"
|
||||
- eukrea,model : The user-visible name of this sound complex.
|
||||
- ssi-controller : The phandle of the SSI controller.
|
||||
- fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
|
||||
- fsl,mux-ext-port : The external port of the i.MX audio muxer.
|
||||
|
||||
- compatible : "eukrea,asoc-tlv320"
|
||||
|
||||
- eukrea,model : The user-visible name of this sound complex.
|
||||
|
||||
- ssi-controller : The phandle of the SSI controller.
|
||||
|
||||
- fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
|
||||
|
||||
- fsl,mux-ext-port : The external port of the i.MX audio muxer.
|
||||
|
||||
Note: The AUDMUX port numbering should start at 1, which is consistent with
|
||||
hardware manual.
|
||||
|
|
|
@ -7,37 +7,39 @@ other DSPs. It has up to six transmitters and four receivers.
|
|||
|
||||
Required properties:
|
||||
|
||||
- compatible : Compatible list, must contain "fsl,imx35-esai" or
|
||||
"fsl,vf610-esai"
|
||||
- compatible : Compatible list, must contain "fsl,imx35-esai" or
|
||||
"fsl,vf610-esai"
|
||||
|
||||
- reg : Offset and length of the register set for the device.
|
||||
- reg : Offset and length of the register set for the device.
|
||||
|
||||
- interrupts : Contains the spdif interrupt.
|
||||
- interrupts : Contains the spdif interrupt.
|
||||
|
||||
- dmas : Generic dma devicetree binding as described in
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
- dmas : Generic dma devicetree binding as described in
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
|
||||
- dma-names : Two dmas have to be defined, "tx" and "rx".
|
||||
- dma-names : Two dmas have to be defined, "tx" and "rx".
|
||||
|
||||
- clocks: Contains an entry for each entry in clock-names.
|
||||
- clocks : Contains an entry for each entry in clock-names.
|
||||
|
||||
- clock-names : Includes the following entries:
|
||||
"core" The core clock used to access registers
|
||||
"extal" The esai baud clock for esai controller used to derive
|
||||
HCK, SCK and FS.
|
||||
"fsys" The system clock derived from ahb clock used to derive
|
||||
HCK, SCK and FS.
|
||||
- clock-names : Includes the following entries:
|
||||
"core" The core clock used to access registers
|
||||
"extal" The esai baud clock for esai controller used to
|
||||
derive HCK, SCK and FS.
|
||||
"fsys" The system clock derived from ahb clock used to
|
||||
derive HCK, SCK and FS.
|
||||
|
||||
- fsl,fifo-depth: The number of elements in the transmit and receive FIFOs.
|
||||
This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM].
|
||||
- fsl,fifo-depth : The number of elements in the transmit and receive
|
||||
FIFOs. This number is the maximum allowed value for
|
||||
TFCR[TFWM] or RFCR[RFWM].
|
||||
|
||||
- fsl,esai-synchronous: This is a boolean property. If present, indicating
|
||||
that ESAI would work in the synchronous mode, which means all the settings
|
||||
for Receiving would be duplicated from Transmition related registers.
|
||||
that ESAI would work in the synchronous mode, which
|
||||
means all the settings for Receiving would be
|
||||
duplicated from Transmition related registers.
|
||||
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -6,32 +6,31 @@ a fibre cable.
|
|||
|
||||
Required properties:
|
||||
|
||||
- compatible : Compatible list, must contain "fsl,imx35-spdif".
|
||||
- compatible : Compatible list, must contain "fsl,imx35-spdif".
|
||||
|
||||
- reg : Offset and length of the register set for the device.
|
||||
- reg : Offset and length of the register set for the device.
|
||||
|
||||
- interrupts : Contains the spdif interrupt.
|
||||
- interrupts : Contains the spdif interrupt.
|
||||
|
||||
- dmas : Generic dma devicetree binding as described in
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
- dmas : Generic dma devicetree binding as described in
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
|
||||
- dma-names : Two dmas have to be defined, "tx" and "rx".
|
||||
- dma-names : Two dmas have to be defined, "tx" and "rx".
|
||||
|
||||
- clocks : Contains an entry for each entry in clock-names.
|
||||
- clocks : Contains an entry for each entry in clock-names.
|
||||
|
||||
- clock-names : Includes the following entries:
|
||||
"core" The core clock of spdif controller
|
||||
"rxtx<0-7>" Clock source list for tx and rx clock.
|
||||
This clock list should be identical to
|
||||
the source list connecting to the spdif
|
||||
clock mux in "SPDIF Transceiver Clock
|
||||
Diagram" of SoC reference manual. It
|
||||
can also be referred to TxClk_Source
|
||||
bit of register SPDIF_STC.
|
||||
- clock-names : Includes the following entries:
|
||||
"core" The core clock of spdif controller.
|
||||
"rxtx<0-7>" Clock source list for tx and rx clock.
|
||||
This clock list should be identical to the source
|
||||
list connecting to the spdif clock mux in "SPDIF
|
||||
Transceiver Clock Diagram" of SoC reference manual.
|
||||
It can also be referred to TxClk_Source bit of
|
||||
register SPDIF_STC.
|
||||
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -5,32 +5,48 @@ which provides a synchronous audio interface that supports fullduplex
|
|||
serial interfaces with frame synchronization such as I2S, AC97, TDM, and
|
||||
codec/DSP interfaces.
|
||||
|
||||
|
||||
Required properties:
|
||||
- compatible: Compatible list, contains "fsl,vf610-sai" or "fsl,imx6sx-sai".
|
||||
- reg: Offset and length of the register set for the device.
|
||||
- clocks: Must contain an entry for each entry in clock-names.
|
||||
- clock-names : Must include the "bus" for register access and "mclk1" "mclk2"
|
||||
"mclk3" for bit clock and frame clock providing.
|
||||
- dmas : Generic dma devicetree binding as described in
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
- dma-names : Two dmas have to be defined, "tx" and "rx".
|
||||
- pinctrl-names: Must contain a "default" entry.
|
||||
- pinctrl-NNN: One property must exist for each entry in 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 is transmitted first.
|
||||
- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
|
||||
that SAI will work in the synchronous mode (sync Tx with Rx) which means
|
||||
both the transimitter and receiver will send and receive data by following
|
||||
receiver's bit clocks and frame sync clocks.
|
||||
- fsl,sai-asynchronous: This is a boolean property. If present, indicating
|
||||
that SAI will work in the asynchronous mode, which means both transimitter
|
||||
and receiver will send and receive data by following their own bit clocks
|
||||
and frame sync clocks separately.
|
||||
|
||||
- compatible : Compatible list, contains "fsl,vf610-sai" or
|
||||
"fsl,imx6sx-sai".
|
||||
|
||||
- reg : Offset and length of the register set for the device.
|
||||
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
|
||||
- clock-names : Must include the "bus" for register access and
|
||||
"mclk1", "mclk2", "mclk3" for bit clock and frame
|
||||
clock providing.
|
||||
- dmas : Generic dma devicetree binding as described in
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
|
||||
- dma-names : Two dmas have to be defined, "tx" and "rx".
|
||||
|
||||
- pinctrl-names : Must contain a "default" entry.
|
||||
|
||||
- pinctrl-NNN : One property must exist for each entry in
|
||||
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
|
||||
is transmitted first.
|
||||
|
||||
- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
|
||||
that SAI will work in the synchronous mode (sync Tx
|
||||
with Rx) which means both the transimitter and the
|
||||
receiver will send and receive data by following
|
||||
receiver's bit clocks and frame sync clocks.
|
||||
|
||||
- fsl,sai-asynchronous: This is a boolean property. If present, indicating
|
||||
that SAI will work in the asynchronous mode, which
|
||||
means both transimitter and receiver will send and
|
||||
receive data by following their own bit clocks and
|
||||
frame sync clocks separately.
|
||||
|
||||
Note:
|
||||
- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
|
||||
|
|
|
@ -1,33 +1,40 @@
|
|||
Freescale i.MX audio complex with SGTL5000 codec
|
||||
|
||||
Required properties:
|
||||
- compatible : "fsl,imx-audio-sgtl5000"
|
||||
- model : The user-visible name of this sound complex
|
||||
- ssi-controller : The phandle of the i.MX SSI controller
|
||||
- audio-codec : The phandle of the SGTL5000 audio codec
|
||||
- audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the connection's sink,
|
||||
the second being the connection's source. Valid names could be power
|
||||
supplies, SGTL5000 pins, and the jacks on the board:
|
||||
|
||||
Power supplies:
|
||||
* Mic Bias
|
||||
- compatible : "fsl,imx-audio-sgtl5000"
|
||||
|
||||
SGTL5000 pins:
|
||||
* MIC_IN
|
||||
* LINE_IN
|
||||
* HP_OUT
|
||||
* LINE_OUT
|
||||
- model : The user-visible name of this sound complex
|
||||
|
||||
Board connectors:
|
||||
* Mic Jack
|
||||
* Line In Jack
|
||||
* Headphone Jack
|
||||
* Line Out Jack
|
||||
* Ext Spk
|
||||
- ssi-controller : The phandle of the i.MX SSI controller
|
||||
|
||||
- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
|
||||
- mux-ext-port : The external port of the i.MX audio muxer
|
||||
- audio-codec : The phandle of the SGTL5000 audio codec
|
||||
|
||||
- audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the
|
||||
connection's sink, the second being the connection's
|
||||
source. Valid names could be power supplies, SGTL5000
|
||||
pins, and the jacks on the board:
|
||||
|
||||
Power supplies:
|
||||
* Mic Bias
|
||||
|
||||
SGTL5000 pins:
|
||||
* MIC_IN
|
||||
* LINE_IN
|
||||
* HP_OUT
|
||||
* LINE_OUT
|
||||
|
||||
Board connectors:
|
||||
* Mic Jack
|
||||
* Line In Jack
|
||||
* Headphone Jack
|
||||
* Line Out Jack
|
||||
* Ext Spk
|
||||
|
||||
- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
|
||||
|
||||
- mux-ext-port : The external port of the i.MX audio muxer
|
||||
|
||||
Note: The AUDMUX port numbering should start at 1, which is consistent with
|
||||
hardware manual.
|
||||
|
|
|
@ -2,23 +2,25 @@ Freescale i.MX audio complex with S/PDIF transceiver
|
|||
|
||||
Required properties:
|
||||
|
||||
- compatible : "fsl,imx-audio-spdif"
|
||||
- compatible : "fsl,imx-audio-spdif"
|
||||
|
||||
- model : The user-visible name of this sound complex
|
||||
- model : The user-visible name of this sound complex
|
||||
|
||||
- spdif-controller : The phandle of the i.MX S/PDIF controller
|
||||
- spdif-controller : The phandle of the i.MX S/PDIF controller
|
||||
|
||||
|
||||
Optional properties:
|
||||
|
||||
- spdif-out : This is a boolean property. If present, the transmitting
|
||||
function of S/PDIF will be enabled, indicating there's a physical
|
||||
S/PDIF out connector/jack on the board or it's connecting to some
|
||||
other IP block, such as an HDMI encoder/display-controller.
|
||||
- spdif-out : This is a boolean property. If present, the
|
||||
transmitting function of S/PDIF will be enabled,
|
||||
indicating there's a physical S/PDIF out connector
|
||||
or jack on the board or it's connecting to some
|
||||
other IP block, such as an HDMI encoder or
|
||||
display-controller.
|
||||
|
||||
- spdif-in : This is a boolean property. If present, the receiving
|
||||
function of S/PDIF will be enabled, indicating there's a physical
|
||||
S/PDIF in connector/jack on the board.
|
||||
- spdif-in : This is a boolean property. If present, the receiving
|
||||
function of S/PDIF will be enabled, indicating there
|
||||
is a physical S/PDIF in connector/jack on the board.
|
||||
|
||||
* Note: At least one of these two properties should be set in the DT binding.
|
||||
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
Freescale i.MX audio complex with WM8962 codec
|
||||
|
||||
Required properties:
|
||||
- compatible : "fsl,imx-audio-wm8962"
|
||||
- model : The user-visible name of this sound complex
|
||||
- ssi-controller : The phandle of the i.MX SSI controller
|
||||
- audio-codec : The phandle of the WM8962 audio codec
|
||||
- audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the connection's sink,
|
||||
the second being the connection's source. Valid names could be power
|
||||
supplies, WM8962 pins, and the jacks on the board:
|
||||
|
||||
Power supplies:
|
||||
* Mic Bias
|
||||
- compatible : "fsl,imx-audio-wm8962"
|
||||
|
||||
Board connectors:
|
||||
* Mic Jack
|
||||
* Headphone Jack
|
||||
* Ext Spk
|
||||
- model : The user-visible name of this sound complex
|
||||
|
||||
- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
|
||||
- mux-ext-port : The external port of the i.MX audio muxer
|
||||
- ssi-controller : The phandle of the i.MX SSI controller
|
||||
|
||||
- audio-codec : The phandle of the WM8962 audio codec
|
||||
|
||||
- audio-routing : A list of the connections between audio components.
|
||||
Each entry is a pair of strings, the first being the
|
||||
connection's sink, the second being the connection's
|
||||
source. Valid names could be power supplies, WM8962
|
||||
pins, and the jacks on the board:
|
||||
|
||||
Power supplies:
|
||||
* Mic Bias
|
||||
|
||||
Board connectors:
|
||||
* Mic Jack
|
||||
* Headphone Jack
|
||||
* Ext Spk
|
||||
|
||||
- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
|
||||
|
||||
- mux-ext-port : The external port of the i.MX audio muxer
|
||||
|
||||
Note: The AUDMUX port numbering should start at 1, which is consistent with
|
||||
hardware manual.
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
Freescale Digital Audio Mux (AUDMUX) device
|
||||
|
||||
Required properties:
|
||||
- compatible : "fsl,imx21-audmux" for AUDMUX version firstly used on i.MX21,
|
||||
or "fsl,imx31-audmux" for the version firstly used on i.MX31.
|
||||
- reg : Should contain AUDMUX registers location and length
|
||||
|
||||
- compatible : "fsl,imx21-audmux" for AUDMUX version firstly used
|
||||
on i.MX21, or "fsl,imx31-audmux" for the version
|
||||
firstly used on i.MX31.
|
||||
|
||||
- reg : Should contain AUDMUX registers location and length.
|
||||
|
||||
An initial configuration can be setup using child nodes.
|
||||
|
||||
Required properties of optional child nodes:
|
||||
- fsl,audmux-port : Integer of the audmux port that is configured by this
|
||||
child node.
|
||||
- fsl,port-config : List of configuration options for the specific port. For
|
||||
imx31-audmux and above, it is a list of tuples <ptcr pdcr>. For
|
||||
imx21-audmux it is a list of pcr values.
|
||||
|
||||
- fsl,audmux-port : Integer of the audmux port that is configured by this
|
||||
child node.
|
||||
|
||||
- fsl,port-config : List of configuration options for the specific port.
|
||||
For imx31-audmux and above, it is a list of tuples
|
||||
<ptcr pdcr>. For imx21-audmux it is a list of pcr
|
||||
values.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ Optional properties:
|
|||
|
||||
- clock-names: Should be "mclk"
|
||||
|
||||
- maxim,dmic-freq: Frequency at which to clock DMIC
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* MIC1
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
Renesas FSI
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,sh_fsi2" or "renesas,sh_fsi"
|
||||
- compatible : "renesas,fsi2-<soctype>",
|
||||
"renesas,sh_fsi2" or "renesas,sh_fsi" as
|
||||
fallback.
|
||||
Examples with soctypes are:
|
||||
- "renesas,fsi2-r8a7740" (R-Mobile A1)
|
||||
- "renesas,fsi2-sh73a0" (SH-Mobile AG5)
|
||||
- reg : Should contain the register physical address and length
|
||||
- interrupts : Should contain FSI interrupt
|
||||
|
||||
- fsia,spdif-connection : FSI is connected by S/PDFI
|
||||
- fsia,spdif-connection : FSI is connected by S/PDIF
|
||||
- fsia,stream-mode-support : FSI supports 16bit stream mode.
|
||||
- fsia,use-internal-clock : FSI uses internal clock when master mode.
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
Renesas R-Car sound
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,rcar_sound-gen1" if generation1
|
||||
- compatible : "renesas,rcar_sound-<soctype>", fallbacks
|
||||
"renesas,rcar_sound-gen1" if generation1, and
|
||||
"renesas,rcar_sound-gen2" if generation2
|
||||
Examples with soctypes are:
|
||||
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
||||
- "renesas,rcar_sound-r8a7791" (R-Car M2-W)
|
||||
- reg : Should contain the register physical address.
|
||||
required register is
|
||||
SRU/ADG/SSI if generation1
|
||||
|
@ -35,9 +39,9 @@ DAI subnode properties:
|
|||
|
||||
Example:
|
||||
|
||||
rcar_sound: rcar_sound@0xffd90000 {
|
||||
rcar_sound: rcar_sound@ec500000 {
|
||||
#sound-dai-cells = <1>;
|
||||
compatible = "renesas,rcar_sound-gen2";
|
||||
compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
|
||||
reg = <0 0xec500000 0 0x1000>, /* SCU */
|
||||
<0 0xec5a0000 0 0x100>, /* ADG */
|
||||
<0 0xec540000 0 0x1000>, /* SSIU */
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
ALC5631/RT5631 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "realtek,alc5631" or "realtek,rt5631"
|
||||
|
||||
- reg : the I2C address of the device.
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* SPK_OUT_R_P
|
||||
* SPK_OUT_R_N
|
||||
* SPK_OUT_L_P
|
||||
* SPK_OUT_L_N
|
||||
* HP_OUT_L
|
||||
* HP_OUT_R
|
||||
* AUX_OUT2_LP
|
||||
* AUX_OUT2_RN
|
||||
* AUX_OUT1_LP
|
||||
* AUX_OUT1_RN
|
||||
* AUX_IN_L_JD
|
||||
* AUX_IN_R_JD
|
||||
* MONO_IN_P
|
||||
* MONO_IN_N
|
||||
* MIC1_P
|
||||
* MIC1_N
|
||||
* MIC2_P
|
||||
* MIC2_N
|
||||
* MONO_OUT_P
|
||||
* MONO_OUT_N
|
||||
* MICBIAS1
|
||||
* MICBIAS2
|
||||
|
||||
Example:
|
||||
|
||||
alc5631: alc5631@1a {
|
||||
compatible = "realtek,alc5631";
|
||||
reg = <0x1a>;
|
||||
};
|
||||
|
||||
or
|
||||
|
||||
rt5631: rt5631@1a {
|
||||
compatible = "realtek,rt5631";
|
||||
reg = <0x1a>;
|
||||
};
|
|
@ -27,6 +27,21 @@ Optional properties:
|
|||
Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential,
|
||||
rather than single-ended.
|
||||
|
||||
- realtek,gpio-config
|
||||
Array of six 8bit elements that configures GPIO.
|
||||
0 - floating (reset value)
|
||||
1 - pull down
|
||||
2 - pull up
|
||||
|
||||
- realtek,jd1-gpio
|
||||
Configures GPIO Mic Jack detection 1.
|
||||
Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively.
|
||||
|
||||
- realtek,jd2-gpio
|
||||
- realtek,jd3-gpio
|
||||
Configures GPIO Mic Jack detection 2 and 3.
|
||||
Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively.
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* IN1P
|
||||
|
@ -56,4 +71,6 @@ rt5677 {
|
|||
realtek,pow-ldo2-gpio =
|
||||
<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
|
||||
realtek,in1-differential = "true";
|
||||
realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */
|
||||
realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */
|
||||
};
|
||||
|
|
|
@ -6,10 +6,17 @@ Required SoC Specific Properties:
|
|||
- samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
|
||||
- samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
|
||||
secondary fifo, s/w reset control and internal mux for root clk src.
|
||||
- samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with
|
||||
secondary fifo, s/w reset control, internal mux for root clk src and
|
||||
TDM support. TDM (Time division multiplexing) is to allow transfer of
|
||||
multiple channel audio data on single data line.
|
||||
- samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
|
||||
playback, sterio channel capture, secondary fifo using internal
|
||||
or external dma, s/w reset control, internal mux for root clk src
|
||||
and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
|
||||
is to allow transfer of multiple channel audio data on single data line.
|
||||
- samsung,exynos7-i2s: with all the available features of exynos5 i2s,
|
||||
exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo
|
||||
with only external dma and more no.of root clk sampling frequencies.
|
||||
- samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports
|
||||
stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with
|
||||
slightly modified bit offsets.
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
|
|
@ -7,6 +7,17 @@ Required properties:
|
|||
|
||||
- clocks : the clock provider of SYS_MCLK
|
||||
|
||||
- micbias-resistor-k-ohms : the bias resistor to be used in kOmhs
|
||||
The resistor can take values of 2k, 4k or 8k.
|
||||
If set to 0 it will be off.
|
||||
If this node is not mentioned or if the value is unknown, then
|
||||
micbias resistor is set to 4K.
|
||||
|
||||
- micbias-voltage-m-volts : the bias voltage to be used in mVolts
|
||||
The voltage can take values from 1.25V to 3V by 250mV steps
|
||||
If this node is not mentionned or the value is unknown, then
|
||||
the value is set to 1.25V.
|
||||
|
||||
- VDDA-supply : the regulator provider of VDDA
|
||||
|
||||
- VDDIO-supply: the regulator provider of VDDIO
|
||||
|
@ -21,6 +32,8 @@ codec: sgtl5000@0a {
|
|||
compatible = "fsl,sgtl5000";
|
||||
reg = <0x0a>;
|
||||
clocks = <&clks 150>;
|
||||
micbias-resistor-k-ohms = <2>;
|
||||
micbias-voltage-m-volts = <2250>;
|
||||
VDDA-supply = <®_3p3v>;
|
||||
VDDIO-supply = <®_3p3v>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
Texas Instruments TS3A227E
|
||||
Autonomous Audio Accessory Detection and Configuration Switch
|
||||
|
||||
The TS3A227E detect headsets of 3-ring and 4-ring standards and
|
||||
switches automatically to route the microphone correctly. It also
|
||||
handles key press detection in accordance with the Android audio
|
||||
headset specification v1.0.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should contain "ti,ts3a227e".
|
||||
- reg: The i2c address. Should contain <0x3b>.
|
||||
- interrupt-parent: The parent interrupt controller
|
||||
- interrupts: Interrupt number for /INT pin from the 227e
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
i2c {
|
||||
ts3a227e@3b {
|
||||
compatible = "ti,ts3a227e";
|
||||
reg = <0x3b>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
WM8960 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8960"
|
||||
|
||||
- reg : the I2C address of the device.
|
||||
|
||||
Optional properties:
|
||||
- wlf,shared-lrclk: This is a boolean property. If present, the LRCM bit of
|
||||
R24 (Additional control 2) gets set, indicating that ADCLRC and DACLRC pins
|
||||
will be disabled only when ADC (Left and Right) and DAC (Left and Right)
|
||||
are disabled.
|
||||
When wm8960 works on synchronize mode and DACLRC pin is used to supply
|
||||
frame clock, it will no frame clock for captrue unless enable DAC to enable
|
||||
DACLRC pin. If shared-lrclk is present, no need to enable DAC for captrue.
|
||||
|
||||
- wlf,capless: This is a boolean property. If present, OUT3 pin will be
|
||||
enabled and disabled together with HP_L and HP_R pins in response to jack
|
||||
detect events.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8960@1a {
|
||||
compatible = "wlf,wm8960";
|
||||
reg = <0x1a>;
|
||||
|
||||
wlf,shared-lrclk;
|
||||
};
|
|
@ -6601,6 +6601,12 @@ S: Supported
|
|||
F: drivers/gpu/drm/i2c/tda998x_drv.c
|
||||
F: include/drm/i2c/tda998x.h
|
||||
|
||||
NXP TFA9879 DRIVER
|
||||
M: Peter Rosin <peda@axentia.se>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: sound/soc/codecs/tfa9879*
|
||||
|
||||
OMAP SUPPORT
|
||||
M: Tony Lindgren <tony@atomide.com>
|
||||
L: linux-omap@vger.kernel.org
|
||||
|
|
|
@ -923,6 +923,14 @@ static void __init spitz_i2c_init(void)
|
|||
static inline void spitz_i2c_init(void) {}
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* Audio devices
|
||||
******************************************************************************/
|
||||
static inline void spitz_audio_init(void)
|
||||
{
|
||||
platform_device_register_simple("spitz-audio", -1, NULL, 0);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Machine init
|
||||
******************************************************************************/
|
||||
|
@ -970,6 +978,7 @@ static void __init spitz_init(void)
|
|||
spitz_nor_init();
|
||||
spitz_nand_init();
|
||||
spitz_i2c_init();
|
||||
spitz_audio_init();
|
||||
}
|
||||
|
||||
static void __init spitz_fixup(struct tag *tags, char **cmdline)
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
#include <linux/sfi.h>
|
||||
|
||||
#define MAX_NUM_STREAMS_MRFLD 25
|
||||
#define MAX_NUM_STREAMS MAX_NUM_STREAMS_MRFLD
|
||||
|
||||
enum sst_audio_task_id_mrfld {
|
||||
SST_TASK_ID_NONE = 0,
|
||||
SST_TASK_ID_SBA = 1,
|
||||
|
@ -73,6 +76,65 @@ struct sst_platform_data {
|
|||
unsigned int strm_map_size;
|
||||
};
|
||||
|
||||
struct sst_info {
|
||||
u32 iram_start;
|
||||
u32 iram_end;
|
||||
bool iram_use;
|
||||
u32 dram_start;
|
||||
u32 dram_end;
|
||||
bool dram_use;
|
||||
u32 imr_start;
|
||||
u32 imr_end;
|
||||
bool imr_use;
|
||||
u32 mailbox_start;
|
||||
bool use_elf;
|
||||
bool lpe_viewpt_rqd;
|
||||
unsigned int max_streams;
|
||||
u32 dma_max_len;
|
||||
u8 num_probes;
|
||||
};
|
||||
|
||||
struct sst_lib_dnld_info {
|
||||
unsigned int mod_base;
|
||||
unsigned int mod_end;
|
||||
unsigned int mod_table_offset;
|
||||
unsigned int mod_table_size;
|
||||
bool mod_ddr_dnld;
|
||||
};
|
||||
|
||||
struct sst_res_info {
|
||||
unsigned int shim_offset;
|
||||
unsigned int shim_size;
|
||||
unsigned int shim_phy_addr;
|
||||
unsigned int ssp0_offset;
|
||||
unsigned int ssp0_size;
|
||||
unsigned int dma0_offset;
|
||||
unsigned int dma0_size;
|
||||
unsigned int dma1_offset;
|
||||
unsigned int dma1_size;
|
||||
unsigned int iram_offset;
|
||||
unsigned int iram_size;
|
||||
unsigned int dram_offset;
|
||||
unsigned int dram_size;
|
||||
unsigned int mbox_offset;
|
||||
unsigned int mbox_size;
|
||||
unsigned int acpi_lpe_res_index;
|
||||
unsigned int acpi_ddr_index;
|
||||
unsigned int acpi_ipc_irq_index;
|
||||
};
|
||||
|
||||
struct sst_ipc_info {
|
||||
int ipc_offset;
|
||||
unsigned int mbox_recv_off;
|
||||
};
|
||||
|
||||
struct sst_platform_info {
|
||||
const struct sst_info *probe_data;
|
||||
const struct sst_ipc_info *ipc_info;
|
||||
const struct sst_res_info *res_info;
|
||||
const struct sst_lib_dnld_info *lib_info;
|
||||
const char *platform;
|
||||
};
|
||||
int add_sst_platform_device(void);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
# subsystems should select the appropriate symbols.
|
||||
|
||||
config REGMAP
|
||||
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ)
|
||||
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
|
||||
select LZO_COMPRESS
|
||||
select LZO_DECOMPRESS
|
||||
select IRQ_DOMAIN if REGMAP_IRQ
|
||||
bool
|
||||
|
||||
config REGMAP_AC97
|
||||
tristate
|
||||
|
||||
config REGMAP_I2C
|
||||
tristate
|
||||
depends on I2C
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
obj-$(CONFIG_REGMAP) += regmap.o regcache.o
|
||||
obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
|
||||
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
|
||||
obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
|
||||
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
|
||||
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
|
||||
obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Register map access API - AC'97 support
|
||||
*
|
||||
* Copyright 2013 Linaro Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <sound/ac97_codec.h>
|
||||
|
||||
bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case AC97_RESET:
|
||||
case AC97_POWERDOWN:
|
||||
case AC97_INT_PAGING:
|
||||
case AC97_EXTENDED_ID:
|
||||
case AC97_EXTENDED_STATUS:
|
||||
case AC97_EXTENDED_MID:
|
||||
case AC97_EXTENDED_MSTATUS:
|
||||
case AC97_GPIO_STATUS:
|
||||
case AC97_MISC_AFE:
|
||||
case AC97_VENDOR_ID1:
|
||||
case AC97_VENDOR_ID2:
|
||||
case AC97_CODEC_CLASS_REV:
|
||||
case AC97_PCI_SVID:
|
||||
case AC97_PCI_SID:
|
||||
case AC97_FUNC_SELECT:
|
||||
case AC97_FUNC_INFO:
|
||||
case AC97_SENSE_INFO:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_ac97_default_volatile);
|
||||
|
||||
static int regmap_ac97_reg_read(void *context, unsigned int reg,
|
||||
unsigned int *val)
|
||||
{
|
||||
struct snd_ac97 *ac97 = context;
|
||||
|
||||
*val = ac97->bus->ops->read(ac97, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int regmap_ac97_reg_write(void *context, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
struct snd_ac97 *ac97 = context;
|
||||
|
||||
ac97->bus->ops->write(ac97, reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_bus ac97_regmap_bus = {
|
||||
.reg_write = regmap_ac97_reg_write,
|
||||
.reg_read = regmap_ac97_reg_read,
|
||||
};
|
||||
|
||||
/**
|
||||
* regmap_init_ac97(): Initialise AC'97 register map
|
||||
*
|
||||
* @ac97: Device that will be interacted with
|
||||
* @config: Configuration for register map
|
||||
*
|
||||
* The return value will be an ERR_PTR() on error or a valid pointer to
|
||||
* a struct regmap.
|
||||
*/
|
||||
struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
|
||||
const struct regmap_config *config)
|
||||
{
|
||||
return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_init_ac97);
|
||||
|
||||
/**
|
||||
* devm_regmap_init_ac97(): Initialise AC'97 register map
|
||||
*
|
||||
* @ac97: Device that will be interacted with
|
||||
* @config: Configuration for register map
|
||||
*
|
||||
* The return value will be an ERR_PTR() on error or a valid pointer
|
||||
* to a struct regmap. The regmap will be automatically freed by the
|
||||
* device management code.
|
||||
*/
|
||||
struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
|
||||
const struct regmap_config *config)
|
||||
{
|
||||
return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_regmap_init_ac97);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -141,6 +141,7 @@ struct arizona {
|
|||
|
||||
uint16_t dac_comp_coeff;
|
||||
uint8_t dac_comp_enabled;
|
||||
struct mutex dac_comp_lock;
|
||||
};
|
||||
|
||||
int arizona_clk32k_enable(struct arizona *arizona);
|
||||
|
|
|
@ -99,12 +99,6 @@ struct davinci_vcif {
|
|||
dma_addr_t dma_rx_addr;
|
||||
};
|
||||
|
||||
struct cq93vc {
|
||||
struct platform_device *pdev;
|
||||
struct snd_soc_codec *codec;
|
||||
u32 sysclk;
|
||||
};
|
||||
|
||||
struct davinci_vc;
|
||||
|
||||
struct davinci_vc {
|
||||
|
@ -122,7 +116,6 @@ struct davinci_vc {
|
|||
|
||||
/* Client devices */
|
||||
struct davinci_vcif davinci_vcif;
|
||||
struct cq93vc cq93vc;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,7 @@ struct samsung_i2s {
|
|||
#define QUIRK_NO_MUXPSR (1 << 2)
|
||||
#define QUIRK_NEED_RSTCLR (1 << 3)
|
||||
#define QUIRK_SUPPORTS_TDM (1 << 4)
|
||||
#define QUIRK_SUPPORTS_IDMA (1 << 5)
|
||||
/* Quirks of the I2S controller */
|
||||
u32 quirks;
|
||||
dma_addr_t idma_addr;
|
||||
|
|
|
@ -27,6 +27,7 @@ struct spmi_device;
|
|||
struct regmap;
|
||||
struct regmap_range_cfg;
|
||||
struct regmap_field;
|
||||
struct snd_ac97;
|
||||
|
||||
/* An enum of all the supported cache types */
|
||||
enum regcache_type {
|
||||
|
@ -340,6 +341,8 @@ struct regmap *regmap_init_spmi_ext(struct spmi_device *dev,
|
|||
struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
|
||||
void __iomem *regs,
|
||||
const struct regmap_config *config);
|
||||
struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
|
||||
const struct regmap_config *config);
|
||||
|
||||
struct regmap *devm_regmap_init(struct device *dev,
|
||||
const struct regmap_bus *bus,
|
||||
|
@ -356,6 +359,10 @@ struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev,
|
|||
struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
|
||||
void __iomem *regs,
|
||||
const struct regmap_config *config);
|
||||
struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
|
||||
const struct regmap_config *config);
|
||||
|
||||
bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
|
||||
|
||||
/**
|
||||
* regmap_init_mmio(): Initialise register map
|
||||
|
|
|
@ -36,14 +36,14 @@
|
|||
#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
|
||||
#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */
|
||||
|
||||
#define RSND_SSI(_dma_id, _pio_irq, _flags) \
|
||||
{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
|
||||
#define RSND_SSI(_dma_id, _irq, _flags) \
|
||||
{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
|
||||
#define RSND_SSI_UNUSED \
|
||||
{ .dma_id = -1, .pio_irq = -1, .flags = 0 }
|
||||
{ .dma_id = -1, .irq = -1, .flags = 0 }
|
||||
|
||||
struct rsnd_ssi_platform_info {
|
||||
int dma_id;
|
||||
int pio_irq;
|
||||
int irq;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,10 @@ struct rt5645_platform_data {
|
|||
|
||||
unsigned int hp_det_gpio;
|
||||
bool gpio_hp_det_active_high;
|
||||
|
||||
/* true if codec's jd function is used */
|
||||
bool en_jd_func;
|
||||
unsigned int jd_mode;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,16 @@ struct rt5677_platform_data {
|
|||
bool lout3_diff;
|
||||
/* DMIC2 clock source selection */
|
||||
enum rt5677_dmic2_clk dmic2_clk_pin;
|
||||
|
||||
/* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */
|
||||
u8 gpio_config[6];
|
||||
|
||||
/* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */
|
||||
unsigned int jd1_gpio;
|
||||
/* jd2 and jd3 can select 0 ~ 3 as
|
||||
OFF, GPIO4, GPIO5 and GPIO6 respectively */
|
||||
unsigned int jd2_gpio;
|
||||
unsigned int jd3_gpio;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -206,7 +206,6 @@ struct snd_soc_dai_driver {
|
|||
/* DAI description */
|
||||
const char *name;
|
||||
unsigned int id;
|
||||
int ac97_control;
|
||||
unsigned int base;
|
||||
|
||||
/* DAI driver callbacks */
|
||||
|
@ -216,6 +215,8 @@ struct snd_soc_dai_driver {
|
|||
int (*resume)(struct snd_soc_dai *dai);
|
||||
/* compress dai */
|
||||
bool compress_dai;
|
||||
/* DAI is also used for the control bus */
|
||||
bool bus_control;
|
||||
|
||||
/* ops */
|
||||
const struct snd_soc_dai_ops *ops;
|
||||
|
@ -241,7 +242,6 @@ struct snd_soc_dai {
|
|||
const char *name;
|
||||
int id;
|
||||
struct device *dev;
|
||||
void *ac97_pdata; /* platform_data for the ac97 codec */
|
||||
|
||||
/* driver ops */
|
||||
struct snd_soc_dai_driver *driver;
|
||||
|
@ -268,7 +268,6 @@ struct snd_soc_dai {
|
|||
unsigned int sample_bits;
|
||||
|
||||
/* parent platform/codec */
|
||||
struct snd_soc_platform *platform;
|
||||
struct snd_soc_codec *codec;
|
||||
struct snd_soc_component *component;
|
||||
|
||||
|
@ -276,8 +275,6 @@ struct snd_soc_dai {
|
|||
unsigned int tx_mask;
|
||||
unsigned int rx_mask;
|
||||
|
||||
struct snd_soc_card *card;
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
|
|
@ -435,7 +435,7 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
|
|||
unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
|
||||
|
||||
/* Mostly internal - should not normally be used */
|
||||
void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
|
||||
void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
|
||||
|
||||
/* dapm path query */
|
||||
int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
|
||||
|
@ -508,9 +508,9 @@ struct snd_soc_dapm_path {
|
|||
|
||||
/* status */
|
||||
u32 connect:1; /* source and sink widgets are connected */
|
||||
u32 walked:1; /* path has been walked */
|
||||
u32 walking:1; /* path is in the process of being walked */
|
||||
u32 weak:1; /* path ignored for power management */
|
||||
u32 is_supply:1; /* At least one of the connected widgets is a supply */
|
||||
|
||||
int (*connected)(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink);
|
||||
|
@ -544,11 +544,13 @@ struct snd_soc_dapm_widget {
|
|||
unsigned char active:1; /* active stream on DAC, ADC's */
|
||||
unsigned char connected:1; /* connected codec pin */
|
||||
unsigned char new:1; /* cnew complete */
|
||||
unsigned char ext:1; /* has external widgets */
|
||||
unsigned char force:1; /* force state */
|
||||
unsigned char ignore_suspend:1; /* kept enabled over suspend */
|
||||
unsigned char new_power:1; /* power from this run */
|
||||
unsigned char power_checked:1; /* power checked this run */
|
||||
unsigned char is_supply:1; /* Widget is a supply type widget */
|
||||
unsigned char is_sink:1; /* Widget is a sink type widget */
|
||||
unsigned char is_source:1; /* Widget is a source type widget */
|
||||
int subseq; /* sort within widget type */
|
||||
|
||||
int (*power_check)(struct snd_soc_dapm_widget *w);
|
||||
|
@ -567,6 +569,7 @@ struct snd_soc_dapm_widget {
|
|||
struct list_head sinks;
|
||||
|
||||
/* used during DAPM updates */
|
||||
struct list_head work_list;
|
||||
struct list_head power_list;
|
||||
struct list_head dirty;
|
||||
int inputs;
|
||||
|
|
|
@ -36,6 +36,11 @@
|
|||
{.reg = xreg, .rreg = xreg, .shift = shift_left, \
|
||||
.rshift = shift_right, .max = xmax, .platform_max = xmax, \
|
||||
.invert = xinvert, .autodisable = xautodisable})
|
||||
#define SOC_DOUBLE_S_VALUE(xreg, shift_left, shift_right, xmin, xmax, xsign_bit, xinvert, xautodisable) \
|
||||
((unsigned long)&(struct soc_mixer_control) \
|
||||
{.reg = xreg, .rreg = xreg, .shift = shift_left, \
|
||||
.rshift = shift_right, .min = xmin, .max = xmax, .platform_max = xmax, \
|
||||
.sign_bit = xsign_bit, .invert = xinvert, .autodisable = xautodisable})
|
||||
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
|
||||
SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
|
||||
#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
|
||||
|
@ -171,11 +176,9 @@
|
|||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
|
||||
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
|
||||
.tlv.p = (tlv_array), \
|
||||
.info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
|
||||
.put = snd_soc_put_volsw_s8, \
|
||||
.private_value = (unsigned long)&(struct soc_mixer_control) \
|
||||
{.reg = xreg, .min = xmin, .max = xmax, \
|
||||
.platform_max = xmax} }
|
||||
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
|
||||
.put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_DOUBLE_S_VALUE(xreg, 0, 8, xmin, xmax, 7, 0, 0) }
|
||||
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \
|
||||
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
|
||||
.items = xitems, .texts = xtexts, \
|
||||
|
@ -366,8 +369,6 @@ struct snd_soc_jack_gpio;
|
|||
|
||||
typedef int (*hw_write_t)(void *,const char* ,int);
|
||||
|
||||
extern struct snd_ac97_bus_ops *soc_ac97_ops;
|
||||
|
||||
enum snd_soc_pcm_subclass {
|
||||
SND_SOC_PCM_CLASS_PCM = 0,
|
||||
SND_SOC_PCM_CLASS_BE = 1,
|
||||
|
@ -409,13 +410,9 @@ int devm_snd_soc_register_component(struct device *dev,
|
|||
const struct snd_soc_component_driver *cmpnt_drv,
|
||||
struct snd_soc_dai_driver *dai_drv, int num_dai);
|
||||
void snd_soc_unregister_component(struct device *dev);
|
||||
int snd_soc_cache_sync(struct snd_soc_codec *codec);
|
||||
int snd_soc_cache_init(struct snd_soc_codec *codec);
|
||||
int snd_soc_cache_exit(struct snd_soc_codec *codec);
|
||||
int snd_soc_cache_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int value);
|
||||
int snd_soc_cache_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int *value);
|
||||
|
||||
int snd_soc_platform_read(struct snd_soc_platform *platform,
|
||||
unsigned int reg);
|
||||
int snd_soc_platform_write(struct snd_soc_platform *platform,
|
||||
|
@ -500,14 +497,28 @@ int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
|
|||
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int mask, unsigned int value);
|
||||
|
||||
int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
|
||||
struct snd_ac97_bus_ops *ops, int num);
|
||||
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
|
||||
#ifdef CONFIG_SND_SOC_AC97_BUS
|
||||
struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec);
|
||||
void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
|
||||
|
||||
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
|
||||
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
|
||||
struct platform_device *pdev);
|
||||
|
||||
extern struct snd_ac97_bus_ops *soc_ac97_ops;
|
||||
#else
|
||||
static inline int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*Controls
|
||||
*/
|
||||
|
@ -545,12 +556,6 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
|
||||
|
@ -780,24 +785,18 @@ struct snd_soc_codec {
|
|||
struct device *dev;
|
||||
const struct snd_soc_codec_driver *driver;
|
||||
|
||||
struct mutex mutex;
|
||||
struct list_head list;
|
||||
struct list_head card_list;
|
||||
|
||||
/* runtime */
|
||||
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
|
||||
unsigned int cache_bypass:1; /* Suppress access to the cache */
|
||||
unsigned int suspended:1; /* Codec is in suspend PM state */
|
||||
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
|
||||
unsigned int ac97_created:1; /* Codec has been created by SoC */
|
||||
unsigned int cache_init:1; /* codec cache has been initialized */
|
||||
u32 cache_sync; /* Cache needs to be synced to hardware */
|
||||
|
||||
/* codec IO */
|
||||
void *control_data; /* codec control (i2c/3wire) data */
|
||||
hw_write_t hw_write;
|
||||
void *reg_cache;
|
||||
struct mutex cache_rw_mutex;
|
||||
|
||||
/* component */
|
||||
struct snd_soc_component component;
|
||||
|
@ -860,8 +859,6 @@ struct snd_soc_platform_driver {
|
|||
|
||||
int (*probe)(struct snd_soc_platform *);
|
||||
int (*remove)(struct snd_soc_platform *);
|
||||
int (*suspend)(struct snd_soc_dai *dai);
|
||||
int (*resume)(struct snd_soc_dai *dai);
|
||||
struct snd_soc_component_driver component_driver;
|
||||
|
||||
/* pcm creation and destruction */
|
||||
|
@ -886,7 +883,7 @@ struct snd_soc_platform_driver {
|
|||
|
||||
struct snd_soc_dai_link_component {
|
||||
const char *name;
|
||||
const struct device_node *of_node;
|
||||
struct device_node *of_node;
|
||||
const char *dai_name;
|
||||
};
|
||||
|
||||
|
@ -894,8 +891,6 @@ struct snd_soc_platform {
|
|||
struct device *dev;
|
||||
const struct snd_soc_platform_driver *driver;
|
||||
|
||||
unsigned int suspended:1; /* platform is suspended */
|
||||
|
||||
struct list_head list;
|
||||
|
||||
struct snd_soc_component component;
|
||||
|
@ -990,7 +985,7 @@ struct snd_soc_codec_conf {
|
|||
* DT/OF node, but not both.
|
||||
*/
|
||||
const char *dev_name;
|
||||
const struct device_node *of_node;
|
||||
struct device_node *of_node;
|
||||
|
||||
/*
|
||||
* optional map of kcontrol, widget and path name prefixes that are
|
||||
|
@ -1007,7 +1002,7 @@ struct snd_soc_aux_dev {
|
|||
* DT/OF node, but not both.
|
||||
*/
|
||||
const char *codec_name;
|
||||
const struct device_node *codec_of_node;
|
||||
struct device_node *codec_of_node;
|
||||
|
||||
/* codec/machine specific init - e.g. add machine controls */
|
||||
int (*init)(struct snd_soc_component *component);
|
||||
|
@ -1264,6 +1259,17 @@ 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);
|
||||
}
|
||||
|
||||
/* component IO */
|
||||
int snd_soc_component_read(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int *val);
|
||||
|
@ -1277,6 +1283,45 @@ void snd_soc_component_async_complete(struct snd_soc_component *component);
|
|||
int snd_soc_component_test_bits(struct snd_soc_component *component,
|
||||
unsigned int reg, unsigned int mask, unsigned int value);
|
||||
|
||||
#ifdef CONFIG_REGMAP
|
||||
|
||||
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 */
|
||||
|
||||
static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card,
|
||||
|
@ -1451,6 +1496,9 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
|
|||
struct device_node **framemaster);
|
||||
int snd_soc_of_get_dai_name(struct device_node *of_node,
|
||||
const char **dai_name);
|
||||
int snd_soc_of_get_dai_link_codecs(struct device *dev,
|
||||
struct device_node *of_node,
|
||||
struct snd_soc_dai_link *dai_link);
|
||||
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
|
|
|
@ -18,18 +18,6 @@ struct uda134x_platform_data {
|
|||
struct l3_pins l3;
|
||||
void (*power) (int);
|
||||
int model;
|
||||
/*
|
||||
ALSA SOC usually puts the device in standby mode when it's not used
|
||||
for sometime. If you unset is_powered_on_standby the driver will
|
||||
turn off the ADC/DAC when this callback is invoked and turn it back
|
||||
on when needed. Unfortunately this will result in a very light bump
|
||||
(it can be audible only with good earphones). If this bothers you
|
||||
set is_powered_on_standby, you will have slightly higher power
|
||||
consumption. Please note that sending the L3 command for ADC is
|
||||
enough to make the bump, so it doesn't make difference if you
|
||||
completely take off power from the codec.
|
||||
*/
|
||||
int is_powered_on_standby;
|
||||
#define UDA134X_UDA1340 1
|
||||
#define UDA134X_UDA1341 2
|
||||
#define UDA134X_UDA1344 3
|
||||
|
|
|
@ -288,31 +288,6 @@ TRACE_EVENT(snd_soc_jack_notify,
|
|||
TP_printk("jack=%s %x", __get_str(name), (int)__entry->val)
|
||||
);
|
||||
|
||||
TRACE_EVENT(snd_soc_cache_sync,
|
||||
|
||||
TP_PROTO(struct snd_soc_codec *codec, const char *type,
|
||||
const char *status),
|
||||
|
||||
TP_ARGS(codec, type, status),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string( name, codec->component.name)
|
||||
__string( status, status )
|
||||
__string( type, type )
|
||||
__field( int, id )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, codec->component.name);
|
||||
__assign_str(status, status);
|
||||
__assign_str(type, type);
|
||||
__entry->id = codec->component.id;
|
||||
),
|
||||
|
||||
TP_printk("codec=%s.%d type=%s status=%s", __get_str(name),
|
||||
(int)__entry->id, __get_str(type), __get_str(status))
|
||||
);
|
||||
|
||||
#endif /* _TRACE_ASOC_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
|
||||
snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o
|
||||
snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
|
||||
|
||||
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
|
||||
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_SND_SOC_AC97_BUS),)
|
||||
snd-soc-core-objs += soc-ac97.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
|
||||
obj-$(CONFIG_SND_SOC) += codecs/
|
||||
obj-$(CONFIG_SND_SOC) += generic/
|
||||
|
|
|
@ -52,12 +52,3 @@ config SND_AT91_SOC_SAM9X5_WM8731
|
|||
help
|
||||
Say Y if you want to add support for audio SoC on an
|
||||
at91sam9x5 based board that is using WM8731 codec.
|
||||
|
||||
config SND_AT91_SOC_AFEB9260
|
||||
tristate "SoC Audio support for AFEB9260 board"
|
||||
depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
|
||||
select SND_ATMEL_SOC_PDC
|
||||
select SND_ATMEL_SOC_SSC
|
||||
select SND_SOC_TLV320AIC23_I2C
|
||||
help
|
||||
Say Y here to support sound on AFEB9260 board.
|
||||
|
|
|
@ -17,4 +17,3 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
|
|||
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
|
||||
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
|
||||
obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
|
||||
obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
|
||||
|
|
|
@ -267,7 +267,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
|
|||
if (!ssc_p->dir_mask) {
|
||||
if (ssc_p->initialized) {
|
||||
/* Shutdown the SSC clock. */
|
||||
pr_debug("atmel_ssc_dau: Stopping clock\n");
|
||||
pr_debug("atmel_ssc_dai: Stopping clock\n");
|
||||
clk_disable(ssc_p->ssc->clk);
|
||||
|
||||
free_irq(ssc_p->ssc->irq, ssc_p);
|
||||
|
@ -310,7 +310,10 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
|
|||
* transmit and receive, so if a value has already
|
||||
* been set, it must match this value.
|
||||
*/
|
||||
if (ssc_p->cmr_div == 0)
|
||||
if (ssc_p->dir_mask !=
|
||||
(SSC_DIR_MASK_PLAYBACK | SSC_DIR_MASK_CAPTURE))
|
||||
ssc_p->cmr_div = div;
|
||||
else if (ssc_p->cmr_div == 0)
|
||||
ssc_p->cmr_div = div;
|
||||
else
|
||||
if (div != ssc_p->cmr_div)
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* afeb9260.c -- SoC audio for AFEB9260
|
||||
*
|
||||
* Copyright (C) 2009 Sergey Lapin <slapin@ossfans.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/atmel-ssc.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "../codecs/tlv320aic23.h"
|
||||
#include "atmel-pcm.h"
|
||||
#include "atmel_ssc_dai.h"
|
||||
|
||||
#define CODEC_CLOCK 12000000
|
||||
|
||||
static int afeb9260_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int err;
|
||||
|
||||
/* Set the codec system clock for DAC and ADC */
|
||||
err =
|
||||
snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
|
||||
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "can't set codec system clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops afeb9260_ops = {
|
||||
.hw_params = afeb9260_hw_params,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In", NULL),
|
||||
SND_SOC_DAPM_MIC("Mic Jack", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route afeb9260_audio_map[] = {
|
||||
{"Headphone Jack", NULL, "LHPOUT"},
|
||||
{"Headphone Jack", NULL, "RHPOUT"},
|
||||
|
||||
{"LLINEIN", NULL, "Line In"},
|
||||
{"RLINEIN", NULL, "Line In"},
|
||||
|
||||
{"MICIN", NULL, "Mic Jack"},
|
||||
};
|
||||
|
||||
|
||||
/* Digital audio interface glue - connects codec <--> CPU */
|
||||
static struct snd_soc_dai_link afeb9260_dai = {
|
||||
.name = "TLV320AIC23",
|
||||
.stream_name = "AIC23",
|
||||
.cpu_dai_name = "atmel-ssc-dai.0",
|
||||
.codec_dai_name = "tlv320aic23-hifi",
|
||||
.platform_name = "atmel_pcm-audio",
|
||||
.codec_name = "tlv320aic23-codec.0-001a",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
|
||||
SND_SOC_DAIFMT_CBM_CFM,
|
||||
.ops = &afeb9260_ops,
|
||||
};
|
||||
|
||||
/* Audio machine driver */
|
||||
static struct snd_soc_card snd_soc_machine_afeb9260 = {
|
||||
.name = "AFEB9260",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &afeb9260_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = tlv320aic23_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
|
||||
.dapm_routes = afeb9260_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(afeb9260_audio_map),
|
||||
};
|
||||
|
||||
static struct platform_device *afeb9260_snd_device;
|
||||
|
||||
static int __init afeb9260_soc_init(void)
|
||||
{
|
||||
int err;
|
||||
struct device *dev;
|
||||
|
||||
if (!(machine_is_afeb9260()))
|
||||
return -ENODEV;
|
||||
|
||||
|
||||
afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
|
||||
if (!afeb9260_snd_device) {
|
||||
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
|
||||
err = platform_device_add(afeb9260_snd_device);
|
||||
if (err)
|
||||
goto err1;
|
||||
|
||||
dev = &afeb9260_snd_device->dev;
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
platform_device_put(afeb9260_snd_device);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit afeb9260_soc_exit(void)
|
||||
{
|
||||
platform_device_unregister(afeb9260_snd_device);
|
||||
}
|
||||
|
||||
module_init(afeb9260_soc_init);
|
||||
module_exit(afeb9260_soc_exit);
|
||||
|
||||
MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
|
||||
MODULE_DESCRIPTION("ALSA SoC for AFEB9260");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -205,7 +205,7 @@ static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
|
|||
|
||||
static struct snd_soc_dai_driver au1xac97c_dai_driver = {
|
||||
.name = "alchemy-ac97c",
|
||||
.ac97_control = 1,
|
||||
.bus_control = true,
|
||||
.probe = au1xac97c_dai_probe,
|
||||
.playback = {
|
||||
.rates = AC97_RATES,
|
||||
|
|
|
@ -343,7 +343,7 @@ static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
|
|||
};
|
||||
|
||||
static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
|
||||
.ac97_control = 1,
|
||||
.bus_control = true,
|
||||
.probe = au1xpsc_ac97_probe,
|
||||
.playback = {
|
||||
.rates = AC97_RATES,
|
||||
|
|
|
@ -260,7 +260,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
|
|||
#endif
|
||||
|
||||
static struct snd_soc_dai_driver bfin_ac97_dai = {
|
||||
.ac97_control = 1,
|
||||
.bus_control = true,
|
||||
.suspend = bf5xx_ac97_suspend,
|
||||
.resume = bf5xx_ac97_resume,
|
||||
.playback = {
|
||||
|
|
|
@ -46,8 +46,6 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
#include "../codecs/ad1980.h"
|
||||
|
||||
#include "bf5xx-ac97.h"
|
||||
|
||||
static struct snd_soc_card bf5xx_board;
|
||||
|
|
|
@ -36,7 +36,8 @@ config SND_EP93XX_SOC_EDB93XX
|
|||
tristate "SoC Audio support for Cirrus Logic EDB93xx boards"
|
||||
depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A)
|
||||
select SND_EP93XX_SOC_I2S
|
||||
select SND_SOC_CS4271
|
||||
select SND_SOC_CS4271_I2C if I2C
|
||||
select SND_SOC_CS4271_SPI if SPI_MASTER
|
||||
help
|
||||
Say Y or M here if you want to add support for I2S audio on the
|
||||
Cirrus Logic EDB93xx boards.
|
||||
|
|
|
@ -338,7 +338,7 @@ static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
|
|||
static struct snd_soc_dai_driver ep93xx_ac97_dai = {
|
||||
.name = "ep93xx-ac97",
|
||||
.id = 0,
|
||||
.ac97_control = 1,
|
||||
.bus_control = true,
|
||||
.probe = ep93xx_ac97_dai_probe,
|
||||
.playback = {
|
||||
.stream_name = "AC97 Playback",
|
||||
|
|
|
@ -50,7 +50,8 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_CS42L73 if I2C
|
||||
select SND_SOC_CS4265 if I2C
|
||||
select SND_SOC_CS4270 if I2C
|
||||
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_CS4271_I2C if I2C
|
||||
select SND_SOC_CS4271_SPI if SPI_MASTER
|
||||
select SND_SOC_CS42XX8_I2C if I2C
|
||||
select SND_SOC_CX20442 if TTY
|
||||
select SND_SOC_DA7210 if I2C
|
||||
|
@ -85,7 +86,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_RT5645 if I2C
|
||||
select SND_SOC_RT5651 if I2C
|
||||
select SND_SOC_RT5670 if I2C
|
||||
select SND_SOC_RT5677 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
|
||||
|
@ -101,6 +102,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_TAS2552 if I2C
|
||||
select SND_SOC_TAS5086 if I2C
|
||||
select SND_SOC_TFA9879 if I2C
|
||||
select SND_SOC_TLV320AIC23_I2C if I2C
|
||||
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
|
||||
select SND_SOC_TLV320AIC26 if SPI_MASTER
|
||||
|
@ -109,6 +111,7 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_TLV320AIC3X if I2C
|
||||
select SND_SOC_TPA6130A2 if I2C
|
||||
select SND_SOC_TLV320DAC33 if I2C
|
||||
select SND_SOC_TS3A227E if I2C
|
||||
select SND_SOC_TWL4030 if TWL4030_CORE
|
||||
select SND_SOC_TWL6040 if TWL6040_CORE
|
||||
select SND_SOC_UDA134X
|
||||
|
@ -223,6 +226,7 @@ config SND_SOC_AD193X_I2C
|
|||
select SND_SOC_AD193X
|
||||
|
||||
config SND_SOC_AD1980
|
||||
select REGMAP_AC97
|
||||
tristate
|
||||
|
||||
config SND_SOC_AD73311
|
||||
|
@ -336,7 +340,8 @@ config SND_SOC_CS42L51
|
|||
tristate
|
||||
|
||||
config SND_SOC_CS42L51_I2C
|
||||
tristate
|
||||
tristate "Cirrus Logic CS42L51 CODEC (I2C)"
|
||||
depends on I2C
|
||||
select SND_SOC_CS42L51
|
||||
|
||||
config SND_SOC_CS42L52
|
||||
|
@ -370,8 +375,19 @@ config SND_SOC_CS4270_VD33_ERRATA
|
|||
depends on SND_SOC_CS4270
|
||||
|
||||
config SND_SOC_CS4271
|
||||
tristate "Cirrus Logic CS4271 CODEC"
|
||||
depends on SND_SOC_I2C_AND_SPI
|
||||
tristate
|
||||
|
||||
config SND_SOC_CS4271_I2C
|
||||
tristate "Cirrus Logic CS4271 CODEC (I2C)"
|
||||
depends on I2C
|
||||
select SND_SOC_CS4271
|
||||
select REGMAP_I2C
|
||||
|
||||
config SND_SOC_CS4271_SPI
|
||||
tristate "Cirrus Logic CS4271 CODEC (SPI)"
|
||||
depends on SPI_MASTER
|
||||
select SND_SOC_CS4271
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_CS42XX8
|
||||
tristate
|
||||
|
@ -487,7 +503,8 @@ config SND_SOC_RT286
|
|||
depends on I2C
|
||||
|
||||
config SND_SOC_RT5631
|
||||
tristate
|
||||
tristate "Realtek ALC5631/RT5631 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_RT5640
|
||||
tristate
|
||||
|
@ -503,6 +520,12 @@ config SND_SOC_RT5670
|
|||
|
||||
config SND_SOC_RT5677
|
||||
tristate
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
|
||||
config SND_SOC_RT5677_SPI
|
||||
tristate
|
||||
default SND_SOC_RT5677
|
||||
|
||||
#Freescale sgtl5000 codec
|
||||
config SND_SOC_SGTL5000
|
||||
|
@ -577,15 +600,21 @@ config SND_SOC_TAS5086
|
|||
tristate "Texas Instruments TAS5086 speaker amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TFA9879
|
||||
tristate "NXP Semiconductors TFA9879 amplifier"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TLV320AIC23
|
||||
tristate
|
||||
|
||||
config SND_SOC_TLV320AIC23_I2C
|
||||
tristate
|
||||
tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C"
|
||||
depends on I2C
|
||||
select SND_SOC_TLV320AIC23
|
||||
|
||||
config SND_SOC_TLV320AIC23_SPI
|
||||
tristate
|
||||
tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI"
|
||||
depends on SPI_MASTER
|
||||
select SND_SOC_TLV320AIC23
|
||||
|
||||
config SND_SOC_TLV320AIC26
|
||||
|
@ -607,6 +636,10 @@ config SND_SOC_TLV320AIC3X
|
|||
config SND_SOC_TLV320DAC33
|
||||
tristate
|
||||
|
||||
config SND_SOC_TS3A227E
|
||||
tristate "TI Headset/Mic detect and keypress chip"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_TWL4030
|
||||
select MFD_TWL4030_AUDIO
|
||||
tristate
|
||||
|
|
|
@ -41,6 +41,8 @@ snd-soc-cs42l73-objs := cs42l73.o
|
|||
snd-soc-cs4265-objs := cs4265.o
|
||||
snd-soc-cs4270-objs := cs4270.o
|
||||
snd-soc-cs4271-objs := cs4271.o
|
||||
snd-soc-cs4271-i2c-objs := cs4271-i2c.o
|
||||
snd-soc-cs4271-spi-objs := cs4271-spi.o
|
||||
snd-soc-cs42xx8-objs := cs42xx8.o
|
||||
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
|
||||
snd-soc-cx20442-objs := cx20442.o
|
||||
|
@ -80,6 +82,7 @@ snd-soc-rt5645-objs := rt5645.o
|
|||
snd-soc-rt5651-objs := rt5651.o
|
||||
snd-soc-rt5670-objs := rt5670.o
|
||||
snd-soc-rt5677-objs := rt5677.o
|
||||
snd-soc-rt5677-spi-objs := rt5677-spi.o
|
||||
snd-soc-sgtl5000-objs := sgtl5000.o
|
||||
snd-soc-alc5623-objs := alc5623.o
|
||||
snd-soc-alc5632-objs := alc5632.o
|
||||
|
@ -101,6 +104,7 @@ snd-soc-sta350-objs := sta350.o
|
|||
snd-soc-sta529-objs := sta529.o
|
||||
snd-soc-stac9766-objs := stac9766.o
|
||||
snd-soc-tas5086-objs := tas5086.o
|
||||
snd-soc-tfa9879-objs := tfa9879.o
|
||||
snd-soc-tlv320aic23-objs := tlv320aic23.o
|
||||
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
|
||||
snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
|
||||
|
@ -109,6 +113,7 @@ snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
|
|||
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
|
||||
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
|
||||
snd-soc-tlv320dac33-objs := tlv320dac33.o
|
||||
snd-soc-ts3a227e-objs := ts3a227e.o
|
||||
snd-soc-twl4030-objs := twl4030.o
|
||||
snd-soc-twl6040-objs := twl6040.o
|
||||
snd-soc-uda134x-objs := uda134x.o
|
||||
|
@ -217,6 +222,8 @@ obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
|
|||
obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o
|
||||
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
|
||||
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
|
||||
obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o
|
||||
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
|
||||
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
|
||||
|
@ -256,6 +263,7 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
|
|||
obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.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
|
||||
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
|
||||
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
|
||||
obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
|
||||
|
@ -274,6 +282,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
|
|||
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
|
||||
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
|
||||
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
|
||||
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
|
||||
|
@ -282,6 +291,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o
|
|||
obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.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
|
||||
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
|
||||
|
|
|
@ -126,13 +126,13 @@ struct ab8500_codec_drvdata_dbg {
|
|||
/* Private data for AB8500 device-driver */
|
||||
struct ab8500_codec_drvdata {
|
||||
struct regmap *regmap;
|
||||
struct mutex ctrl_lock;
|
||||
|
||||
/* Sidetone */
|
||||
long *sid_fir_values;
|
||||
enum sid_state sid_status;
|
||||
|
||||
/* ANC */
|
||||
struct mutex anc_lock;
|
||||
long *anc_fir_values;
|
||||
long *anc_iir_values;
|
||||
enum anc_state anc_status;
|
||||
|
@ -1129,9 +1129,9 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
mutex_lock(&drvdata->ctrl_lock);
|
||||
ucontrol->value.integer.value[0] = drvdata->sid_status;
|
||||
mutex_unlock(&codec->mutex);
|
||||
mutex_unlock(&drvdata->ctrl_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1154,7 +1154,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
mutex_lock(&drvdata->ctrl_lock);
|
||||
|
||||
sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF);
|
||||
if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
|
||||
|
@ -1185,7 +1185,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
|
|||
drvdata->sid_status = SID_FIR_CONFIGURED;
|
||||
|
||||
out:
|
||||
mutex_unlock(&codec->mutex);
|
||||
mutex_unlock(&drvdata->ctrl_lock);
|
||||
|
||||
dev_dbg(codec->dev, "%s: Exit\n", __func__);
|
||||
|
||||
|
@ -1198,9 +1198,9 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
mutex_lock(&drvdata->ctrl_lock);
|
||||
ucontrol->value.integer.value[0] = drvdata->anc_status;
|
||||
mutex_unlock(&codec->mutex);
|
||||
mutex_unlock(&drvdata->ctrl_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1217,7 +1217,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
|
|||
|
||||
dev_dbg(dev, "%s: Enter.\n", __func__);
|
||||
|
||||
mutex_lock(&drvdata->anc_lock);
|
||||
mutex_lock(&drvdata->ctrl_lock);
|
||||
|
||||
req = ucontrol->value.integer.value[0];
|
||||
if (req >= ARRAY_SIZE(enum_anc_state)) {
|
||||
|
@ -1244,9 +1244,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
|
|||
}
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
anc_configure(codec, apply_fir, apply_iir);
|
||||
mutex_unlock(&codec->mutex);
|
||||
|
||||
if (apply_fir) {
|
||||
if (drvdata->anc_status == ANC_IIR_CONFIGURED)
|
||||
|
@ -1265,7 +1263,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
|
|||
snd_soc_dapm_sync(&codec->dapm);
|
||||
|
||||
cleanup:
|
||||
mutex_unlock(&drvdata->anc_lock);
|
||||
mutex_unlock(&drvdata->ctrl_lock);
|
||||
|
||||
if (status < 0)
|
||||
dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n",
|
||||
|
@ -1294,14 +1292,15 @@ static int filter_control_get(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec);
|
||||
struct filter_control *fc =
|
||||
(struct filter_control *)kcontrol->private_value;
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
mutex_lock(&drvdata->ctrl_lock);
|
||||
for (i = 0; i < fc->count; i++)
|
||||
ucontrol->value.integer.value[i] = fc->value[i];
|
||||
mutex_unlock(&codec->mutex);
|
||||
mutex_unlock(&drvdata->ctrl_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1310,14 +1309,15 @@ static int filter_control_put(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec);
|
||||
struct filter_control *fc =
|
||||
(struct filter_control *)kcontrol->private_value;
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
mutex_lock(&drvdata->ctrl_lock);
|
||||
for (i = 0; i < fc->count; i++)
|
||||
fc->value[i] = ucontrol->value.integer.value[i];
|
||||
mutex_unlock(&codec->mutex);
|
||||
mutex_unlock(&drvdata->ctrl_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2545,7 +2545,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
|
|||
|
||||
(void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
|
||||
|
||||
mutex_init(&drvdata->anc_lock);
|
||||
mutex_init(&drvdata->ctrl_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -37,10 +37,11 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
||||
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
|
||||
return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate);
|
||||
return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
|
||||
}
|
||||
|
||||
#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
|
@ -53,7 +54,6 @@ static const struct snd_soc_dai_ops ac97_dai_ops = {
|
|||
|
||||
static struct snd_soc_dai_driver ac97_dai = {
|
||||
.name = "ac97-hifi",
|
||||
.ac97_control = 1,
|
||||
.playback = {
|
||||
.stream_name = "AC97 Playback",
|
||||
.channels_min = 1,
|
||||
|
@ -71,6 +71,7 @@ static struct snd_soc_dai_driver ac97_dai = {
|
|||
|
||||
static int ac97_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_ac97 *ac97;
|
||||
struct snd_ac97_bus *ac97_bus;
|
||||
struct snd_ac97_template ac97_template;
|
||||
int ret;
|
||||
|
@ -82,24 +83,31 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
|
|||
return ret;
|
||||
|
||||
memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
|
||||
ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
|
||||
ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, ac97);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ac97_soc_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_ac97_suspend(codec->ac97);
|
||||
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
snd_ac97_suspend(ac97);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac97_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_ac97_resume(codec->ac97);
|
||||
|
||||
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
snd_ac97_resume(ac97);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -72,11 +72,13 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = {
|
|||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1),
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
|
||||
SND_SOC_DAPM_VMID("VMID"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC1OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC2OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC3OUT"),
|
||||
|
@ -87,13 +89,15 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
|
|||
|
||||
static const struct snd_soc_dapm_route audio_paths[] = {
|
||||
{ "DAC", NULL, "SYSCLK" },
|
||||
{ "DAC Output", NULL, "DAC" },
|
||||
{ "DAC Output", NULL, "VMID" },
|
||||
{ "ADC", NULL, "SYSCLK" },
|
||||
{ "DAC", NULL, "ADC_PWR" },
|
||||
{ "ADC", NULL, "ADC_PWR" },
|
||||
{ "DAC1OUT", NULL, "DAC" },
|
||||
{ "DAC2OUT", NULL, "DAC" },
|
||||
{ "DAC3OUT", NULL, "DAC" },
|
||||
{ "DAC4OUT", NULL, "DAC" },
|
||||
{ "DAC1OUT", NULL, "DAC Output" },
|
||||
{ "DAC2OUT", NULL, "DAC Output" },
|
||||
{ "DAC3OUT", NULL, "DAC Output" },
|
||||
{ "DAC4OUT", NULL, "DAC Output" },
|
||||
{ "ADC", NULL, "ADC1IN" },
|
||||
{ "ADC", NULL, "ADC2IN" },
|
||||
{ "SYSCLK", NULL, "PLL_PWR" },
|
||||
|
|
|
@ -24,34 +24,86 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "ad1980.h"
|
||||
static const struct reg_default ad1980_reg_defaults[] = {
|
||||
{ 0x02, 0x8000 },
|
||||
{ 0x04, 0x8000 },
|
||||
{ 0x06, 0x8000 },
|
||||
{ 0x0c, 0x8008 },
|
||||
{ 0x0e, 0x8008 },
|
||||
{ 0x10, 0x8808 },
|
||||
{ 0x12, 0x8808 },
|
||||
{ 0x16, 0x8808 },
|
||||
{ 0x18, 0x8808 },
|
||||
{ 0x1a, 0x0000 },
|
||||
{ 0x1c, 0x8000 },
|
||||
{ 0x20, 0x0000 },
|
||||
{ 0x28, 0x03c7 },
|
||||
{ 0x2c, 0xbb80 },
|
||||
{ 0x2e, 0xbb80 },
|
||||
{ 0x30, 0xbb80 },
|
||||
{ 0x32, 0xbb80 },
|
||||
{ 0x36, 0x8080 },
|
||||
{ 0x38, 0x8080 },
|
||||
{ 0x3a, 0x2000 },
|
||||
{ 0x60, 0x0000 },
|
||||
{ 0x62, 0x0000 },
|
||||
{ 0x72, 0x0000 },
|
||||
{ 0x74, 0x1001 },
|
||||
{ 0x76, 0x0000 },
|
||||
};
|
||||
|
||||
/*
|
||||
* AD1980 register cache
|
||||
*/
|
||||
static const u16 ad1980_reg[] = {
|
||||
0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */
|
||||
0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */
|
||||
0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */
|
||||
0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */
|
||||
0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */
|
||||
0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */
|
||||
0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
|
||||
0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */
|
||||
0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */
|
||||
static bool ad1980_readable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case AC97_RESET ... AC97_MASTER_MONO:
|
||||
case AC97_PHONE ... AC97_CD:
|
||||
case AC97_AUX ... AC97_GENERAL_PURPOSE:
|
||||
case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE:
|
||||
case AC97_SPDIF:
|
||||
case AC97_CODEC_CLASS_REV:
|
||||
case AC97_PCI_SVID:
|
||||
case AC97_AD_CODEC_CFG:
|
||||
case AC97_AD_JACK_SPDIF:
|
||||
case AC97_AD_SERIAL_CFG:
|
||||
case AC97_VENDOR_ID1:
|
||||
case AC97_VENDOR_ID2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ad1980_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case AC97_VENDOR_ID1:
|
||||
case AC97_VENDOR_ID2:
|
||||
return false;
|
||||
default:
|
||||
return ad1980_readable_reg(dev, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config ad1980_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.reg_stride = 2,
|
||||
.val_bits = 16,
|
||||
.max_register = 0x7e,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.volatile_reg = regmap_ac97_default_volatile,
|
||||
.readable_reg = ad1980_readable_reg,
|
||||
.writeable_reg = ad1980_writeable_reg,
|
||||
|
||||
.reg_defaults = ad1980_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults),
|
||||
};
|
||||
|
||||
static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
|
||||
|
@ -134,45 +186,8 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = {
|
|||
{ "HP_OUT_R", NULL, "Playback" },
|
||||
};
|
||||
|
||||
static unsigned int ac97_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
switch (reg) {
|
||||
case AC97_RESET:
|
||||
case AC97_INT_PAGING:
|
||||
case AC97_POWERDOWN:
|
||||
case AC97_EXTENDED_STATUS:
|
||||
case AC97_VENDOR_ID1:
|
||||
case AC97_VENDOR_ID2:
|
||||
return soc_ac97_ops->read(codec->ac97, reg);
|
||||
default:
|
||||
reg = reg >> 1;
|
||||
|
||||
if (reg >= ARRAY_SIZE(ad1980_reg))
|
||||
return -EINVAL;
|
||||
|
||||
return cache[reg];
|
||||
}
|
||||
}
|
||||
|
||||
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
soc_ac97_ops->write(codec->ac97, reg, val);
|
||||
reg = reg >> 1;
|
||||
if (reg < ARRAY_SIZE(ad1980_reg))
|
||||
cache[reg] = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver ad1980_dai = {
|
||||
.name = "ad1980-hifi",
|
||||
.ac97_control = 1,
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
|
@ -189,108 +204,115 @@ static struct snd_soc_dai_driver ad1980_dai = {
|
|||
|
||||
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
|
||||
{
|
||||
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int retry_cnt = 0;
|
||||
|
||||
do {
|
||||
if (try_warm && soc_ac97_ops->warm_reset) {
|
||||
soc_ac97_ops->warm_reset(codec->ac97);
|
||||
if (ac97_read(codec, AC97_RESET) == 0x0090)
|
||||
soc_ac97_ops->warm_reset(ac97);
|
||||
if (snd_soc_read(codec, AC97_RESET) == 0x0090)
|
||||
return 1;
|
||||
}
|
||||
|
||||
soc_ac97_ops->reset(codec->ac97);
|
||||
soc_ac97_ops->reset(ac97);
|
||||
/*
|
||||
* Set bit 16slot in register 74h, then every slot will has only
|
||||
* 16 bits. This command is sent out in 20bit mode, in which
|
||||
* case the first nibble of data is eaten by the addr. (Tag is
|
||||
* always 16 bit)
|
||||
*/
|
||||
ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
|
||||
snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
|
||||
|
||||
if (ac97_read(codec, AC97_RESET) == 0x0090)
|
||||
if (snd_soc_read(codec, AC97_RESET) == 0x0090)
|
||||
return 0;
|
||||
} while (retry_cnt++ < 10);
|
||||
|
||||
printk(KERN_ERR "AD1980 AC97 reset failed\n");
|
||||
dev_err(codec->dev, "Failed to reset: AC97 link error\n");
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ad1980_soc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_ac97 *ac97;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
u16 vendor_id2;
|
||||
u16 ext_status;
|
||||
|
||||
printk(KERN_INFO "AD1980 SoC Audio Codec\n");
|
||||
|
||||
ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
|
||||
ac97 = snd_soc_new_ac97_codec(codec);
|
||||
if (IS_ERR(ac97)) {
|
||||
ret = PTR_ERR(ac97);
|
||||
dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad1980_reset(codec, 0);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
|
||||
goto reset_err;
|
||||
regmap = regmap_init_ac97(ac97, &ad1980_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
ret = PTR_ERR(regmap);
|
||||
goto err_free_ac97;
|
||||
}
|
||||
|
||||
snd_soc_codec_init_regmap(codec, regmap);
|
||||
snd_soc_codec_set_drvdata(codec, ac97);
|
||||
|
||||
ret = ad1980_reset(codec, 0);
|
||||
if (ret < 0)
|
||||
goto reset_err;
|
||||
|
||||
/* Read out vendor ID to make sure it is ad1980 */
|
||||
if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) {
|
||||
if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) {
|
||||
ret = -ENODEV;
|
||||
goto reset_err;
|
||||
}
|
||||
|
||||
vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);
|
||||
vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2);
|
||||
|
||||
if (vendor_id2 != 0x5370) {
|
||||
if (vendor_id2 != 0x5374) {
|
||||
ret = -ENODEV;
|
||||
goto reset_err;
|
||||
} else {
|
||||
printk(KERN_WARNING "ad1980: "
|
||||
"Found AD1981 - only 2/2 IN/OUT Channels "
|
||||
"supported\n");
|
||||
dev_warn(codec->dev,
|
||||
"Found AD1981 - only 2/2 IN/OUT Channels supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* unmute captures and playbacks volume */
|
||||
ac97_write(codec, AC97_MASTER, 0x0000);
|
||||
ac97_write(codec, AC97_PCM, 0x0000);
|
||||
ac97_write(codec, AC97_REC_GAIN, 0x0000);
|
||||
ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
|
||||
ac97_write(codec, AC97_SURROUND_MASTER, 0x0000);
|
||||
snd_soc_write(codec, AC97_MASTER, 0x0000);
|
||||
snd_soc_write(codec, AC97_PCM, 0x0000);
|
||||
snd_soc_write(codec, AC97_REC_GAIN, 0x0000);
|
||||
snd_soc_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
|
||||
snd_soc_write(codec, AC97_SURROUND_MASTER, 0x0000);
|
||||
|
||||
/*power on LFE/CENTER/Surround DACs*/
|
||||
ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
|
||||
ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
|
||||
|
||||
snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls,
|
||||
ARRAY_SIZE(ad1980_snd_ac97_controls));
|
||||
ext_status = snd_soc_read(codec, AC97_EXTENDED_STATUS);
|
||||
snd_soc_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
|
||||
|
||||
return 0;
|
||||
|
||||
reset_err:
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
snd_soc_codec_exit_regmap(codec);
|
||||
err_free_ac97:
|
||||
snd_soc_free_ac97_codec(ac97);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad1980_soc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
snd_soc_codec_exit_regmap(codec);
|
||||
snd_soc_free_ac97_codec(ac97);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
|
||||
.probe = ad1980_soc_probe,
|
||||
.remove = ad1980_soc_remove,
|
||||
.reg_cache_size = ARRAY_SIZE(ad1980_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = ad1980_reg,
|
||||
.reg_cache_step = 2,
|
||||
.write = ac97_write,
|
||||
.read = ac97_read,
|
||||
|
||||
.controls = ad1980_snd_ac97_controls,
|
||||
.num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls),
|
||||
.dapm_widgets = ad1980_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
|
||||
.dapm_routes = ad1980_dapm_routes,
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* ad1980.h -- ad1980 Soc Audio driver
|
||||
*
|
||||
* WARNING:
|
||||
*
|
||||
* Because Analog Devices Inc. discontinued the ad1980 sound chip since
|
||||
* Sep. 2009, this ad1980 driver is not maintained, tested and supported
|
||||
* by ADI now.
|
||||
*/
|
||||
|
||||
#ifndef _AD1980_H
|
||||
#define _AD1980_H
|
||||
/* Bit definition of Power-Down Control/Status Register */
|
||||
#define ADC 0x0001
|
||||
#define DAC 0x0002
|
||||
#define ANL 0x0004
|
||||
#define REF 0x0008
|
||||
#define PR0 0x0100
|
||||
#define PR1 0x0200
|
||||
#define PR2 0x0400
|
||||
#define PR3 0x0800
|
||||
#define PR4 0x1000
|
||||
#define PR5 0x2000
|
||||
#define PR6 0x4000
|
||||
|
||||
#endif
|
|
@ -551,7 +551,7 @@ static const struct snd_kcontrol_new adau1373_drc_controls[] = {
|
|||
static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int pll_id = w->name[3] - '1';
|
||||
unsigned int val;
|
||||
|
@ -823,7 +823,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {
|
|||
static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct snd_soc_codec *codec = source->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int dai;
|
||||
const char *clk;
|
||||
|
@ -844,7 +844,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
|
|||
static int adau1373_check_src(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct snd_soc_codec *codec = source->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int dai;
|
||||
|
||||
|
|
|
@ -22,9 +22,14 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "sigmadsp.h"
|
||||
#include "adau1701.h"
|
||||
|
||||
#define ADAU1701_SAFELOAD_DATA(i) (0x0810 + (i))
|
||||
#define ADAU1701_SAFELOAD_ADDR(i) (0x0815 + (i))
|
||||
|
||||
#define ADAU1701_DSPCTRL 0x081c
|
||||
#define ADAU1701_SEROCTL 0x081e
|
||||
#define ADAU1701_SERICTL 0x081f
|
||||
|
@ -42,6 +47,7 @@
|
|||
#define ADAU1701_DSPCTRL_CR (1 << 2)
|
||||
#define ADAU1701_DSPCTRL_DAM (1 << 3)
|
||||
#define ADAU1701_DSPCTRL_ADM (1 << 4)
|
||||
#define ADAU1701_DSPCTRL_IST (1 << 5)
|
||||
#define ADAU1701_DSPCTRL_SR_48 0x00
|
||||
#define ADAU1701_DSPCTRL_SR_96 0x01
|
||||
#define ADAU1701_DSPCTRL_SR_192 0x02
|
||||
|
@ -102,7 +108,10 @@ struct adau1701 {
|
|||
unsigned int pll_clkdiv;
|
||||
unsigned int sysclk;
|
||||
struct regmap *regmap;
|
||||
struct i2c_client *client;
|
||||
u8 pin_config[12];
|
||||
|
||||
struct sigmadsp *sigmadsp;
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new adau1701_controls[] = {
|
||||
|
@ -159,6 +168,7 @@ static bool adau1701_volatile_reg(struct device *dev, unsigned int reg)
|
|||
{
|
||||
switch (reg) {
|
||||
case ADAU1701_DACSET:
|
||||
case ADAU1701_DSPCTRL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -238,12 +248,58 @@ static int adau1701_reg_read(void *context, unsigned int reg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
|
||||
static int adau1701_safeload(struct sigmadsp *sigmadsp, unsigned int addr,
|
||||
const uint8_t bytes[], size_t len)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(sigmadsp->dev);
|
||||
struct adau1701 *adau1701 = i2c_get_clientdata(client);
|
||||
unsigned int val;
|
||||
unsigned int i;
|
||||
uint8_t buf[10];
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(adau1701->regmap, ADAU1701_DSPCTRL, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val & ADAU1701_DSPCTRL_IST)
|
||||
msleep(50);
|
||||
|
||||
for (i = 0; i < len / 4; i++) {
|
||||
put_unaligned_le16(ADAU1701_SAFELOAD_DATA(i), buf);
|
||||
buf[2] = 0x00;
|
||||
memcpy(buf + 3, bytes + i * 4, 4);
|
||||
ret = i2c_master_send(client, buf, 7);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret != 7)
|
||||
return -EIO;
|
||||
|
||||
put_unaligned_le16(ADAU1701_SAFELOAD_ADDR(i), buf);
|
||||
put_unaligned_le16(addr + i, buf + 2);
|
||||
ret = i2c_master_send(client, buf, 4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret != 4)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
|
||||
ADAU1701_DSPCTRL_IST, ADAU1701_DSPCTRL_IST);
|
||||
}
|
||||
|
||||
static const struct sigmadsp_ops adau1701_sigmadsp_ops = {
|
||||
.safeload = adau1701_safeload,
|
||||
};
|
||||
|
||||
static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv,
|
||||
unsigned int rate)
|
||||
{
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *client = to_i2c_client(codec->dev);
|
||||
int ret;
|
||||
|
||||
sigmadsp_reset(adau1701->sigmadsp);
|
||||
|
||||
if (clkdiv != ADAU1707_CLKDIV_UNSET &&
|
||||
gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
|
||||
gpio_is_valid(adau1701->gpio_pll_mode[1])) {
|
||||
|
@ -284,7 +340,7 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
|
|||
* know the correct PLL setup
|
||||
*/
|
||||
if (clkdiv != ADAU1707_CLKDIV_UNSET) {
|
||||
ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
|
||||
ret = sigmadsp_setup(adau1701->sigmadsp, rate);
|
||||
if (ret) {
|
||||
dev_warn(codec->dev, "Failed to load firmware\n");
|
||||
return ret;
|
||||
|
@ -385,7 +441,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
|
|||
* firmware upload.
|
||||
*/
|
||||
if (clkdiv != adau1701->pll_clkdiv) {
|
||||
ret = adau1701_reset(codec, clkdiv);
|
||||
ret = adau1701_reset(codec, clkdiv, params_rate(params));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
@ -554,6 +610,14 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adau1701_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(dai->codec);
|
||||
|
||||
return sigmadsp_restrict_params(adau1701->sigmadsp, substream);
|
||||
}
|
||||
|
||||
#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
|
||||
SNDRV_PCM_RATE_192000)
|
||||
|
||||
|
@ -564,6 +628,7 @@ static const struct snd_soc_dai_ops adau1701_dai_ops = {
|
|||
.set_fmt = adau1701_set_dai_fmt,
|
||||
.hw_params = adau1701_hw_params,
|
||||
.digital_mute = adau1701_digital_mute,
|
||||
.startup = adau1701_startup,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver adau1701_dai = {
|
||||
|
@ -600,6 +665,10 @@ static int adau1701_probe(struct snd_soc_codec *codec)
|
|||
unsigned int val;
|
||||
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ret = sigmadsp_attach(adau1701->sigmadsp, &codec->component);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Let the pll_clkdiv variable default to something that won't happen
|
||||
* at runtime. That way, we can postpone the firmware download from
|
||||
|
@ -609,7 +678,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
|
|||
adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
|
||||
|
||||
/* initalize with pre-configured pll mode settings */
|
||||
ret = adau1701_reset(codec, adau1701->pll_clkdiv);
|
||||
ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -667,6 +736,7 @@ static int adau1701_i2c_probe(struct i2c_client *client,
|
|||
if (!adau1701)
|
||||
return -ENOMEM;
|
||||
|
||||
adau1701->client = client;
|
||||
adau1701->regmap = devm_regmap_init(dev, NULL, client,
|
||||
&adau1701_regmap);
|
||||
if (IS_ERR(adau1701->regmap))
|
||||
|
@ -722,6 +792,12 @@ static int adau1701_i2c_probe(struct i2c_client *client,
|
|||
adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];
|
||||
|
||||
i2c_set_clientdata(client, adau1701);
|
||||
|
||||
adau1701->sigmadsp = devm_sigmadsp_init_i2c(client,
|
||||
&adau1701_sigmadsp_ops, ADAU1701_FIRMWARE);
|
||||
if (IS_ERR(adau1701->sigmadsp))
|
||||
return PTR_ERR(adau1701->sigmadsp);
|
||||
|
||||
ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
|
||||
&adau1701_dai, 1);
|
||||
return ret;
|
||||
|
|
|
@ -255,7 +255,8 @@ static const struct snd_kcontrol_new adau1761_input_mux_control =
|
|||
static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* After any power changes have been made the dejitter circuit
|
||||
* has to be reinitialized. */
|
||||
|
@ -702,11 +703,6 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
|
|||
ARRAY_SIZE(adau1761_dapm_routes));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adau17x1_load_firmware(adau, codec->dev,
|
||||
ADAU1761_FIRMWARE);
|
||||
if (ret)
|
||||
dev_warn(codec->dev, "Failed to firmware\n");
|
||||
}
|
||||
|
||||
ret = adau17x1_add_routes(codec);
|
||||
|
@ -775,17 +771,21 @@ int adau1761_probe(struct device *dev, struct regmap *regmap,
|
|||
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
|
||||
{
|
||||
struct snd_soc_dai_driver *dai_drv;
|
||||
const char *firmware_name;
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_probe(dev, regmap, type, switch_mode);
|
||||
if (type == ADAU1361) {
|
||||
dai_drv = &adau1361_dai_driver;
|
||||
firmware_name = NULL;
|
||||
} else {
|
||||
dai_drv = &adau1761_dai_driver;
|
||||
firmware_name = ADAU1761_FIRMWARE;
|
||||
}
|
||||
|
||||
ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (type == ADAU1361)
|
||||
dai_drv = &adau1361_dai_driver;
|
||||
else
|
||||
dai_drv = &adau1761_dai_driver;
|
||||
|
||||
return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau1761_probe);
|
||||
|
@ -798,6 +798,7 @@ const struct regmap_config adau1761_regmap_config = {
|
|||
.num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults),
|
||||
.readable_reg = adau1761_readable_register,
|
||||
.volatile_reg = adau17x1_volatile_register,
|
||||
.precious_reg = adau17x1_precious_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adau1761_regmap_config);
|
||||
|
|
|
@ -174,7 +174,7 @@ static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = {
|
|||
static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* After any power changes have been made the dejitter circuit
|
||||
|
@ -385,7 +385,6 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
|
|||
{
|
||||
struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
const char *firmware;
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_add_widgets(codec);
|
||||
|
@ -422,25 +421,10 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
|
|||
return ret;
|
||||
}
|
||||
|
||||
switch (adau->type) {
|
||||
case ADAU1381:
|
||||
firmware = ADAU1381_FIRMWARE;
|
||||
break;
|
||||
case ADAU1781:
|
||||
firmware = ADAU1781_FIRMWARE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = adau17x1_add_routes(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = adau17x1_load_firmware(adau, codec->dev, firmware);
|
||||
if (ret)
|
||||
dev_warn(codec->dev, "Failed to load firmware\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -488,6 +472,7 @@ const struct regmap_config adau1781_regmap_config = {
|
|||
.num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults),
|
||||
.readable_reg = adau1781_readable_register,
|
||||
.volatile_reg = adau17x1_volatile_register,
|
||||
.precious_reg = adau17x1_precious_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adau1781_regmap_config);
|
||||
|
@ -495,9 +480,21 @@ EXPORT_SYMBOL_GPL(adau1781_regmap_config);
|
|||
int adau1781_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
|
||||
{
|
||||
const char *firmware_name;
|
||||
int ret;
|
||||
|
||||
ret = adau17x1_probe(dev, regmap, type, switch_mode);
|
||||
switch (type) {
|
||||
case ADAU1381:
|
||||
firmware_name = ADAU1381_FIRMWARE;
|
||||
break;
|
||||
case ADAU1781:
|
||||
firmware_name = ADAU1781_FIRMWARE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ static const struct snd_kcontrol_new adau17x1_controls[] = {
|
|||
static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
|
@ -307,6 +308,7 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
|||
struct adau *adau = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val, div, dsp_div;
|
||||
unsigned int freq;
|
||||
int ret;
|
||||
|
||||
if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
|
||||
freq = adau->pll_freq;
|
||||
|
@ -356,6 +358,12 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
|
|||
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
|
||||
}
|
||||
|
||||
if (adau->sigmadsp) {
|
||||
ret = adau17x1_setup_firmware(adau, params_rate(params));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
|
||||
return 0;
|
||||
|
||||
|
@ -661,12 +669,24 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adau17x1_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
|
||||
|
||||
if (adau->sigmadsp)
|
||||
return sigmadsp_restrict_params(adau->sigmadsp, substream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct snd_soc_dai_ops adau17x1_dai_ops = {
|
||||
.hw_params = adau17x1_hw_params,
|
||||
.set_sysclk = adau17x1_set_dai_sysclk,
|
||||
.set_fmt = adau17x1_set_dai_fmt,
|
||||
.set_pll = adau17x1_set_dai_pll,
|
||||
.set_tdm_slot = adau17x1_set_dai_tdm_slot,
|
||||
.startup = adau17x1_startup,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
|
||||
|
||||
|
@ -687,8 +707,22 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage);
|
||||
|
||||
bool adau17x1_precious_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
/* SigmaDSP parameter memory */
|
||||
if (reg < 0x400)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_precious_register);
|
||||
|
||||
bool adau17x1_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
/* SigmaDSP parameter memory */
|
||||
if (reg < 0x400)
|
||||
return true;
|
||||
|
||||
switch (reg) {
|
||||
case ADAU17X1_CLOCK_CONTROL:
|
||||
case ADAU17X1_PLL_CONTROL:
|
||||
|
@ -745,8 +779,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
|
||||
|
||||
int adau17x1_load_firmware(struct adau *adau, struct device *dev,
|
||||
const char *firmware)
|
||||
int adau17x1_setup_firmware(struct adau *adau, unsigned int rate)
|
||||
{
|
||||
int ret;
|
||||
int dspsr;
|
||||
|
@ -758,7 +791,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,
|
|||
regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
|
||||
|
||||
ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware);
|
||||
ret = sigmadsp_setup(adau->sigmadsp, rate);
|
||||
if (ret) {
|
||||
regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
|
||||
return ret;
|
||||
|
@ -767,7 +800,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_load_firmware);
|
||||
EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
|
||||
|
||||
int adau17x1_add_widgets(struct snd_soc_codec *codec)
|
||||
{
|
||||
|
@ -787,8 +820,21 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
|
|||
ret = snd_soc_dapm_new_controls(&codec->dapm,
|
||||
adau17x1_dsp_dapm_widgets,
|
||||
ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!adau->sigmadsp)
|
||||
return 0;
|
||||
|
||||
ret = sigmadsp_attach(adau->sigmadsp, &codec->component);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to attach firmware: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
|
||||
|
||||
|
@ -829,7 +875,8 @@ int adau17x1_resume(struct snd_soc_codec *codec)
|
|||
EXPORT_SYMBOL_GPL(adau17x1_resume);
|
||||
|
||||
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
|
||||
const char *firmware_name)
|
||||
{
|
||||
struct adau *adau;
|
||||
|
||||
|
@ -846,6 +893,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
|||
|
||||
dev_set_drvdata(dev, adau);
|
||||
|
||||
if (firmware_name) {
|
||||
adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
|
||||
firmware_name);
|
||||
if (IS_ERR(adau->sigmadsp)) {
|
||||
dev_warn(dev, "Could not find firmware file: %ld\n",
|
||||
PTR_ERR(adau->sigmadsp));
|
||||
adau->sigmadsp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_mode)
|
||||
switch_mode(dev);
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/platform_data/adau17x1.h>
|
||||
|
||||
#include "sigmadsp.h"
|
||||
|
||||
enum adau17x1_type {
|
||||
ADAU1361,
|
||||
ADAU1761,
|
||||
|
@ -42,22 +44,24 @@ struct adau {
|
|||
bool dsp_bypass[2];
|
||||
|
||||
struct regmap *regmap;
|
||||
struct sigmadsp *sigmadsp;
|
||||
};
|
||||
|
||||
int adau17x1_add_widgets(struct snd_soc_codec *codec);
|
||||
int adau17x1_add_routes(struct snd_soc_codec *codec);
|
||||
int adau17x1_probe(struct device *dev, struct regmap *regmap,
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev));
|
||||
enum adau17x1_type type, void (*switch_mode)(struct device *dev),
|
||||
const char *firmware_name);
|
||||
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
|
||||
enum adau17x1_micbias_voltage micbias);
|
||||
bool adau17x1_readable_register(struct device *dev, unsigned int reg);
|
||||
bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
|
||||
bool adau17x1_precious_register(struct device *dev, unsigned int reg);
|
||||
int adau17x1_resume(struct snd_soc_codec *codec);
|
||||
|
||||
extern const struct snd_soc_dai_ops adau17x1_dai_ops;
|
||||
|
||||
int adau17x1_load_firmware(struct adau *adau, struct device *dev,
|
||||
const char *firmware);
|
||||
int adau17x1_setup_firmware(struct adau *adau, unsigned int rate);
|
||||
bool adau17x1_has_dsp(struct adau *adau);
|
||||
|
||||
#define ADAU17X1_CLOCK_CONTROL 0x4000
|
||||
|
|
|
@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
|
|||
static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct snd_soc_codec *codec = source->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
const char *clk;
|
||||
|
||||
|
@ -236,7 +236,7 @@ static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
|
|||
static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct snd_soc_codec *codec = source->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL;
|
||||
|
|
|
@ -373,33 +373,9 @@ static struct snd_soc_dai_driver ak4535_dai = {
|
|||
.ops = &ak4535_dai_ops,
|
||||
};
|
||||
|
||||
static int ak4535_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4535_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_soc_cache_sync(codec);
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4535_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
/* power on device */
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
snd_soc_add_codec_controls(codec, ak4535_snd_controls,
|
||||
ARRAY_SIZE(ak4535_snd_controls));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int ak4535_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -416,11 +392,12 @@ static const struct regmap_config ak4535_regmap = {
|
|||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
|
||||
.probe = ak4535_probe,
|
||||
.remove = ak4535_remove,
|
||||
.suspend = ak4535_suspend,
|
||||
.resume = ak4535_resume,
|
||||
.set_bias_level = ak4535_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.controls = ak4535_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(ak4535_snd_controls),
|
||||
.dapm_widgets = ak4535_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
|
||||
.dapm_routes = ak4535_audio_map,
|
||||
|
|
|
@ -505,39 +505,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int ak4641_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4641_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4641_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
/* power on device */
|
||||
ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4641_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
|
||||
.probe = ak4641_probe,
|
||||
.remove = ak4641_remove,
|
||||
.suspend = ak4641_suspend,
|
||||
.resume = ak4641_resume,
|
||||
.controls = ak4641_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(ak4641_snd_controls),
|
||||
.dapm_widgets = ak4641_dapm_widgets,
|
||||
|
@ -545,6 +513,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
|
|||
.dapm_routes = ak4641_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(ak4641_audio_map),
|
||||
.set_bias_level = ak4641_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
};
|
||||
|
||||
static const struct regmap_config ak4641_regmap = {
|
||||
|
|
|
@ -491,23 +491,7 @@ static int ak4642_resume(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ak4642_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak4642_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
|
||||
.probe = ak4642_probe,
|
||||
.remove = ak4642_remove,
|
||||
.resume = ak4642_resume,
|
||||
.set_bias_level = ak4642_set_bias_level,
|
||||
.controls = ak4642_snd_controls,
|
||||
|
|
|
@ -611,20 +611,7 @@ static struct snd_soc_dai_driver ak4671_dai = {
|
|||
.ops = &ak4671_dai_ops,
|
||||
};
|
||||
|
||||
static int ak4671_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
}
|
||||
|
||||
static int ak4671_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
|
||||
.probe = ak4671_probe,
|
||||
.remove = ak4671_remove,
|
||||
.set_bias_level = ak4671_set_bias_level,
|
||||
.controls = ak4671_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(ak4671_snd_controls),
|
||||
|
|
|
@ -866,7 +866,6 @@ static int alc5623_suspend(struct snd_soc_codec *codec)
|
|||
{
|
||||
struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
regcache_cache_only(alc5623->regmap, true);
|
||||
|
||||
return 0;
|
||||
|
@ -887,15 +886,6 @@ static int alc5623_resume(struct snd_soc_codec *codec)
|
|||
return ret;
|
||||
}
|
||||
|
||||
alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
/* charge alc5623 caps */
|
||||
if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
|
||||
alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
codec->dapm.bias_level = SND_SOC_BIAS_ON;
|
||||
alc5623_set_bias_level(codec, codec->dapm.bias_level);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -906,9 +896,6 @@ static int alc5623_probe(struct snd_soc_codec *codec)
|
|||
|
||||
alc5623_reset(codec);
|
||||
|
||||
/* power on device */
|
||||
alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
if (alc5623->add_ctrl) {
|
||||
snd_soc_write(codec, ALC5623_ADD_CTRL_REG,
|
||||
alc5623->add_ctrl);
|
||||
|
@ -964,19 +951,12 @@ static int alc5623_probe(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int alc5623_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_device_alc5623 = {
|
||||
.probe = alc5623_probe,
|
||||
.remove = alc5623_remove,
|
||||
.suspend = alc5623_suspend,
|
||||
.resume = alc5623_resume,
|
||||
.set_bias_level = alc5623_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
};
|
||||
|
||||
static const struct regmap_config alc5623_regmap = {
|
||||
|
|
|
@ -1038,23 +1038,15 @@ static struct snd_soc_dai_driver alc5632_dai = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int alc5632_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alc5632_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regcache_sync(alc5632->regmap);
|
||||
|
||||
alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define alc5632_suspend NULL
|
||||
#define alc5632_resume NULL
|
||||
#endif
|
||||
|
||||
|
@ -1062,9 +1054,6 @@ static int alc5632_probe(struct snd_soc_codec *codec)
|
|||
{
|
||||
struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* power on device */
|
||||
alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
switch (alc5632->id) {
|
||||
case 0x5c:
|
||||
snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls,
|
||||
|
@ -1077,19 +1066,12 @@ static int alc5632_probe(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int alc5632_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
|
||||
.probe = alc5632_probe,
|
||||
.remove = alc5632_remove,
|
||||
.suspend = alc5632_suspend,
|
||||
.resume = alc5632_resume,
|
||||
.set_bias_level = alc5632_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.controls = alc5632_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(alc5632_snd_controls),
|
||||
.dapm_widgets = alc5632_dapm_widgets,
|
||||
|
|
|
@ -61,6 +61,11 @@
|
|||
#define ARIZONA_FLL_MIN_OUTDIV 2
|
||||
#define ARIZONA_FLL_MAX_OUTDIV 7
|
||||
|
||||
#define ARIZONA_FMT_DSP_MODE_A 0
|
||||
#define ARIZONA_FMT_DSP_MODE_B 1
|
||||
#define ARIZONA_FMT_I2S_MODE 2
|
||||
#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
|
||||
|
||||
#define arizona_fll_err(_fll, fmt, ...) \
|
||||
dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
|
||||
#define arizona_fll_warn(_fll, fmt, ...) \
|
||||
|
@ -648,7 +653,7 @@ SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
|
|||
EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
|
||||
|
||||
static const char * const arizona_in_dmic_osr_text[] = {
|
||||
"1.536MHz", "3.072MHz", "6.144MHz",
|
||||
"1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
|
||||
};
|
||||
|
||||
const struct soc_enum arizona_in_dmic_osr[] = {
|
||||
|
@ -946,10 +951,26 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
mode = 0;
|
||||
mode = ARIZONA_FMT_DSP_MODE_A;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
|
||||
!= SND_SOC_DAIFMT_CBM_CFM) {
|
||||
arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mode = ARIZONA_FMT_DSP_MODE_B;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
mode = 2;
|
||||
mode = ARIZONA_FMT_I2S_MODE;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
|
||||
!= SND_SOC_DAIFMT_CBM_CFM) {
|
||||
arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
|
||||
break;
|
||||
default:
|
||||
arizona_aif_err(dai, "Unsupported DAI format %d\n",
|
||||
|
@ -1164,13 +1185,13 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
|
|||
{ 0x80, 0x0 },
|
||||
};
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
mutex_lock(&arizona->dac_comp_lock);
|
||||
|
||||
dac_comp[1].def = arizona->dac_comp_coeff;
|
||||
if (rate >= 176400)
|
||||
dac_comp[2].def = arizona->dac_comp_enabled;
|
||||
|
||||
mutex_unlock(&codec->mutex);
|
||||
mutex_unlock(&arizona->dac_comp_lock);
|
||||
|
||||
regmap_multi_reg_write(arizona->regmap,
|
||||
dac_comp,
|
||||
|
@ -1298,7 +1319,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
/* Force multiple of 2 channels for I2S mode */
|
||||
val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
|
||||
if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) {
|
||||
val &= ARIZONA_AIF1_FMT_MASK;
|
||||
if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
|
||||
arizona_aif_dbg(dai, "Forcing stereo mode\n");
|
||||
bclk_target /= channels;
|
||||
bclk_target *= channels + 1;
|
||||
|
|
|
@ -62,14 +62,10 @@ static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
|
|||
static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct davinci_vc *davinci_vc = codec->dev->platform_data;
|
||||
|
||||
switch (freq) {
|
||||
case 22579200:
|
||||
case 27000000:
|
||||
case 33868800:
|
||||
davinci_vc->cq93vc.sysclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -126,32 +122,6 @@ static struct snd_soc_dai_driver cq93vc_dai = {
|
|||
.ops = &cq93vc_dai_ops,
|
||||
};
|
||||
|
||||
static int cq93vc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cq93vc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct davinci_vc *davinci_vc = codec->dev->platform_data;
|
||||
|
||||
davinci_vc->cq93vc.codec = codec;
|
||||
|
||||
/* Off, with power on */
|
||||
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cq93vc_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap *cq93vc_get_regmap(struct device *dev)
|
||||
{
|
||||
struct davinci_vc *davinci_vc = dev->platform_data;
|
||||
|
@ -161,9 +131,6 @@ static struct regmap *cq93vc_get_regmap(struct device *dev)
|
|||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
|
||||
.set_bias_level = cq93vc_set_bias_level,
|
||||
.probe = cq93vc_probe,
|
||||
.remove = cq93vc_remove,
|
||||
.resume = cq93vc_resume,
|
||||
.get_regmap = cq93vc_get_regmap,
|
||||
.controls = cq93vc_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "cs4265.h"
|
||||
|
||||
struct cs4265_private {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct gpio_desc *reset_gpio;
|
||||
u8 format;
|
||||
|
@ -598,7 +597,6 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
|
|||
GFP_KERNEL);
|
||||
if (cs4265 == NULL)
|
||||
return -ENOMEM;
|
||||
cs4265->dev = &i2c_client->dev;
|
||||
|
||||
cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap);
|
||||
if (IS_ERR(cs4265->regmap)) {
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* CS4271 I2C audio driver
|
||||
*
|
||||
* Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
#include "cs4271.h"
|
||||
|
||||
static int cs4271_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = cs4271_regmap_config;
|
||||
config.reg_bits = 8;
|
||||
config.val_bits = 8;
|
||||
|
||||
return cs4271_probe(&client->dev,
|
||||
devm_regmap_init_i2c(client, &config));
|
||||
}
|
||||
|
||||
static int cs4271_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cs4271_i2c_id[] = {
|
||||
{ "cs4271", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
|
||||
|
||||
static struct i2c_driver cs4271_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs4271",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(cs4271_dt_ids),
|
||||
},
|
||||
.probe = cs4271_i2c_probe,
|
||||
.remove = cs4271_i2c_remove,
|
||||
.id_table = cs4271_i2c_id,
|
||||
};
|
||||
module_i2c_driver(cs4271_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC CS4271 I2C Driver");
|
||||
MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* CS4271 SPI audio driver
|
||||
*
|
||||
* Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
#include "cs4271.h"
|
||||
|
||||
static int cs4271_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = cs4271_regmap_config;
|
||||
config.reg_bits = 16;
|
||||
config.val_bits = 8;
|
||||
config.read_flag_mask = 0x21;
|
||||
config.write_flag_mask = 0x20;
|
||||
|
||||
return cs4271_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
|
||||
}
|
||||
|
||||
static int cs4271_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver cs4271_spi_driver = {
|
||||
.driver = {
|
||||
.name = "cs4271",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(cs4271_dt_ids),
|
||||
},
|
||||
.probe = cs4271_spi_probe,
|
||||
.remove = cs4271_spi_remove,
|
||||
};
|
||||
module_spi_driver(cs4271_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC CS4271 SPI Driver");
|
||||
MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -23,8 +23,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
@ -32,6 +30,7 @@
|
|||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/cs4271.h>
|
||||
#include "cs4271.h"
|
||||
|
||||
#define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
|
@ -527,14 +526,15 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
|
|||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id cs4271_dt_ids[] = {
|
||||
const struct of_device_id cs4271_dt_ids[] = {
|
||||
{ .compatible = "cirrus,cs4271", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
|
||||
EXPORT_SYMBOL_GPL(cs4271_dt_ids);
|
||||
#endif
|
||||
|
||||
static int cs4271_probe(struct snd_soc_codec *codec)
|
||||
static int cs4271_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
|
||||
|
@ -587,7 +587,7 @@ static int cs4271_probe(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cs4271_remove(struct snd_soc_codec *codec)
|
||||
static int cs4271_codec_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
|
@ -599,8 +599,8 @@ static int cs4271_remove(struct snd_soc_codec *codec)
|
|||
};
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
|
||||
.probe = cs4271_probe,
|
||||
.remove = cs4271_remove,
|
||||
.probe = cs4271_codec_probe,
|
||||
.remove = cs4271_codec_remove,
|
||||
.suspend = cs4271_soc_suspend,
|
||||
.resume = cs4271_soc_resume,
|
||||
|
||||
|
@ -642,67 +642,7 @@ static int cs4271_common_probe(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
|
||||
static const struct regmap_config cs4271_spi_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.max_register = CS4271_LASTREG,
|
||||
.read_flag_mask = 0x21,
|
||||
.write_flag_mask = 0x20,
|
||||
|
||||
.reg_defaults = cs4271_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.volatile_reg = cs4271_volatile_reg,
|
||||
};
|
||||
|
||||
static int cs4271_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct cs4271_private *cs4271;
|
||||
int ret;
|
||||
|
||||
ret = cs4271_common_probe(&spi->dev, &cs4271);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
spi_set_drvdata(spi, cs4271);
|
||||
cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap);
|
||||
if (IS_ERR(cs4271->regmap))
|
||||
return PTR_ERR(cs4271->regmap);
|
||||
|
||||
return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271,
|
||||
&cs4271_dai, 1);
|
||||
}
|
||||
|
||||
static int cs4271_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver cs4271_spi_driver = {
|
||||
.driver = {
|
||||
.name = "cs4271",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(cs4271_dt_ids),
|
||||
},
|
||||
.probe = cs4271_spi_probe,
|
||||
.remove = cs4271_spi_remove,
|
||||
};
|
||||
#endif /* defined(CONFIG_SPI_MASTER) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
static const struct i2c_device_id cs4271_i2c_id[] = {
|
||||
{"cs4271", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
|
||||
|
||||
static const struct regmap_config cs4271_i2c_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
const struct regmap_config cs4271_regmap_config = {
|
||||
.max_register = CS4271_LASTREG,
|
||||
|
||||
.reg_defaults = cs4271_reg_defaults,
|
||||
|
@ -711,86 +651,27 @@ static const struct regmap_config cs4271_i2c_regmap = {
|
|||
|
||||
.volatile_reg = cs4271_volatile_reg,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cs4271_regmap_config);
|
||||
|
||||
static int cs4271_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
int cs4271_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct cs4271_private *cs4271;
|
||||
int ret;
|
||||
|
||||
ret = cs4271_common_probe(&client->dev, &cs4271);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
ret = cs4271_common_probe(dev, &cs4271);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
i2c_set_clientdata(client, cs4271);
|
||||
cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap);
|
||||
if (IS_ERR(cs4271->regmap))
|
||||
return PTR_ERR(cs4271->regmap);
|
||||
dev_set_drvdata(dev, cs4271);
|
||||
cs4271->regmap = regmap;
|
||||
|
||||
return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271,
|
||||
&cs4271_dai, 1);
|
||||
return snd_soc_register_codec(dev, &soc_codec_dev_cs4271, &cs4271_dai,
|
||||
1);
|
||||
}
|
||||
|
||||
static int cs4271_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver cs4271_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs4271",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(cs4271_dt_ids),
|
||||
},
|
||||
.id_table = cs4271_i2c_id,
|
||||
.probe = cs4271_i2c_probe,
|
||||
.remove = cs4271_i2c_remove,
|
||||
};
|
||||
#endif /* IS_ENABLED(CONFIG_I2C) */
|
||||
|
||||
/*
|
||||
* We only register our serial bus driver here without
|
||||
* assignment to particular chip. So if any of the below
|
||||
* fails, there is some problem with I2C or SPI subsystem.
|
||||
* In most cases this module will be compiled with support
|
||||
* of only one serial bus.
|
||||
*/
|
||||
static int __init cs4271_modinit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
ret = i2c_add_driver(&cs4271_i2c_driver);
|
||||
if (ret) {
|
||||
pr_err("Failed to register CS4271 I2C driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
ret = spi_register_driver(&cs4271_spi_driver);
|
||||
if (ret) {
|
||||
pr_err("Failed to register CS4271 SPI driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(cs4271_modinit);
|
||||
|
||||
static void __exit cs4271_modexit(void)
|
||||
{
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&cs4271_spi_driver);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
i2c_del_driver(&cs4271_i2c_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(cs4271_modexit);
|
||||
EXPORT_SYMBOL_GPL(cs4271_probe);
|
||||
|
||||
MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef _CS4271_PRIV_H
|
||||
#define _CS4271_PRIV_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
extern const struct of_device_id cs4271_dt_ids[];
|
||||
extern const struct regmap_config cs4271_regmap_config;
|
||||
|
||||
int cs4271_probe(struct device *dev, struct regmap *regmap);
|
||||
|
||||
#endif
|
|
@ -153,15 +153,17 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
|
|||
static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
|
||||
snd_soc_update_bits(codec, CS42L51_POWER_CTL1,
|
||||
CS42L51_POWER_CTL1_PDN,
|
||||
CS42L51_POWER_CTL1_PDN);
|
||||
break;
|
||||
default:
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
|
||||
snd_soc_update_bits(codec, CS42L51_POWER_CTL1,
|
||||
CS42L51_POWER_CTL1_PDN, 0);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -584,7 +584,7 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
|
|||
static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
|
@ -600,7 +600,7 @@ static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
|
|||
static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
|
@ -618,7 +618,7 @@ static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
|
|||
static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
|
|
|
@ -47,6 +47,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
|
|||
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.sig_bits = 24,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
|
@ -75,6 +76,7 @@ static struct snd_soc_codec_driver hdmi_codec = {
|
|||
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
|
||||
.dapm_routes = hdmi_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
|
||||
.ignore_pmdown_time = true,
|
||||
};
|
||||
|
||||
static int hdmi_codec_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -1395,15 +1395,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* power down chip */
|
||||
static int lm49453_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
|
||||
.remove = lm49453_remove,
|
||||
.set_bias_level = lm49453_set_bias_level,
|
||||
.controls = lm49453_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(lm49453_snd_controls),
|
||||
|
|
|
@ -875,7 +875,7 @@ static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
|
|||
static int max98088_mic_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (event) {
|
||||
|
@ -905,7 +905,7 @@ static int max98088_mic_event(struct snd_soc_dapm_widget *w,
|
|||
static int max98088_line_pga(struct snd_soc_dapm_widget *w,
|
||||
int event, int line, u8 channel)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 *state;
|
||||
|
||||
|
@ -1887,25 +1887,6 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec)
|
|||
max98088_handle_eq_pdata(codec);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int max98088_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98088_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define max98088_suspend NULL
|
||||
#define max98088_resume NULL
|
||||
#endif
|
||||
|
||||
static int max98088_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
|
||||
|
@ -1946,9 +1927,6 @@ static int max98088_probe(struct snd_soc_codec *codec)
|
|||
|
||||
snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
|
||||
|
||||
/* initialize registers cache to hardware default */
|
||||
max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
|
||||
|
||||
snd_soc_write(codec, M98088_REG_22_MIX_DAC,
|
||||
|
@ -1974,7 +1952,6 @@ static int max98088_remove(struct snd_soc_codec *codec)
|
|||
{
|
||||
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
kfree(max98088->eq_texts);
|
||||
|
||||
return 0;
|
||||
|
@ -1983,9 +1960,9 @@ static int max98088_remove(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
|
||||
.probe = max98088_probe,
|
||||
.remove = max98088_remove,
|
||||
.suspend = max98088_suspend,
|
||||
.resume = max98088_resume,
|
||||
.set_bias_level = max98088_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.controls = max98088_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(max98088_snd_controls),
|
||||
.dapm_widgets = max98088_dapm_widgets,
|
||||
|
|
|
@ -806,7 +806,7 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = {
|
|||
static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
unsigned int val = snd_soc_read(codec, w->reg);
|
||||
|
@ -1311,6 +1311,10 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
|
|||
{"MIC1 Input", NULL, "MIC1"},
|
||||
{"MIC2 Input", NULL, "MIC2"},
|
||||
|
||||
{"DMICL", NULL, "DMICL_ENA"},
|
||||
{"DMICL", NULL, "DMICR_ENA"},
|
||||
{"DMICR", NULL, "DMICL_ENA"},
|
||||
{"DMICR", NULL, "DMICR_ENA"},
|
||||
{"DMICL", NULL, "AHPF"},
|
||||
{"DMICR", NULL, "AHPF"},
|
||||
|
||||
|
@ -1368,8 +1372,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
|
|||
{"DMIC Mux", "ADC", "ADCR"},
|
||||
{"DMIC Mux", "DMIC", "DMICL"},
|
||||
{"DMIC Mux", "DMIC", "DMICR"},
|
||||
{"DMIC Mux", "DMIC", "DMICL_ENA"},
|
||||
{"DMIC Mux", "DMIC", "DMICR_ENA"},
|
||||
|
||||
{"LBENL Mux", "Normal", "DMIC Mux"},
|
||||
{"LBENL Mux", "Loopback", "LTENL Mux"},
|
||||
|
@ -1395,8 +1397,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
|
|||
{"STENL Mux", "Sidetone Left", "DMICL"},
|
||||
{"STENR Mux", "Sidetone Right", "ADCR"},
|
||||
{"STENR Mux", "Sidetone Right", "DMICR"},
|
||||
{"DACL", "NULL", "STENL Mux"},
|
||||
{"DACR", "NULL", "STENL Mux"},
|
||||
{"DACL", NULL, "STENL Mux"},
|
||||
{"DACR", NULL, "STENR Mux"},
|
||||
|
||||
{"AIFINL", NULL, "SHDN"},
|
||||
{"AIFINR", NULL, "SHDN"},
|
||||
|
@ -1826,27 +1828,155 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const int comp_pclk_rates[] = {
|
||||
11289600, 12288000, 12000000, 13000000, 19200000
|
||||
};
|
||||
|
||||
static const int dmic_micclk[] = {
|
||||
2, 2, 2, 2, 4, 2
|
||||
};
|
||||
static const int dmic_divisors[] = { 2, 3, 4, 5, 6, 8 };
|
||||
|
||||
static const int comp_lrclk_rates[] = {
|
||||
8000, 16000, 32000, 44100, 48000, 96000
|
||||
};
|
||||
|
||||
static const int dmic_comp[6][6] = {
|
||||
{7, 8, 3, 3, 3, 3},
|
||||
{7, 8, 3, 3, 3, 3},
|
||||
{7, 8, 3, 3, 3, 3},
|
||||
{7, 8, 3, 1, 1, 1},
|
||||
{7, 8, 3, 1, 2, 2},
|
||||
{7, 8, 3, 3, 3, 3}
|
||||
struct dmic_table {
|
||||
int pclk;
|
||||
struct {
|
||||
int freq;
|
||||
int comp[6]; /* One each for 8, 16, 32, 44.1, 48, and 96 kHz */
|
||||
} settings[6]; /* One for each dmic divisor. */
|
||||
};
|
||||
|
||||
static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */
|
||||
{
|
||||
.pclk = 11289600,
|
||||
.settings = {
|
||||
{ .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
{ .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
},
|
||||
},
|
||||
{
|
||||
.pclk = 12000000,
|
||||
.settings = {
|
||||
{ .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
{ .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
}
|
||||
},
|
||||
{
|
||||
.pclk = 12288000,
|
||||
.settings = {
|
||||
{ .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
{ .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
|
||||
}
|
||||
},
|
||||
{
|
||||
.pclk = 13000000,
|
||||
.settings = {
|
||||
{ .freq = 2, .comp = { 7, 8, 1, 1, 1, 1 } },
|
||||
{ .freq = 1, .comp = { 7, 8, 0, 0, 0, 0 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 4, 4, 5, 5 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
|
||||
}
|
||||
},
|
||||
{
|
||||
.pclk = 19200000,
|
||||
.settings = {
|
||||
{ .freq = 2, .comp = { 0, 0, 0, 0, 0, 0 } },
|
||||
{ .freq = 1, .comp = { 7, 8, 1, 1, 1, 1 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 2, 2, 3, 3 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 1, 1, 2, 2 } },
|
||||
{ .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static int max98090_find_divisor(int target_freq, int pclk)
|
||||
{
|
||||
int current_diff = INT_MAX;
|
||||
int test_diff = INT_MAX;
|
||||
int divisor_index = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dmic_divisors); i++) {
|
||||
test_diff = abs(target_freq - (pclk / dmic_divisors[i]));
|
||||
if (test_diff < current_diff) {
|
||||
current_diff = test_diff;
|
||||
divisor_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return divisor_index;
|
||||
}
|
||||
|
||||
static int max98090_find_closest_pclk(int pclk)
|
||||
{
|
||||
int m1;
|
||||
int m2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dmic_table); i++) {
|
||||
if (pclk == dmic_table[i].pclk)
|
||||
return i;
|
||||
if (pclk < dmic_table[i].pclk) {
|
||||
if (i == 0)
|
||||
return i;
|
||||
m1 = pclk - dmic_table[i-1].pclk;
|
||||
m2 = dmic_table[i].pclk - pclk;
|
||||
if (m1 < m2)
|
||||
return i - 1;
|
||||
else
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int max98090_configure_dmic(struct max98090_priv *max98090,
|
||||
int target_dmic_clk, int pclk, int fs)
|
||||
{
|
||||
int micclk_index;
|
||||
int pclk_index;
|
||||
int dmic_freq;
|
||||
int dmic_comp;
|
||||
int i;
|
||||
|
||||
pclk_index = max98090_find_closest_pclk(pclk);
|
||||
if (pclk_index < 0)
|
||||
return pclk_index;
|
||||
|
||||
micclk_index = max98090_find_divisor(target_dmic_clk, pclk);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) {
|
||||
if (fs <= (comp_lrclk_rates[i] + comp_lrclk_rates[i+1]) / 2)
|
||||
break;
|
||||
}
|
||||
|
||||
dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq;
|
||||
dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i];
|
||||
|
||||
regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE,
|
||||
M98090_MICCLK_MASK,
|
||||
micclk_index << M98090_MICCLK_SHIFT);
|
||||
|
||||
regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_CONFIG,
|
||||
M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK,
|
||||
dmic_comp << M98090_DMIC_COMP_SHIFT |
|
||||
dmic_freq << M98090_DMIC_FREQ_SHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
|
@ -1854,7 +1984,6 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
|
||||
struct max98090_cdata *cdata;
|
||||
int i, j;
|
||||
|
||||
cdata = &max98090->dai[0];
|
||||
max98090->bclk = snd_soc_params_to_bclk(params);
|
||||
|
@ -1893,27 +2022,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
|
|||
snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
|
||||
M98090_DHF_MASK, M98090_DHF_MASK);
|
||||
|
||||
/* Check for supported PCLK to LRCLK ratios */
|
||||
for (j = 0; j < ARRAY_SIZE(comp_pclk_rates); j++) {
|
||||
if (comp_pclk_rates[j] == max98090->sysclk) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) {
|
||||
if (max98090->lrclk <= (comp_lrclk_rates[i] +
|
||||
comp_lrclk_rates[i + 1]) / 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_ENABLE,
|
||||
M98090_MICCLK_MASK,
|
||||
dmic_micclk[j] << M98090_MICCLK_SHIFT);
|
||||
|
||||
snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_CONFIG,
|
||||
M98090_DMIC_COMP_MASK,
|
||||
dmic_comp[j][i] << M98090_DMIC_COMP_SHIFT);
|
||||
max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk,
|
||||
max98090->lrclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1944,12 +2054,15 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
|
|||
if ((freq >= 10000000) && (freq <= 20000000)) {
|
||||
snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
|
||||
M98090_PSCLK_DIV1);
|
||||
max98090->pclk = freq;
|
||||
} else if ((freq > 20000000) && (freq <= 40000000)) {
|
||||
snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
|
||||
M98090_PSCLK_DIV2);
|
||||
max98090->pclk = freq >> 1;
|
||||
} else if ((freq > 40000000) && (freq <= 60000000)) {
|
||||
snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
|
||||
M98090_PSCLK_DIV4);
|
||||
max98090->pclk = freq >> 2;
|
||||
} else {
|
||||
dev_err(codec->dev, "Invalid master clock frequency\n");
|
||||
return -EINVAL;
|
||||
|
@ -2324,6 +2437,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
|
|||
/* Initialize private data */
|
||||
|
||||
max98090->sysclk = (unsigned)-1;
|
||||
max98090->pclk = (unsigned)-1;
|
||||
max98090->master = false;
|
||||
|
||||
cdata = &max98090->dai[0];
|
||||
|
@ -2463,6 +2577,11 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
|
|||
i2c_set_clientdata(i2c, max98090);
|
||||
max98090->pdata = i2c->dev.platform_data;
|
||||
|
||||
ret = of_property_read_u32(i2c->dev.of_node, "maxim,dmic-freq",
|
||||
&max98090->dmic_freq);
|
||||
if (ret < 0)
|
||||
max98090->dmic_freq = MAX98090_DEFAULT_DMIC_FREQ;
|
||||
|
||||
max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
|
||||
if (IS_ERR(max98090->regmap)) {
|
||||
ret = PTR_ERR(max98090->regmap);
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
#ifndef _MAX98090_H
|
||||
#define _MAX98090_H
|
||||
|
||||
/*
|
||||
* The default operating frequency for a DMIC attached to the codec.
|
||||
* This can be overridden by a device tree property.
|
||||
*/
|
||||
#define MAX98090_DEFAULT_DMIC_FREQ 2500000
|
||||
|
||||
/*
|
||||
* MAX98090 Register Definitions
|
||||
*/
|
||||
|
@ -1518,8 +1524,10 @@ struct max98090_priv {
|
|||
struct max98090_pdata *pdata;
|
||||
struct clk *mclk;
|
||||
unsigned int sysclk;
|
||||
unsigned int pclk;
|
||||
unsigned int bclk;
|
||||
unsigned int lrclk;
|
||||
u32 dmic_freq;
|
||||
struct max98090_cdata dai[1];
|
||||
int jack_state;
|
||||
struct delayed_work jack_work;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
@ -57,6 +58,7 @@ struct max98095_priv {
|
|||
unsigned int mic2pre;
|
||||
struct snd_soc_jack *headphone_jack;
|
||||
struct snd_soc_jack *mic_jack;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static const struct reg_default max98095_reg_def[] = {
|
||||
|
@ -864,7 +866,7 @@ static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = {
|
|||
static int max98095_mic_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (event) {
|
||||
|
@ -894,7 +896,7 @@ static int max98095_mic_event(struct snd_soc_dapm_widget *w,
|
|||
static int max98095_line_pga(struct snd_soc_dapm_widget *w,
|
||||
int event, u8 channel)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 *state;
|
||||
|
||||
|
@ -942,7 +944,7 @@ static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w,
|
|||
static int max98095_lineout_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
|
@ -1803,7 +1805,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
|
|||
regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
|
||||
snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
mutex_lock(&max98095->lock);
|
||||
snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
|
||||
m98095_eq_band(codec, channel, 0, coef_set->band1);
|
||||
m98095_eq_band(codec, channel, 1, coef_set->band2);
|
||||
|
@ -1811,7 +1813,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
|
|||
m98095_eq_band(codec, channel, 3, coef_set->band4);
|
||||
m98095_eq_band(codec, channel, 4, coef_set->band5);
|
||||
snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
|
||||
mutex_unlock(&codec->mutex);
|
||||
mutex_unlock(&max98095->lock);
|
||||
|
||||
/* Restore the original on/off state */
|
||||
snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
|
||||
|
@ -1957,12 +1959,12 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
|
|||
regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
|
||||
snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
|
||||
|
||||
mutex_lock(&codec->mutex);
|
||||
mutex_lock(&max98095->lock);
|
||||
snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
|
||||
m98095_biquad_band(codec, channel, 0, coef_set->band1);
|
||||
m98095_biquad_band(codec, channel, 1, coef_set->band2);
|
||||
snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
|
||||
mutex_unlock(&codec->mutex);
|
||||
mutex_unlock(&max98095->lock);
|
||||
|
||||
/* Restore the original on/off state */
|
||||
snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
|
||||
|
@ -2317,9 +2319,6 @@ static int max98095_probe(struct snd_soc_codec *codec)
|
|||
|
||||
snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV);
|
||||
|
||||
/* initialize registers cache to hardware default */
|
||||
max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
snd_soc_write(codec, M98095_048_MIX_DAC_LR,
|
||||
M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR);
|
||||
|
||||
|
@ -2359,8 +2358,6 @@ static int max98095_remove(struct snd_soc_codec *codec)
|
|||
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *client = to_i2c_client(codec->dev);
|
||||
|
||||
max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
if (max98095->headphone_jack || max98095->mic_jack)
|
||||
max98095_jack_detect_disable(codec);
|
||||
|
||||
|
@ -2395,6 +2392,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
|
|||
if (max98095 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&max98095->lock);
|
||||
|
||||
max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap);
|
||||
if (IS_ERR(max98095->regmap)) {
|
||||
ret = PTR_ERR(max98095->regmap);
|
||||
|
|
|
@ -291,25 +291,6 @@ static struct snd_soc_dai_driver max9850_dai = {
|
|||
.ops = &max9850_dai_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int max9850_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
max9850_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9850_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
max9850_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define max9850_suspend NULL
|
||||
#define max9850_resume NULL
|
||||
#endif
|
||||
|
||||
static int max9850_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
/* enable zero-detect */
|
||||
|
@ -324,9 +305,8 @@ static int max9850_probe(struct snd_soc_codec *codec)
|
|||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
|
||||
.probe = max9850_probe,
|
||||
.suspend = max9850_suspend,
|
||||
.resume = max9850_resume,
|
||||
.set_bias_level = max9850_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
|
||||
.controls = max9850_controls,
|
||||
.num_controls = ARRAY_SIZE(max9850_controls),
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
|
@ -36,11 +37,13 @@
|
|||
|
||||
struct rt286_priv {
|
||||
struct regmap *regmap;
|
||||
struct snd_soc_codec *codec;
|
||||
struct rt286_platform_data pdata;
|
||||
struct i2c_client *i2c;
|
||||
struct snd_soc_jack *jack;
|
||||
struct delayed_work jack_detect_work;
|
||||
int sys_clk;
|
||||
int clk_id;
|
||||
struct reg_default *index_cache;
|
||||
};
|
||||
|
||||
|
@ -188,7 +191,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value)
|
|||
u8 data[4];
|
||||
int ret, i;
|
||||
|
||||
/*handle index registers*/
|
||||
/* handle index registers */
|
||||
if (reg <= 0xff) {
|
||||
rt286_hw_write(client, RT286_COEF_INDEX, reg);
|
||||
for (i = 0; i < INDEX_CACHE_SIZE; i++) {
|
||||
|
@ -231,7 +234,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value)
|
|||
__be32 be_reg;
|
||||
unsigned int index, vid, buf = 0x0;
|
||||
|
||||
/*handle index registers*/
|
||||
/* handle index registers */
|
||||
if (reg <= 0xff) {
|
||||
rt286_hw_write(client, RT286_COEF_INDEX, reg);
|
||||
reg = RT286_PROC_COEF;
|
||||
|
@ -298,7 +301,6 @@ static int rt286_support_power_controls[] = {
|
|||
static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
|
||||
{
|
||||
unsigned int val, buf;
|
||||
int i;
|
||||
|
||||
*hp = false;
|
||||
*mic = false;
|
||||
|
@ -309,67 +311,44 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
|
|||
if (*hp) {
|
||||
/* power on HV,VERF */
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_POWER_CTRL1, 0x1001, 0x0);
|
||||
RT286_DC_GAIN, 0x200, 0x200);
|
||||
|
||||
snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
|
||||
"HV");
|
||||
snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
|
||||
"VREF");
|
||||
/* power LDO1 */
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_POWER_CTRL2, 0x4, 0x4);
|
||||
snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
|
||||
"LDO1");
|
||||
snd_soc_dapm_sync(&rt286->codec->dapm);
|
||||
|
||||
regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
|
||||
msleep(50);
|
||||
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_CBJ_CTRL1, 0xfcc0, 0xd400);
|
||||
msleep(300);
|
||||
regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val);
|
||||
|
||||
msleep(200);
|
||||
i = 40;
|
||||
while (((val & 0x0800) == 0) && (i > 0)) {
|
||||
if (0x0070 == (val & 0x0070)) {
|
||||
*mic = true;
|
||||
} else {
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_CBJ_CTRL1, 0xfcc0, 0xe400);
|
||||
msleep(300);
|
||||
regmap_read(rt286->regmap,
|
||||
RT286_CBJ_CTRL2, &val);
|
||||
i--;
|
||||
msleep(20);
|
||||
if (0x0070 == (val & 0x0070))
|
||||
*mic = true;
|
||||
else
|
||||
*mic = false;
|
||||
}
|
||||
|
||||
if (0x0400 == (val & 0x0700)) {
|
||||
*mic = false;
|
||||
|
||||
regmap_write(rt286->regmap,
|
||||
RT286_SET_MIC1, 0x20);
|
||||
/* power off HV,VERF */
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_POWER_CTRL1, 0x1001, 0x1001);
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_CBJ_CTRL1, 0x0030, 0x0000);
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
|
||||
} else if ((0x0200 == (val & 0x0700)) ||
|
||||
(0x0100 == (val & 0x0700))) {
|
||||
*mic = true;
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_CBJ_CTRL1, 0x0030, 0x0020);
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
|
||||
} else {
|
||||
*mic = false;
|
||||
}
|
||||
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_MISC_CTRL1,
|
||||
0x0060, 0x0000);
|
||||
RT286_DC_GAIN, 0x200, 0x0);
|
||||
|
||||
} else {
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_MISC_CTRL1,
|
||||
0x0060, 0x0020);
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_A_BIAS_CTRL3,
|
||||
0xc000, 0x8000);
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_CBJ_CTRL1,
|
||||
0x0030, 0x0020);
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_A_BIAS_CTRL2,
|
||||
0xc000, 0x8000);
|
||||
|
||||
*mic = false;
|
||||
regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20);
|
||||
}
|
||||
} else {
|
||||
regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
|
||||
|
@ -378,6 +357,12 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
|
|||
*mic = buf & 0x80000000;
|
||||
}
|
||||
|
||||
snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV");
|
||||
snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF");
|
||||
if (!*hp)
|
||||
snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1");
|
||||
snd_soc_dapm_sync(&rt286->codec->dapm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -415,6 +400,17 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(rt286_mic_detect);
|
||||
|
||||
static int is_mclk_mode(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec);
|
||||
|
||||
if (rt286->clk_id == RT286_SCLK_S_MCLK)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
|
||||
|
||||
|
@ -568,7 +564,84 @@ static int rt286_adc_event(struct snd_soc_dapm_widget *w,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rt286_vref_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
snd_soc_update_bits(codec,
|
||||
RT286_CBJ_CTRL1, 0x0400, 0x0000);
|
||||
mdelay(50);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x08);
|
||||
break;
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x30);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt286_mic1_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
snd_soc_update_bits(codec,
|
||||
RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
|
||||
snd_soc_update_bits(codec,
|
||||
RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
snd_soc_update_bits(codec,
|
||||
RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
|
||||
snd_soc_update_bits(codec,
|
||||
RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1,
|
||||
12, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1,
|
||||
0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU),
|
||||
SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2,
|
||||
2, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1,
|
||||
13, 1, rt286_ldo2_event, SND_SOC_DAPM_PRE_PMD |
|
||||
SND_SOC_DAPM_POST_PMU),
|
||||
SND_SOC_DAPM_SUPPLY("MCLK MODE", RT286_PLL_CTRL1,
|
||||
5, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM,
|
||||
0, 0, rt286_mic1_event, SND_SOC_DAPM_PRE_PMU |
|
||||
SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
/* Input Lines */
|
||||
SND_SOC_DAPM_INPUT("DMIC1 Pin"),
|
||||
SND_SOC_DAPM_INPUT("DMIC2 Pin"),
|
||||
|
@ -642,6 +715,25 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
|
|||
};
|
||||
|
||||
static const struct snd_soc_dapm_route rt286_dapm_routes[] = {
|
||||
{"ADC 0", NULL, "MCLK MODE", is_mclk_mode},
|
||||
{"ADC 1", NULL, "MCLK MODE", is_mclk_mode},
|
||||
{"Front", NULL, "MCLK MODE", is_mclk_mode},
|
||||
{"Surround", NULL, "MCLK MODE", is_mclk_mode},
|
||||
|
||||
{"HP Power", NULL, "LDO1"},
|
||||
{"HP Power", NULL, "LDO2"},
|
||||
|
||||
{"MIC1", NULL, "LDO1"},
|
||||
{"MIC1", NULL, "LDO2"},
|
||||
{"MIC1", NULL, "HV"},
|
||||
{"MIC1", NULL, "VREF"},
|
||||
{"MIC1", NULL, "MIC1 Input Buffer"},
|
||||
|
||||
{"SPO", NULL, "LDO1"},
|
||||
{"SPO", NULL, "LDO2"},
|
||||
{"SPO", NULL, "HV"},
|
||||
{"SPO", NULL, "VREF"},
|
||||
|
||||
{"DMIC1", NULL, "DMIC1 Pin"},
|
||||
{"DMIC2", NULL, "DMIC2 Pin"},
|
||||
{"DMIC1", NULL, "DMIC Receiver"},
|
||||
|
@ -880,6 +972,7 @@ static int rt286_set_dai_sysclk(struct snd_soc_dai *dai,
|
|||
}
|
||||
|
||||
rt286->sys_clk = freq;
|
||||
rt286->clk_id = clk_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -915,13 +1008,18 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
|
|||
|
||||
case SND_SOC_BIAS_ON:
|
||||
mdelay(10);
|
||||
snd_soc_update_bits(codec,
|
||||
RT286_CBJ_CTRL1, 0x0400, 0x0400);
|
||||
snd_soc_update_bits(codec,
|
||||
RT286_DC_GAIN, 0x200, 0x0);
|
||||
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
snd_soc_write(codec,
|
||||
RT286_SET_AUDIO_POWER, AC_PWRST_D3);
|
||||
snd_soc_update_bits(codec,
|
||||
RT286_DC_GAIN, 0x200, 0x0);
|
||||
RT286_CBJ_CTRL1, 0x0400, 0x0000);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -962,6 +1060,7 @@ static int rt286_probe(struct snd_soc_codec *codec)
|
|||
{
|
||||
struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
rt286->codec = codec;
|
||||
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
|
||||
|
||||
if (rt286->i2c->irq) {
|
||||
|
@ -1107,6 +1206,16 @@ static const struct acpi_device_id rt286_acpi_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt286_acpi_match);
|
||||
|
||||
static struct dmi_system_id force_combo_jack_table[] = {
|
||||
{
|
||||
.ident = "Intel Wilson Beach",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS")
|
||||
}
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static int rt286_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -1142,6 +1251,9 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
|
|||
if (pdata)
|
||||
rt286->pdata = *pdata;
|
||||
|
||||
if (dmi_check_system(force_combo_jack_table))
|
||||
rt286->pdata.cbj_en = true;
|
||||
|
||||
regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3);
|
||||
|
||||
for (i = 0; i < RT286_POWER_REG_LEN; i++)
|
||||
|
@ -1152,7 +1264,6 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
|
|||
if (!rt286->pdata.cbj_en) {
|
||||
regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000);
|
||||
regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816);
|
||||
regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000);
|
||||
regmap_update_bits(rt286->regmap,
|
||||
RT286_CBJ_CTRL1, 0xf000, 0xb000);
|
||||
} else {
|
||||
|
@ -1169,10 +1280,12 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
|
|||
|
||||
mdelay(10);
|
||||
|
||||
/*Power down LDO2*/
|
||||
regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0);
|
||||
regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000);
|
||||
/* Power down LDO, VREF */
|
||||
regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0xc, 0x0);
|
||||
regmap_update_bits(rt286->regmap, RT286_POWER_CTRL1, 0x1001, 0x1001);
|
||||
|
||||
/*Set depop parameter*/
|
||||
/* Set depop parameter */
|
||||
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a);
|
||||
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737);
|
||||
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);
|
||||
|
|
|
@ -1612,29 +1612,6 @@ static int rt5631_probe(struct snd_soc_codec *codec)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rt5631_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int rt5631_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5631_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define rt5631_suspend NULL
|
||||
#define rt5631_resume NULL
|
||||
#endif
|
||||
|
||||
#define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000
|
||||
#define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
|
@ -1672,10 +1649,8 @@ static struct snd_soc_dai_driver rt5631_dai[] = {
|
|||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
|
||||
.probe = rt5631_probe,
|
||||
.remove = rt5631_remove,
|
||||
.suspend = rt5631_suspend,
|
||||
.resume = rt5631_resume,
|
||||
.set_bias_level = rt5631_set_bias_level,
|
||||
.suspend_bias_off = true,
|
||||
.controls = rt5631_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(rt5631_snd_controls),
|
||||
.dapm_widgets = rt5631_dapm_widgets,
|
||||
|
@ -1686,10 +1661,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
|
|||
|
||||
static const struct i2c_device_id rt5631_i2c_id[] = {
|
||||
{ "rt5631", 0 },
|
||||
{ "alc5631", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id rt5631_i2c_dt_ids[] = {
|
||||
{ .compatible = "realtek,rt5631"},
|
||||
{ .compatible = "realtek,alc5631"},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rt5631_i2c_dt_ids);
|
||||
#endif
|
||||
|
||||
static const struct regmap_config rt5631_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
|
@ -1734,6 +1719,7 @@ static struct i2c_driver rt5631_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "rt5631",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(rt5631_i2c_dt_ids),
|
||||
},
|
||||
.probe = rt5631_i2c_probe,
|
||||
.remove = rt5631_i2c_remove,
|
||||
|
|
|
@ -554,6 +554,53 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int is_using_asrc(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
unsigned int reg, shift, val;
|
||||
|
||||
switch (source->shift) {
|
||||
case 0:
|
||||
reg = RT5645_ASRC_3;
|
||||
shift = 0;
|
||||
break;
|
||||
case 1:
|
||||
reg = RT5645_ASRC_3;
|
||||
shift = 4;
|
||||
break;
|
||||
case 3:
|
||||
reg = RT5645_ASRC_2;
|
||||
shift = 0;
|
||||
break;
|
||||
case 8:
|
||||
reg = RT5645_ASRC_2;
|
||||
shift = 4;
|
||||
break;
|
||||
case 9:
|
||||
reg = RT5645_ASRC_2;
|
||||
shift = 8;
|
||||
break;
|
||||
case 10:
|
||||
reg = RT5645_ASRC_2;
|
||||
shift = 12;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
|
||||
switch (val) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Digital Mixer */
|
||||
static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
|
||||
SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
|
||||
|
@ -1246,6 +1293,30 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL,
|
||||
RT5645_PWR_MIC_DET_BIT, 0, NULL, 0),
|
||||
|
||||
/* ASRC */
|
||||
SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5645_ASRC_1,
|
||||
11, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5645_ASRC_1,
|
||||
12, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5645_ASRC_1,
|
||||
10, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5645_ASRC_1,
|
||||
9, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5645_ASRC_1,
|
||||
8, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5645_ASRC_1,
|
||||
7, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5645_ASRC_1,
|
||||
5, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5645_ASRC_1,
|
||||
4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5645_ASRC_1,
|
||||
3, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5645_ASRC_1,
|
||||
1, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5645_ASRC_1,
|
||||
0, 0, NULL, 0),
|
||||
|
||||
/* Input Side */
|
||||
/* micbias */
|
||||
SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2,
|
||||
|
@ -1504,6 +1575,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
|
|||
};
|
||||
|
||||
static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
|
||||
{ "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
|
||||
{ "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
|
||||
{ "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
|
||||
{ "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
|
||||
{ "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc },
|
||||
{ "dac mono right filter", NULL, "DAC MONO R ASRC", is_using_asrc },
|
||||
{ "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc },
|
||||
|
||||
{ "I2S1", NULL, "I2S1 ASRC" },
|
||||
{ "I2S2", NULL, "I2S2 ASRC" },
|
||||
|
||||
{ "IN1P", NULL, "LDO2" },
|
||||
{ "IN2P", NULL, "LDO2" },
|
||||
|
||||
|
@ -1550,12 +1632,15 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
|
|||
|
||||
{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
|
||||
{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
|
||||
{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC" },
|
||||
|
||||
{ "Mono DMIC L Mux", "DMIC1", "DMIC L1" },
|
||||
{ "Mono DMIC L Mux", "DMIC2", "DMIC L2" },
|
||||
{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC" },
|
||||
|
||||
{ "Mono DMIC R Mux", "DMIC1", "DMIC R1" },
|
||||
{ "Mono DMIC R Mux", "DMIC2", "DMIC R2" },
|
||||
{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC" },
|
||||
|
||||
{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" },
|
||||
{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
|
||||
|
@ -2029,8 +2114,11 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
|||
struct snd_soc_codec *codec = dai->codec;
|
||||
unsigned int val = 0;
|
||||
|
||||
if (rx_mask || tx_mask)
|
||||
if (rx_mask || tx_mask) {
|
||||
val |= (1 << 14);
|
||||
snd_soc_update_bits(codec, RT5645_BASS_BACK,
|
||||
RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB);
|
||||
}
|
||||
|
||||
switch (slots) {
|
||||
case 4:
|
||||
|
@ -2071,8 +2159,8 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
|
|||
enum snd_soc_bias_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
|
||||
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
|
||||
RT5645_PWR_VREF1 | RT5645_PWR_MB |
|
||||
RT5645_PWR_BG | RT5645_PWR_VREF2,
|
||||
|
@ -2087,15 +2175,24 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
|
|||
}
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
|
||||
RT5645_PWR_VREF1 | RT5645_PWR_MB |
|
||||
RT5645_PWR_BG | RT5645_PWR_VREF2,
|
||||
RT5645_PWR_VREF1 | RT5645_PWR_MB |
|
||||
RT5645_PWR_BG | RT5645_PWR_VREF2);
|
||||
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
|
||||
RT5645_PWR_FV1 | RT5645_PWR_FV2,
|
||||
RT5645_PWR_FV1 | RT5645_PWR_FV2);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
|
||||
snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128);
|
||||
snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000);
|
||||
snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000);
|
||||
snd_soc_write(codec, RT5645_PWR_VOL, 0x0000);
|
||||
snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000);
|
||||
snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000);
|
||||
snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000);
|
||||
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
|
||||
RT5645_PWR_VREF1 | RT5645_PWR_MB |
|
||||
RT5645_PWR_BG | RT5645_PWR_VREF2 |
|
||||
RT5645_PWR_FV1 | RT5645_PWR_FV2, 0x0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -2106,13 +2203,16 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rt5645_jack_detect(struct snd_soc_codec *codec,
|
||||
struct snd_soc_jack *jack)
|
||||
static int rt5645_jack_detect(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
||||
int gpio_state, jack_type = 0;
|
||||
unsigned int val;
|
||||
|
||||
if (!gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
|
||||
dev_err(codec->dev, "invalid gpio\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
|
||||
|
||||
dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio,
|
||||
|
@ -2145,34 +2245,44 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec,
|
|||
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
|
||||
if (rt5645->pdata.jd_mode == 0)
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
|
||||
snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
}
|
||||
|
||||
snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET);
|
||||
|
||||
snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE);
|
||||
snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
|
||||
struct snd_soc_jack *jack)
|
||||
struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
|
||||
{
|
||||
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
rt5645->jack = jack;
|
||||
|
||||
rt5645_jack_detect(codec, rt5645->jack);
|
||||
rt5645->hp_jack = hp_jack;
|
||||
rt5645->mic_jack = mic_jack;
|
||||
rt5645_jack_detect(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
|
||||
|
||||
static void rt5645_jack_detect_work(struct work_struct *work)
|
||||
{
|
||||
struct rt5645_priv *rt5645 =
|
||||
container_of(work, struct rt5645_priv, jack_detect_work.work);
|
||||
|
||||
rt5645_jack_detect(rt5645->codec);
|
||||
}
|
||||
|
||||
static irqreturn_t rt5645_irq(int irq, void *data)
|
||||
{
|
||||
struct rt5645_priv *rt5645 = data;
|
||||
|
||||
rt5645_jack_detect(rt5645->codec, rt5645->jack);
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&rt5645->jack_detect_work, msecs_to_jiffies(250));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -2187,6 +2297,13 @@ static int rt5645_probe(struct snd_soc_codec *codec)
|
|||
|
||||
snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
|
||||
|
||||
/* for JD function */
|
||||
if (rt5645->pdata.en_jd_func) {
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power");
|
||||
snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2420,6 +2537,51 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
|
|||
|
||||
}
|
||||
|
||||
if (rt5645->pdata.en_jd_func) {
|
||||
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
|
||||
RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU,
|
||||
RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU);
|
||||
regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
|
||||
RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
|
||||
regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3,
|
||||
RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL,
|
||||
RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL);
|
||||
regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
|
||||
RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
|
||||
}
|
||||
|
||||
if (rt5645->pdata.jd_mode) {
|
||||
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
|
||||
RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN);
|
||||
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
|
||||
RT5645_JD_PSV_MODE, RT5645_JD_PSV_MODE);
|
||||
regmap_update_bits(rt5645->regmap, RT5645_HPO_MIXER,
|
||||
RT5645_IRQ_PSV_MODE, RT5645_IRQ_PSV_MODE);
|
||||
regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
|
||||
RT5645_MIC2_OVCD_EN, RT5645_MIC2_OVCD_EN);
|
||||
regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
|
||||
RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
|
||||
switch (rt5645->pdata.jd_mode) {
|
||||
case 1:
|
||||
regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
|
||||
RT5645_JD1_MODE_MASK,
|
||||
RT5645_JD1_MODE_0);
|
||||
break;
|
||||
case 2:
|
||||
regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
|
||||
RT5645_JD1_MODE_MASK,
|
||||
RT5645_JD1_MODE_1);
|
||||
break;
|
||||
case 3:
|
||||
regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
|
||||
RT5645_JD1_MODE_MASK,
|
||||
RT5645_JD1_MODE_2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rt5645->i2c->irq) {
|
||||
ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
|
||||
|
@ -2438,6 +2600,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
|
|||
dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n");
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
|
||||
|
||||
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
|
||||
rt5645_dai, ARRAY_SIZE(rt5645_dai));
|
||||
}
|
||||
|
@ -2449,6 +2613,8 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
|
|||
if (i2c->irq)
|
||||
free_irq(i2c->irq, rt5645);
|
||||
|
||||
cancel_delayed_work_sync(&rt5645->jack_detect_work);
|
||||
|
||||
if (gpio_is_valid(rt5645->pdata.hp_det_gpio))
|
||||
gpio_free(rt5645->pdata.hp_det_gpio);
|
||||
|
||||
|
|
|
@ -594,6 +594,7 @@
|
|||
#define RT5645_M_DAC1_HM_SFT 14
|
||||
#define RT5645_M_HPVOL_HM (0x1 << 13)
|
||||
#define RT5645_M_HPVOL_HM_SFT 13
|
||||
#define RT5645_IRQ_PSV_MODE (0x1 << 12)
|
||||
|
||||
/* SPK Left Mixer Control (0x46) */
|
||||
#define RT5645_G_RM_L_SM_L_MASK (0x3 << 14)
|
||||
|
@ -1348,6 +1349,12 @@
|
|||
#define RT5645_PWR_CLK25M_SFT 4
|
||||
#define RT5645_PWR_CLK25M_PD (0x0 << 4)
|
||||
#define RT5645_PWR_CLK25M_PU (0x1 << 4)
|
||||
#define RT5645_IRQ_CLK_MCLK (0x0 << 3)
|
||||
#define RT5645_IRQ_CLK_INT (0x1 << 3)
|
||||
#define RT5645_JD1_MODE_MASK (0x3 << 0)
|
||||
#define RT5645_JD1_MODE_0 (0x0 << 0)
|
||||
#define RT5645_JD1_MODE_1 (0x1 << 0)
|
||||
#define RT5645_JD1_MODE_2 (0x2 << 0)
|
||||
|
||||
/* VAD Control 4 (0x9d) */
|
||||
#define RT5645_VAD_SEL_MASK (0x3 << 8)
|
||||
|
@ -1636,6 +1643,7 @@
|
|||
#define RT5645_OT_P_SFT 10
|
||||
#define RT5645_OT_P_NOR (0x0 << 10)
|
||||
#define RT5645_OT_P_INV (0x1 << 10)
|
||||
#define RT5645_IRQ_JD_1_1_EN (0x1 << 9)
|
||||
|
||||
/* IRQ Control 2 (0xbe) */
|
||||
#define RT5645_IRQ_MB1_OC_MASK (0x1 << 15)
|
||||
|
@ -1853,6 +1861,7 @@
|
|||
#define RT5645_M_BB_HPF_R_SFT 6
|
||||
#define RT5645_G_BB_BST_MASK (0x3f)
|
||||
#define RT5645_G_BB_BST_SFT 0
|
||||
#define RT5645_G_BB_BST_25DB 0x14
|
||||
|
||||
/* MP3 Plus Control 1 (0xd0) */
|
||||
#define RT5645_M_MP3_L_MASK (0x1 << 15)
|
||||
|
@ -2116,6 +2125,10 @@ enum {
|
|||
#define RT5645_RXDP2_SEL_ADC (0x1 << 3)
|
||||
#define RT5645_RXDP2_SEL_SFT (3)
|
||||
|
||||
/* General Control3 (0xfc) */
|
||||
#define RT5645_JD_PSV_MODE (0x1 << 12)
|
||||
#define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11)
|
||||
#define RT5645_MICINDET_MANU (0x1 << 7)
|
||||
|
||||
/* Vendor ID (0xfd) */
|
||||
#define RT5645_VER_C 0x2
|
||||
|
@ -2167,7 +2180,9 @@ struct rt5645_priv {
|
|||
struct rt5645_platform_data pdata;
|
||||
struct regmap *regmap;
|
||||
struct i2c_client *i2c;
|
||||
struct snd_soc_jack *jack;
|
||||
struct snd_soc_jack *hp_jack;
|
||||
struct snd_soc_jack *mic_jack;
|
||||
struct delayed_work jack_detect_work;
|
||||
|
||||
int sysclk;
|
||||
int sysclk_src;
|
||||
|
@ -2181,6 +2196,6 @@ struct rt5645_priv {
|
|||
};
|
||||
|
||||
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
|
||||
struct snd_soc_jack *jack);
|
||||
struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
|
||||
|
||||
#endif /* __RT5645_H__ */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
|
@ -575,6 +576,18 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
|
|||
|
||||
}
|
||||
|
||||
static int can_use_asrc(struct snd_soc_dapm_widget *source,
|
||||
struct snd_soc_dapm_widget *sink)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
|
||||
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (rt5670->sysclk > rt5670->lrck[RT5670_AIF1] * 384)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Digital Mixer */
|
||||
static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
|
||||
SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
|
||||
|
@ -1281,6 +1294,14 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
|
|||
9, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1,
|
||||
8, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5670_ASRC_1,
|
||||
7, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5670_ASRC_1,
|
||||
6, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5670_ASRC_1,
|
||||
5, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5670_ASRC_1,
|
||||
4, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1,
|
||||
3, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1,
|
||||
|
@ -1595,29 +1616,40 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
|
|||
/* PDM */
|
||||
SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2,
|
||||
RT5670_PWR_PDM1_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2,
|
||||
RT5670_PWR_PDM2_BIT, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL,
|
||||
RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux),
|
||||
SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL,
|
||||
RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux),
|
||||
SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL,
|
||||
RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux),
|
||||
SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL,
|
||||
RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux),
|
||||
|
||||
/* Output Lines */
|
||||
SND_SOC_DAPM_OUTPUT("HPOL"),
|
||||
SND_SOC_DAPM_OUTPUT("HPOR"),
|
||||
SND_SOC_DAPM_OUTPUT("LOUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("LOUTR"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget rt5670_specific_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2,
|
||||
RT5670_PWR_PDM2_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL,
|
||||
RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux),
|
||||
SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL,
|
||||
RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux),
|
||||
SND_SOC_DAPM_OUTPUT("PDM1L"),
|
||||
SND_SOC_DAPM_OUTPUT("PDM1R"),
|
||||
SND_SOC_DAPM_OUTPUT("PDM2L"),
|
||||
SND_SOC_DAPM_OUTPUT("PDM2R"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget rt5672_specific_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_PGA("SPO Amp", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_OUTPUT("SPOLP"),
|
||||
SND_SOC_DAPM_OUTPUT("SPOLN"),
|
||||
SND_SOC_DAPM_OUTPUT("SPORP"),
|
||||
SND_SOC_DAPM_OUTPUT("SPORN"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
|
||||
{ "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc },
|
||||
{ "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc },
|
||||
|
@ -1626,9 +1658,13 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
|
|||
{ "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc },
|
||||
{ "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc },
|
||||
{ "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
|
||||
{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
|
||||
{ "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
|
||||
{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
|
||||
{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
|
||||
|
||||
{ "I2S1", NULL, "I2S1 ASRC" },
|
||||
{ "I2S2", NULL, "I2S2 ASRC" },
|
||||
{ "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
|
||||
{ "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
|
||||
|
||||
{ "DMIC1", NULL, "DMIC L1" },
|
||||
{ "DMIC1", NULL, "DMIC R1" },
|
||||
|
@ -1970,12 +2006,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
|
|||
{ "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
|
||||
{ "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" },
|
||||
{ "PDM1 R Mux", NULL, "PDM1 Power" },
|
||||
{ "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
|
||||
{ "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" },
|
||||
{ "PDM2 L Mux", NULL, "PDM2 Power" },
|
||||
{ "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
|
||||
{ "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" },
|
||||
{ "PDM2 R Mux", NULL, "PDM2 Power" },
|
||||
|
||||
{ "HP Amp", NULL, "HPO MIX" },
|
||||
{ "HP Amp", NULL, "Mic Det Power" },
|
||||
|
@ -1993,13 +2023,30 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
|
|||
{ "LOUTR", NULL, "LOUT R Playback" },
|
||||
{ "LOUTL", NULL, "Improve HP Amp Drv" },
|
||||
{ "LOUTR", NULL, "Improve HP Amp Drv" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route rt5670_specific_dapm_routes[] = {
|
||||
{ "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
|
||||
{ "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" },
|
||||
{ "PDM2 L Mux", NULL, "PDM2 Power" },
|
||||
{ "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
|
||||
{ "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" },
|
||||
{ "PDM2 R Mux", NULL, "PDM2 Power" },
|
||||
{ "PDM1L", NULL, "PDM1 L Mux" },
|
||||
{ "PDM1R", NULL, "PDM1 R Mux" },
|
||||
{ "PDM2L", NULL, "PDM2 L Mux" },
|
||||
{ "PDM2R", NULL, "PDM2 R Mux" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route rt5672_specific_dapm_routes[] = {
|
||||
{ "SPO Amp", NULL, "PDM1 L Mux" },
|
||||
{ "SPO Amp", NULL, "PDM1 R Mux" },
|
||||
{ "SPOLP", NULL, "SPO Amp" },
|
||||
{ "SPOLN", NULL, "SPO Amp" },
|
||||
{ "SPORP", NULL, "SPO Amp" },
|
||||
{ "SPORN", NULL, "SPO Amp" },
|
||||
};
|
||||
|
||||
static int rt5670_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
|
@ -2287,6 +2334,8 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
|||
static int rt5670_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
|
||||
|
@ -2308,16 +2357,27 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
|
|||
}
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
snd_soc_write(codec, RT5670_PWR_DIG1, 0x0000);
|
||||
snd_soc_write(codec, RT5670_PWR_DIG2, 0x0001);
|
||||
snd_soc_write(codec, RT5670_PWR_VOL, 0x0000);
|
||||
snd_soc_write(codec, RT5670_PWR_MIXER, 0x0001);
|
||||
snd_soc_write(codec, RT5670_PWR_ANLG1, 0x2800);
|
||||
snd_soc_write(codec, RT5670_PWR_ANLG2, 0x0004);
|
||||
snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0);
|
||||
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
|
||||
RT5670_PWR_VREF1 | RT5670_PWR_VREF2 |
|
||||
RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
|
||||
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
|
||||
RT5670_LDO_SEL_MASK, 0x1);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
if (rt5670->pdata.jd_mode)
|
||||
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
|
||||
RT5670_PWR_VREF1 | RT5670_PWR_MB |
|
||||
RT5670_PWR_BG | RT5670_PWR_VREF2 |
|
||||
RT5670_PWR_FV1 | RT5670_PWR_FV2,
|
||||
RT5670_PWR_MB | RT5670_PWR_BG);
|
||||
else
|
||||
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
|
||||
RT5670_PWR_VREF1 | RT5670_PWR_MB |
|
||||
RT5670_PWR_BG | RT5670_PWR_VREF2 |
|
||||
RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
|
||||
|
||||
snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -2331,6 +2391,29 @@ static int rt5670_probe(struct snd_soc_codec *codec)
|
|||
{
|
||||
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) {
|
||||
case RT5670_ID_5670:
|
||||
case RT5670_ID_5671:
|
||||
snd_soc_dapm_new_controls(&codec->dapm,
|
||||
rt5670_specific_dapm_widgets,
|
||||
ARRAY_SIZE(rt5670_specific_dapm_widgets));
|
||||
snd_soc_dapm_add_routes(&codec->dapm,
|
||||
rt5670_specific_dapm_routes,
|
||||
ARRAY_SIZE(rt5670_specific_dapm_routes));
|
||||
break;
|
||||
case RT5670_ID_5672:
|
||||
snd_soc_dapm_new_controls(&codec->dapm,
|
||||
rt5672_specific_dapm_widgets,
|
||||
ARRAY_SIZE(rt5672_specific_dapm_widgets));
|
||||
snd_soc_dapm_add_routes(&codec->dapm,
|
||||
rt5672_specific_dapm_routes,
|
||||
ARRAY_SIZE(rt5672_specific_dapm_routes));
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev,
|
||||
"The driver is for RT5670 RT5671 or RT5672 only\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
rt5670->codec = codec;
|
||||
|
||||
return 0;
|
||||
|
@ -2452,10 +2535,20 @@ static const struct regmap_config rt5670_regmap = {
|
|||
|
||||
static const struct i2c_device_id rt5670_i2c_id[] = {
|
||||
{ "rt5670", 0 },
|
||||
{ "rt5671", 0 },
|
||||
{ "rt5672", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static struct acpi_device_id rt5670_acpi_match[] = {
|
||||
{ "10EC5670", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
|
||||
#endif
|
||||
|
||||
static int rt5670_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -2644,6 +2737,7 @@ static struct i2c_driver rt5670_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "rt5670",
|
||||
.owner = THIS_MODULE,
|
||||
.acpi_match_table = ACPI_PTR(rt5670_acpi_match),
|
||||
},
|
||||
.probe = rt5670_i2c_probe,
|
||||
.remove = rt5670_i2c_remove,
|
||||
|
|
|
@ -228,6 +228,12 @@
|
|||
#define RT5670_R_VOL_MASK (0x3f)
|
||||
#define RT5670_R_VOL_SFT 0
|
||||
|
||||
/* SW Reset & Device ID (0x00) */
|
||||
#define RT5670_ID_MASK (0x3 << 1)
|
||||
#define RT5670_ID_5670 (0x0 << 1)
|
||||
#define RT5670_ID_5672 (0x1 << 1)
|
||||
#define RT5670_ID_5671 (0x2 << 1)
|
||||
|
||||
/* Combo Jack Control 1 (0x0a) */
|
||||
#define RT5670_CBJ_BST1_MASK (0xf << 12)
|
||||
#define RT5670_CBJ_BST1_SFT (12)
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* rt5677-spi.c -- RT5677 ALSA SoC audio codec driver
|
||||
*
|
||||
* Copyright 2013 Realtek Semiconductor Corp.
|
||||
* Author: Oder Chiou <oder_chiou@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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include "rt5677-spi.h"
|
||||
|
||||
static struct spi_device *g_spi;
|
||||
|
||||
/**
|
||||
* rt5677_spi_write - Write data to SPI.
|
||||
* @txbuf: Data Buffer for writing.
|
||||
* @len: Data length.
|
||||
*
|
||||
*
|
||||
* Returns true for success.
|
||||
*/
|
||||
int rt5677_spi_write(u8 *txbuf, size_t len)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = spi_write(g_spi, txbuf, len);
|
||||
|
||||
if (status)
|
||||
dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5677_spi_write);
|
||||
|
||||
/**
|
||||
* rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address.
|
||||
* @addr: Start address.
|
||||
* @txbuf: Data Buffer for writng.
|
||||
* @len: Data length, it must be a multiple of 8.
|
||||
*
|
||||
*
|
||||
* Returns true for success.
|
||||
*/
|
||||
int rt5677_spi_burst_write(u32 addr, const struct firmware *fw)
|
||||
{
|
||||
u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE;
|
||||
u8 *write_buf;
|
||||
unsigned int i, end, offset = 0;
|
||||
|
||||
write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL);
|
||||
|
||||
if (write_buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
while (offset < fw->size) {
|
||||
if (offset + RT5677_SPI_BUF_LEN <= fw->size)
|
||||
end = RT5677_SPI_BUF_LEN;
|
||||
else
|
||||
end = fw->size % RT5677_SPI_BUF_LEN;
|
||||
|
||||
write_buf[0] = spi_cmd;
|
||||
write_buf[1] = ((addr + offset) & 0xff000000) >> 24;
|
||||
write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
|
||||
write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
|
||||
write_buf[4] = ((addr + offset) & 0x000000ff) >> 0;
|
||||
|
||||
for (i = 0; i < end; i += 8) {
|
||||
write_buf[i + 12] = fw->data[offset + i + 0];
|
||||
write_buf[i + 11] = fw->data[offset + i + 1];
|
||||
write_buf[i + 10] = fw->data[offset + i + 2];
|
||||
write_buf[i + 9] = fw->data[offset + i + 3];
|
||||
write_buf[i + 8] = fw->data[offset + i + 4];
|
||||
write_buf[i + 7] = fw->data[offset + i + 5];
|
||||
write_buf[i + 6] = fw->data[offset + i + 6];
|
||||
write_buf[i + 5] = fw->data[offset + i + 7];
|
||||
}
|
||||
|
||||
write_buf[end + 5] = spi_cmd;
|
||||
|
||||
rt5677_spi_write(write_buf, end + 6);
|
||||
|
||||
offset += RT5677_SPI_BUF_LEN;
|
||||
}
|
||||
|
||||
kfree(write_buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5677_spi_burst_write);
|
||||
|
||||
static int rt5677_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
g_spi = spi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver rt5677_spi_driver = {
|
||||
.driver = {
|
||||
.name = "rt5677",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = rt5677_spi_probe,
|
||||
};
|
||||
module_spi_driver(rt5677_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC RT5677 SPI driver");
|
||||
MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* rt5677-spi.h -- RT5677 ALSA SoC audio codec driver
|
||||
*
|
||||
* Copyright 2013 Realtek Semiconductor Corp.
|
||||
* Author: Oder Chiou <oder_chiou@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 __RT5677_SPI_H__
|
||||
#define __RT5677_SPI_H__
|
||||
|
||||
#define RT5677_SPI_BUF_LEN 240
|
||||
#define RT5677_SPI_CMD_BURST_WRITE 0x05
|
||||
|
||||
int rt5677_spi_write(u8 *txbuf, size_t len);
|
||||
int rt5677_spi_burst_write(u32 addr, const struct firmware *fw);
|
||||
|
||||
#endif /* __RT5677_SPI_H__ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -13,6 +13,7 @@
|
|||
#define __RT5677_H__
|
||||
|
||||
#include <sound/rt5677.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
/* Info */
|
||||
#define RT5677_RESET 0x00
|
||||
|
@ -305,10 +306,10 @@
|
|||
#define RT5677_R_MUTE_SFT 7
|
||||
#define RT5677_VOL_R_MUTE (0x1 << 6)
|
||||
#define RT5677_VOL_R_SFT 6
|
||||
#define RT5677_L_VOL_MASK (0x3f << 8)
|
||||
#define RT5677_L_VOL_SFT 8
|
||||
#define RT5677_R_VOL_MASK (0x3f)
|
||||
#define RT5677_R_VOL_SFT 0
|
||||
#define RT5677_L_VOL_MASK (0x7f << 9)
|
||||
#define RT5677_L_VOL_SFT 9
|
||||
#define RT5677_R_VOL_MASK (0x7f << 1)
|
||||
#define RT5677_R_VOL_SFT 1
|
||||
|
||||
/* LOUT1 Control (0x01) */
|
||||
#define RT5677_LOUT1_L_MUTE (0x1 << 15)
|
||||
|
@ -446,16 +447,16 @@
|
|||
#define RT5677_SEL_DAC2_R_SRC_SFT 0
|
||||
|
||||
/* Stereo1 ADC Digital Volume Control (0x1c) */
|
||||
#define RT5677_STO1_ADC_L_VOL_MASK (0x7f << 8)
|
||||
#define RT5677_STO1_ADC_L_VOL_SFT 8
|
||||
#define RT5677_STO1_ADC_R_VOL_MASK (0x7f)
|
||||
#define RT5677_STO1_ADC_R_VOL_SFT 0
|
||||
#define RT5677_STO1_ADC_L_VOL_MASK (0x3f << 9)
|
||||
#define RT5677_STO1_ADC_L_VOL_SFT 9
|
||||
#define RT5677_STO1_ADC_R_VOL_MASK (0x3f << 1)
|
||||
#define RT5677_STO1_ADC_R_VOL_SFT 1
|
||||
|
||||
/* Mono ADC Digital Volume Control (0x1d) */
|
||||
#define RT5677_MONO_ADC_L_VOL_MASK (0x7f << 8)
|
||||
#define RT5677_MONO_ADC_L_VOL_SFT 8
|
||||
#define RT5677_MONO_ADC_R_VOL_MASK (0x7f)
|
||||
#define RT5677_MONO_ADC_R_VOL_SFT 0
|
||||
#define RT5677_MONO_ADC_L_VOL_MASK (0x3f << 9)
|
||||
#define RT5677_MONO_ADC_L_VOL_SFT 9
|
||||
#define RT5677_MONO_ADC_R_VOL_MASK (0x3f << 1)
|
||||
#define RT5677_MONO_ADC_R_VOL_SFT 1
|
||||
|
||||
/* Stereo 1/2 ADC Boost Gain Control (0x1e) */
|
||||
#define RT5677_STO1_ADC_L_BST_MASK (0x3 << 14)
|
||||
|
@ -798,7 +799,21 @@
|
|||
#define RT5677_PDM2_I2C_EXE (0x1 << 1)
|
||||
#define RT5677_PDM2_I2C_BUSY (0x1 << 0)
|
||||
|
||||
/* MX3C TDM1 control 1 (0x3c) */
|
||||
/* TDM1 control 1 (0x3b) */
|
||||
#define RT5677_IF1_ADC_MODE_MASK (0x1 << 12)
|
||||
#define RT5677_IF1_ADC_MODE_SFT 12
|
||||
#define RT5677_IF1_ADC_MODE_I2S (0x0 << 12)
|
||||
#define RT5677_IF1_ADC_MODE_TDM (0x1 << 12)
|
||||
#define RT5677_IF1_ADC1_SWAP_MASK (0x3 << 6)
|
||||
#define RT5677_IF1_ADC1_SWAP_SFT 6
|
||||
#define RT5677_IF1_ADC2_SWAP_MASK (0x3 << 4)
|
||||
#define RT5677_IF1_ADC2_SWAP_SFT 4
|
||||
#define RT5677_IF1_ADC3_SWAP_MASK (0x3 << 2)
|
||||
#define RT5677_IF1_ADC3_SWAP_SFT 2
|
||||
#define RT5677_IF1_ADC4_SWAP_MASK (0x3 << 0)
|
||||
#define RT5677_IF1_ADC4_SWAP_SFT 0
|
||||
|
||||
/* TDM1 control 2 (0x3c) */
|
||||
#define RT5677_IF1_ADC4_MASK (0x3 << 10)
|
||||
#define RT5677_IF1_ADC4_SFT 10
|
||||
#define RT5677_IF1_ADC3_MASK (0x3 << 8)
|
||||
|
@ -807,8 +822,44 @@
|
|||
#define RT5677_IF1_ADC2_SFT 6
|
||||
#define RT5677_IF1_ADC1_MASK (0x3 << 4)
|
||||
#define RT5677_IF1_ADC1_SFT 4
|
||||
#define RT5677_IF1_ADC_CTRL_MASK (0x7 << 0)
|
||||
#define RT5677_IF1_ADC_CTRL_SFT 0
|
||||
|
||||
/* MX41 TDM2 control 1 (0x41) */
|
||||
/* TDM1 control 4 (0x3e) */
|
||||
#define RT5677_IF1_DAC0_MASK (0x7 << 12)
|
||||
#define RT5677_IF1_DAC0_SFT 12
|
||||
#define RT5677_IF1_DAC1_MASK (0x7 << 8)
|
||||
#define RT5677_IF1_DAC1_SFT 8
|
||||
#define RT5677_IF1_DAC2_MASK (0x7 << 4)
|
||||
#define RT5677_IF1_DAC2_SFT 4
|
||||
#define RT5677_IF1_DAC3_MASK (0x7 << 0)
|
||||
#define RT5677_IF1_DAC3_SFT 0
|
||||
|
||||
/* TDM1 control 5 (0x3f) */
|
||||
#define RT5677_IF1_DAC4_MASK (0x7 << 12)
|
||||
#define RT5677_IF1_DAC4_SFT 12
|
||||
#define RT5677_IF1_DAC5_MASK (0x7 << 8)
|
||||
#define RT5677_IF1_DAC5_SFT 8
|
||||
#define RT5677_IF1_DAC6_MASK (0x7 << 4)
|
||||
#define RT5677_IF1_DAC6_SFT 4
|
||||
#define RT5677_IF1_DAC7_MASK (0x7 << 0)
|
||||
#define RT5677_IF1_DAC7_SFT 0
|
||||
|
||||
/* TDM2 control 1 (0x40) */
|
||||
#define RT5677_IF2_ADC_MODE_MASK (0x1 << 12)
|
||||
#define RT5677_IF2_ADC_MODE_SFT 12
|
||||
#define RT5677_IF2_ADC_MODE_I2S (0x0 << 12)
|
||||
#define RT5677_IF2_ADC_MODE_TDM (0x1 << 12)
|
||||
#define RT5677_IF2_ADC1_SWAP_MASK (0x3 << 6)
|
||||
#define RT5677_IF2_ADC1_SWAP_SFT 6
|
||||
#define RT5677_IF2_ADC2_SWAP_MASK (0x3 << 4)
|
||||
#define RT5677_IF2_ADC2_SWAP_SFT 4
|
||||
#define RT5677_IF2_ADC3_SWAP_MASK (0x3 << 2)
|
||||
#define RT5677_IF2_ADC3_SWAP_SFT 2
|
||||
#define RT5677_IF2_ADC4_SWAP_MASK (0x3 << 0)
|
||||
#define RT5677_IF2_ADC4_SWAP_SFT 0
|
||||
|
||||
/* TDM2 control 2 (0x41) */
|
||||
#define RT5677_IF2_ADC4_MASK (0x3 << 10)
|
||||
#define RT5677_IF2_ADC4_SFT 10
|
||||
#define RT5677_IF2_ADC3_MASK (0x3 << 8)
|
||||
|
@ -817,6 +868,28 @@
|
|||
#define RT5677_IF2_ADC2_SFT 6
|
||||
#define RT5677_IF2_ADC1_MASK (0x3 << 4)
|
||||
#define RT5677_IF2_ADC1_SFT 4
|
||||
#define RT5677_IF2_ADC_CTRL_MASK (0x7 << 0)
|
||||
#define RT5677_IF2_ADC_CTRL_SFT 0
|
||||
|
||||
/* TDM2 control 4 (0x43) */
|
||||
#define RT5677_IF2_DAC0_MASK (0x7 << 12)
|
||||
#define RT5677_IF2_DAC0_SFT 12
|
||||
#define RT5677_IF2_DAC1_MASK (0x7 << 8)
|
||||
#define RT5677_IF2_DAC1_SFT 8
|
||||
#define RT5677_IF2_DAC2_MASK (0x7 << 4)
|
||||
#define RT5677_IF2_DAC2_SFT 4
|
||||
#define RT5677_IF2_DAC3_MASK (0x7 << 0)
|
||||
#define RT5677_IF2_DAC3_SFT 0
|
||||
|
||||
/* TDM2 control 5 (0x44) */
|
||||
#define RT5677_IF2_DAC4_MASK (0x7 << 12)
|
||||
#define RT5677_IF2_DAC4_SFT 12
|
||||
#define RT5677_IF2_DAC5_MASK (0x7 << 8)
|
||||
#define RT5677_IF2_DAC5_SFT 8
|
||||
#define RT5677_IF2_DAC6_MASK (0x7 << 4)
|
||||
#define RT5677_IF2_DAC6_SFT 4
|
||||
#define RT5677_IF2_DAC7_MASK (0x7 << 0)
|
||||
#define RT5677_IF2_DAC7_SFT 0
|
||||
|
||||
/* Digital Microphone Control 1 (0x50) */
|
||||
#define RT5677_DMIC_1_EN_MASK (0x1 << 15)
|
||||
|
@ -1367,6 +1440,48 @@
|
|||
#define RT5677_SEL_SRC_IB01 (0x1 << 0)
|
||||
#define RT5677_SEL_SRC_IB01_SFT 0
|
||||
|
||||
/* Jack Detect Control 1 (0xb5) */
|
||||
#define RT5677_SEL_GPIO_JD1_MASK (0x3 << 14)
|
||||
#define RT5677_SEL_GPIO_JD1_SFT 14
|
||||
#define RT5677_SEL_GPIO_JD2_MASK (0x3 << 12)
|
||||
#define RT5677_SEL_GPIO_JD2_SFT 12
|
||||
#define RT5677_SEL_GPIO_JD3_MASK (0x3 << 10)
|
||||
#define RT5677_SEL_GPIO_JD3_SFT 10
|
||||
|
||||
/* IRQ Control 1 (0xbd) */
|
||||
#define RT5677_STA_GPIO_JD1 (0x1 << 15)
|
||||
#define RT5677_STA_GPIO_JD1_SFT 15
|
||||
#define RT5677_EN_IRQ_GPIO_JD1 (0x1 << 14)
|
||||
#define RT5677_EN_IRQ_GPIO_JD1_SFT 14
|
||||
#define RT5677_EN_GPIO_JD1_STICKY (0x1 << 13)
|
||||
#define RT5677_EN_GPIO_JD1_STICKY_SFT 13
|
||||
#define RT5677_INV_GPIO_JD1 (0x1 << 12)
|
||||
#define RT5677_INV_GPIO_JD1_SFT 12
|
||||
#define RT5677_STA_GPIO_JD2 (0x1 << 11)
|
||||
#define RT5677_STA_GPIO_JD2_SFT 11
|
||||
#define RT5677_EN_IRQ_GPIO_JD2 (0x1 << 10)
|
||||
#define RT5677_EN_IRQ_GPIO_JD2_SFT 10
|
||||
#define RT5677_EN_GPIO_JD2_STICKY (0x1 << 9)
|
||||
#define RT5677_EN_GPIO_JD2_STICKY_SFT 9
|
||||
#define RT5677_INV_GPIO_JD2 (0x1 << 8)
|
||||
#define RT5677_INV_GPIO_JD2_SFT 8
|
||||
#define RT5677_STA_MICBIAS1_OVCD (0x1 << 7)
|
||||
#define RT5677_STA_MICBIAS1_OVCD_SFT 7
|
||||
#define RT5677_EN_IRQ_MICBIAS1_OVCD (0x1 << 6)
|
||||
#define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT 6
|
||||
#define RT5677_EN_MICBIAS1_OVCD_STICKY (0x1 << 5)
|
||||
#define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT 5
|
||||
#define RT5677_INV_MICBIAS1_OVCD (0x1 << 4)
|
||||
#define RT5677_INV_MICBIAS1_OVCD_SFT 4
|
||||
#define RT5677_STA_GPIO_JD3 (0x1 << 3)
|
||||
#define RT5677_STA_GPIO_JD3_SFT 3
|
||||
#define RT5677_EN_IRQ_GPIO_JD3 (0x1 << 2)
|
||||
#define RT5677_EN_IRQ_GPIO_JD3_SFT 2
|
||||
#define RT5677_EN_GPIO_JD3_STICKY (0x1 << 1)
|
||||
#define RT5677_EN_GPIO_JD3_STICKY_SFT 1
|
||||
#define RT5677_INV_GPIO_JD3 (0x1 << 0)
|
||||
#define RT5677_INV_GPIO_JD3_SFT 0
|
||||
|
||||
/* GPIO status (0xbf) */
|
||||
#define RT5677_GPIO6_STATUS_MASK (0x1 << 5)
|
||||
#define RT5677_GPIO6_STATUS_SFT 5
|
||||
|
@ -1506,6 +1621,9 @@
|
|||
#define RT5677_GPIO5_FUNC_GPIO (0x0 << 9)
|
||||
#define RT5677_GPIO5_FUNC_DMIC (0x1 << 9)
|
||||
|
||||
#define RT5677_FIRMWARE1 "rt5677_dsp_fw1.bin"
|
||||
#define RT5677_FIRMWARE2 "rt5677_dsp_fw2.bin"
|
||||
|
||||
/* System Clock Source */
|
||||
enum {
|
||||
RT5677_SCLK_S_MCLK,
|
||||
|
@ -1541,10 +1659,18 @@ enum {
|
|||
RT5677_GPIO_NUM,
|
||||
};
|
||||
|
||||
enum {
|
||||
RT5677_IRQ_JD1,
|
||||
RT5677_IRQ_JD2,
|
||||
RT5677_IRQ_JD3,
|
||||
};
|
||||
|
||||
struct rt5677_priv {
|
||||
struct snd_soc_codec *codec;
|
||||
struct rt5677_platform_data pdata;
|
||||
struct regmap *regmap;
|
||||
struct regmap *regmap, *regmap_physical;
|
||||
const struct firmware *fw1, *fw2;
|
||||
struct mutex dsp_cmd_lock, dsp_pri_lock;
|
||||
|
||||
int sysclk;
|
||||
int sysclk_src;
|
||||
|
@ -1558,6 +1684,10 @@ struct rt5677_priv {
|
|||
#ifdef CONFIG_GPIOLIB
|
||||
struct gpio_chip gpio_chip;
|
||||
#endif
|
||||
bool dsp_vad_en;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
bool is_dsp_mode;
|
||||
bool is_vref_slow;
|
||||
};
|
||||
|
||||
#endif /* __RT5677_H__ */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
@ -121,6 +122,13 @@ struct ldo_regulator {
|
|||
bool enabled;
|
||||
};
|
||||
|
||||
enum sgtl5000_micbias_resistor {
|
||||
SGTL5000_MICBIAS_OFF = 0,
|
||||
SGTL5000_MICBIAS_2K = 2,
|
||||
SGTL5000_MICBIAS_4K = 4,
|
||||
SGTL5000_MICBIAS_8K = 8,
|
||||
};
|
||||
|
||||
/* sgtl5000 private structure in codec */
|
||||
struct sgtl5000_priv {
|
||||
int sysclk; /* sysclk rate */
|
||||
|
@ -131,6 +139,8 @@ struct sgtl5000_priv {
|
|||
struct regmap *regmap;
|
||||
struct clk *mclk;
|
||||
int revision;
|
||||
u8 micbias_resistor;
|
||||
u8 micbias_voltage;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -145,12 +155,14 @@ struct sgtl5000_priv {
|
|||
static int mic_bias_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
/* change mic bias resistor to 4Kohm */
|
||||
/* change mic bias resistor */
|
||||
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
|
||||
SGTL5000_BIAS_R_MASK,
|
||||
SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT);
|
||||
SGTL5000_BIAS_R_MASK,
|
||||
sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
|
@ -530,16 +542,16 @@ static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
|||
|
||||
/*
|
||||
* set clock according to i2s frame clock,
|
||||
* sgtl5000 provide 2 clock sources.
|
||||
* 1. sys_mclk. sample freq can only configure to
|
||||
* sgtl5000 provides 2 clock sources:
|
||||
* 1. sys_mclk: sample freq can only be configured to
|
||||
* 1/256, 1/384, 1/512 of sys_mclk.
|
||||
* 2. pll. can derive any audio clocks.
|
||||
* 2. pll: can derive any audio clocks.
|
||||
*
|
||||
* clock setting rules:
|
||||
* 1. in slave mode, only sys_mclk can use.
|
||||
* 2. as constraint by sys_mclk, sample freq should
|
||||
* set to 32k, 44.1k and above.
|
||||
* 3. using sys_mclk prefer to pll to save power.
|
||||
* 1. in slave mode, only sys_mclk can be used
|
||||
* 2. as constraint by sys_mclk, sample freq should be set to 32 kHz, 44.1 kHz
|
||||
* and above.
|
||||
* 3. usage of sys_mclk is preferred over pll to save power.
|
||||
*/
|
||||
static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
|
||||
{
|
||||
|
@ -549,8 +561,8 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
|
|||
|
||||
/*
|
||||
* sample freq should be divided by frame clock,
|
||||
* if frame clock lower than 44.1khz, sample feq should set to
|
||||
* 32khz or 44.1khz.
|
||||
* if frame clock is lower than 44.1 kHz, sample freq should be set to
|
||||
* 32 kHz or 44.1 kHz.
|
||||
*/
|
||||
switch (frame_rate) {
|
||||
case 8000:
|
||||
|
@ -603,9 +615,10 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
|
|||
|
||||
/*
|
||||
* calculate the divider of mclk/sample_freq,
|
||||
* factor of freq =96k can only be 256, since mclk in range (12m,27m)
|
||||
* factor of freq = 96 kHz can only be 256, since mclk is in the range
|
||||
* of 8 MHz - 27 MHz
|
||||
*/
|
||||
switch (sgtl5000->sysclk / sys_fs) {
|
||||
switch (sgtl5000->sysclk / frame_rate) {
|
||||
case 256:
|
||||
clk_ctl |= SGTL5000_MCLK_FREQ_256FS <<
|
||||
SGTL5000_MCLK_FREQ_SHIFT;
|
||||
|
@ -619,7 +632,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
|
|||
SGTL5000_MCLK_FREQ_SHIFT;
|
||||
break;
|
||||
default:
|
||||
/* if mclk not satisify the divider, use pll */
|
||||
/* if mclk does not satisfy the divider, use pll */
|
||||
if (sgtl5000->master) {
|
||||
clk_ctl |= SGTL5000_MCLK_FREQ_PLL <<
|
||||
SGTL5000_MCLK_FREQ_SHIFT;
|
||||
|
@ -628,7 +641,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
|
|||
"PLL not supported in slave mode\n");
|
||||
dev_err(codec->dev, "%d ratio is not supported. "
|
||||
"SYS_MCLK needs to be 256, 384 or 512 * fs\n",
|
||||
sgtl5000->sysclk / sys_fs);
|
||||
sgtl5000->sysclk / frame_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
@ -795,7 +808,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev)
|
|||
SGTL5000_LINEREG_D_POWERUP,
|
||||
SGTL5000_LINEREG_D_POWERUP);
|
||||
|
||||
/* when internal ldo enabled, simple digital power can be disabled */
|
||||
/* when internal ldo is enabled, simple digital power can be disabled */
|
||||
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
|
||||
SGTL5000_LINREG_SIMPLE_POWERUP,
|
||||
0);
|
||||
|
@ -1079,7 +1092,7 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg)
|
|||
/*
|
||||
* sgtl5000 has 3 internal power supplies:
|
||||
* 1. VAG, normally set to vdda/2
|
||||
* 2. chargepump, set to different value
|
||||
* 2. charge pump, set to different value
|
||||
* according to voltage of vdda and vddio
|
||||
* 3. line out VAG, normally set to vddio/2
|
||||
*
|
||||
|
@ -1325,8 +1338,13 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
|
|||
SGTL5000_HP_ZCD_EN |
|
||||
SGTL5000_ADC_ZCD_EN);
|
||||
|
||||
snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2);
|
||||
snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
|
||||
SGTL5000_BIAS_R_MASK,
|
||||
sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
|
||||
|
||||
snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
|
||||
SGTL5000_BIAS_R_MASK,
|
||||
sgtl5000->micbias_voltage << SGTL5000_BIAS_R_SHIFT);
|
||||
/*
|
||||
* disable DAP
|
||||
* TODO:
|
||||
|
@ -1416,10 +1434,10 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
|
|||
{
|
||||
struct sgtl5000_priv *sgtl5000;
|
||||
int ret, reg, rev;
|
||||
unsigned int mclk;
|
||||
struct device_node *np = client->dev.of_node;
|
||||
u32 value;
|
||||
|
||||
sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv),
|
||||
GFP_KERNEL);
|
||||
sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL);
|
||||
if (!sgtl5000)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1440,14 +1458,6 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */
|
||||
mclk = clk_get_rate(sgtl5000->mclk);
|
||||
if (mclk < 8000000 || mclk > 27000000) {
|
||||
dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n",
|
||||
mclk / 1000000, mclk / 1000 % 1000);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(sgtl5000->mclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1469,6 +1479,47 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
|
|||
dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
|
||||
sgtl5000->revision = rev;
|
||||
|
||||
if (np) {
|
||||
if (!of_property_read_u32(np,
|
||||
"micbias-resistor-k-ohms", &value)) {
|
||||
switch (value) {
|
||||
case SGTL5000_MICBIAS_OFF:
|
||||
sgtl5000->micbias_resistor = 0;
|
||||
break;
|
||||
case SGTL5000_MICBIAS_2K:
|
||||
sgtl5000->micbias_resistor = 1;
|
||||
break;
|
||||
case SGTL5000_MICBIAS_4K:
|
||||
sgtl5000->micbias_resistor = 2;
|
||||
break;
|
||||
case SGTL5000_MICBIAS_8K:
|
||||
sgtl5000->micbias_resistor = 3;
|
||||
break;
|
||||
default:
|
||||
sgtl5000->micbias_resistor = 2;
|
||||
dev_err(&client->dev,
|
||||
"Unsuitable MicBias resistor\n");
|
||||
}
|
||||
} else {
|
||||
/* default is 4Kohms */
|
||||
sgtl5000->micbias_resistor = 2;
|
||||
}
|
||||
if (!of_property_read_u32(np,
|
||||
"micbias-voltage-m-volts", &value)) {
|
||||
/* 1250mV => 0 */
|
||||
/* steps of 250mV */
|
||||
if ((value >= 1250) && (value <= 3000))
|
||||
sgtl5000->micbias_voltage = (value / 250) - 5;
|
||||
else {
|
||||
sgtl5000->micbias_voltage = 0;
|
||||
dev_err(&client->dev,
|
||||
"Unsuitable MicBias resistor\n");
|
||||
}
|
||||
} else {
|
||||
sgtl5000->micbias_voltage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, sgtl5000);
|
||||
|
||||
/* Ensure sgtl5000 will start with sane register values */
|
||||
|
|
|
@ -6,29 +6,88 @@
|
|||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "sigmadsp.h"
|
||||
|
||||
static int sigma_action_write_i2c(void *control_data,
|
||||
const struct sigma_action *sa, size_t len)
|
||||
static int sigmadsp_write_i2c(void *control_data,
|
||||
unsigned int addr, const uint8_t data[], size_t len)
|
||||
{
|
||||
return i2c_master_send(control_data, (const unsigned char *)&sa->addr,
|
||||
len);
|
||||
uint8_t *buf;
|
||||
int ret;
|
||||
|
||||
buf = kzalloc(2 + len, GFP_KERNEL | GFP_DMA);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
put_unaligned_be16(addr, buf);
|
||||
memcpy(buf + 2, data, len);
|
||||
|
||||
ret = i2c_master_send(control_data, buf, len + 2);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int process_sigma_firmware(struct i2c_client *client, const char *name)
|
||||
static int sigmadsp_read_i2c(void *control_data,
|
||||
unsigned int addr, uint8_t data[], size_t len)
|
||||
{
|
||||
struct sigma_firmware ssfw;
|
||||
struct i2c_client *client = control_data;
|
||||
struct i2c_msg msgs[2];
|
||||
uint8_t buf[2];
|
||||
int ret;
|
||||
|
||||
ssfw.control_data = client;
|
||||
ssfw.write = sigma_action_write_i2c;
|
||||
put_unaligned_be16(addr, buf);
|
||||
|
||||
return _process_sigma_firmware(&client->dev, &ssfw, name);
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].len = sizeof(buf);
|
||||
msgs[0].buf = buf;
|
||||
msgs[0].flags = 0;
|
||||
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].len = len;
|
||||
msgs[1].buf = data;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret != ARRAY_SIZE(msgs))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(process_sigma_firmware);
|
||||
|
||||
/**
|
||||
* devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
|
||||
* @client: The parent I2C device
|
||||
* @ops: The sigmadsp_ops to use for this instance
|
||||
* @firmware_name: Name of the firmware file to load
|
||||
*
|
||||
* Allocates a SigmaDSP instance and loads the specified firmware file.
|
||||
*
|
||||
* Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
|
||||
*/
|
||||
struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
|
||||
const struct sigmadsp_ops *ops, const char *firmware_name)
|
||||
{
|
||||
struct sigmadsp *sigmadsp;
|
||||
|
||||
sigmadsp = devm_sigmadsp_init(&client->dev, ops, firmware_name);
|
||||
if (IS_ERR(sigmadsp))
|
||||
return sigmadsp;
|
||||
|
||||
sigmadsp->control_data = client;
|
||||
sigmadsp->write = sigmadsp_write_i2c;
|
||||
sigmadsp->read = sigmadsp_read_i2c;
|
||||
|
||||
return sigmadsp;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_sigmadsp_init_i2c);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("SigmaDSP I2C firmware loader");
|
||||
|
|
|
@ -12,24 +12,48 @@
|
|||
|
||||
#include "sigmadsp.h"
|
||||
|
||||
static int sigma_action_write_regmap(void *control_data,
|
||||
const struct sigma_action *sa, size_t len)
|
||||
static int sigmadsp_write_regmap(void *control_data,
|
||||
unsigned int addr, const uint8_t data[], size_t len)
|
||||
{
|
||||
return regmap_raw_write(control_data, be16_to_cpu(sa->addr),
|
||||
sa->payload, len - 2);
|
||||
return regmap_raw_write(control_data, addr,
|
||||
data, len);
|
||||
}
|
||||
|
||||
int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap,
|
||||
const char *name)
|
||||
static int sigmadsp_read_regmap(void *control_data,
|
||||
unsigned int addr, uint8_t data[], size_t len)
|
||||
{
|
||||
struct sigma_firmware ssfw;
|
||||
|
||||
ssfw.control_data = regmap;
|
||||
ssfw.write = sigma_action_write_regmap;
|
||||
|
||||
return _process_sigma_firmware(dev, &ssfw, name);
|
||||
return regmap_raw_read(control_data, addr,
|
||||
data, len);
|
||||
}
|
||||
EXPORT_SYMBOL(process_sigma_firmware_regmap);
|
||||
|
||||
/**
|
||||
* devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
|
||||
* @dev: The parent device
|
||||
* @regmap: Regmap instance to use
|
||||
* @ops: The sigmadsp_ops to use for this instance
|
||||
* @firmware_name: Name of the firmware file to load
|
||||
*
|
||||
* Allocates a SigmaDSP instance and loads the specified firmware file.
|
||||
*
|
||||
* Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
|
||||
*/
|
||||
struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
|
||||
struct regmap *regmap, const struct sigmadsp_ops *ops,
|
||||
const char *firmware_name)
|
||||
{
|
||||
struct sigmadsp *sigmadsp;
|
||||
|
||||
sigmadsp = devm_sigmadsp_init(dev, ops, firmware_name);
|
||||
if (IS_ERR(sigmadsp))
|
||||
return sigmadsp;
|
||||
|
||||
sigmadsp->control_data = regmap;
|
||||
sigmadsp->write = sigmadsp_write_regmap;
|
||||
sigmadsp->read = sigmadsp_read_regmap;
|
||||
|
||||
return sigmadsp;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_sigmadsp_init_regmap);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("SigmaDSP regmap firmware loader");
|
||||
|
|
|
@ -1,23 +1,74 @@
|
|||
/*
|
||||
* Load Analog Devices SigmaStudio firmware files
|
||||
*
|
||||
* Copyright 2009-2011 Analog Devices Inc.
|
||||
* Copyright 2009-2014 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <sound/control.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "sigmadsp.h"
|
||||
|
||||
#define SIGMA_MAGIC "ADISIGM"
|
||||
|
||||
#define SIGMA_FW_CHUNK_TYPE_DATA 0
|
||||
#define SIGMA_FW_CHUNK_TYPE_CONTROL 1
|
||||
#define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2
|
||||
|
||||
struct sigmadsp_control {
|
||||
struct list_head head;
|
||||
uint32_t samplerates;
|
||||
unsigned int addr;
|
||||
unsigned int num_bytes;
|
||||
const char *name;
|
||||
struct snd_kcontrol *kcontrol;
|
||||
bool cached;
|
||||
uint8_t cache[];
|
||||
};
|
||||
|
||||
struct sigmadsp_data {
|
||||
struct list_head head;
|
||||
uint32_t samplerates;
|
||||
unsigned int addr;
|
||||
unsigned int length;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
struct sigma_fw_chunk {
|
||||
__le32 length;
|
||||
__le32 tag;
|
||||
__le32 samplerates;
|
||||
} __packed;
|
||||
|
||||
struct sigma_fw_chunk_data {
|
||||
struct sigma_fw_chunk chunk;
|
||||
__le16 addr;
|
||||
uint8_t data[];
|
||||
} __packed;
|
||||
|
||||
struct sigma_fw_chunk_control {
|
||||
struct sigma_fw_chunk chunk;
|
||||
__le16 type;
|
||||
__le16 addr;
|
||||
__le16 num_bytes;
|
||||
const char name[];
|
||||
} __packed;
|
||||
|
||||
struct sigma_fw_chunk_samplerate {
|
||||
struct sigma_fw_chunk chunk;
|
||||
__le32 samplerates[];
|
||||
} __packed;
|
||||
|
||||
struct sigma_firmware_header {
|
||||
unsigned char magic[7];
|
||||
u8 version;
|
||||
|
@ -28,12 +79,286 @@ enum {
|
|||
SIGMA_ACTION_WRITEXBYTES = 0,
|
||||
SIGMA_ACTION_WRITESINGLE,
|
||||
SIGMA_ACTION_WRITESAFELOAD,
|
||||
SIGMA_ACTION_DELAY,
|
||||
SIGMA_ACTION_PLLWAIT,
|
||||
SIGMA_ACTION_NOOP,
|
||||
SIGMA_ACTION_END,
|
||||
};
|
||||
|
||||
struct sigma_action {
|
||||
u8 instr;
|
||||
u8 len_hi;
|
||||
__le16 len;
|
||||
__be16 addr;
|
||||
unsigned char payload[];
|
||||
} __packed;
|
||||
|
||||
static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr,
|
||||
const uint8_t data[], size_t len)
|
||||
{
|
||||
return sigmadsp->write(sigmadsp->control_data, addr, data, len);
|
||||
}
|
||||
|
||||
static int sigmadsp_read(struct sigmadsp *sigmadsp, unsigned int addr,
|
||||
uint8_t data[], size_t len)
|
||||
{
|
||||
return sigmadsp->read(sigmadsp->control_data, addr, data, len);
|
||||
}
|
||||
|
||||
static int sigmadsp_ctrl_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
|
||||
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_BYTES;
|
||||
info->count = ctrl->num_bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sigmadsp_ctrl_write(struct sigmadsp *sigmadsp,
|
||||
struct sigmadsp_control *ctrl, void *data)
|
||||
{
|
||||
/* safeload loads up to 20 bytes in a atomic operation */
|
||||
if (ctrl->num_bytes > 4 && ctrl->num_bytes <= 20 && sigmadsp->ops &&
|
||||
sigmadsp->ops->safeload)
|
||||
return sigmadsp->ops->safeload(sigmadsp, ctrl->addr, data,
|
||||
ctrl->num_bytes);
|
||||
else
|
||||
return sigmadsp_write(sigmadsp, ctrl->addr, data,
|
||||
ctrl->num_bytes);
|
||||
}
|
||||
|
||||
static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
|
||||
struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
|
||||
uint8_t *data;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&sigmadsp->lock);
|
||||
|
||||
data = ucontrol->value.bytes.data;
|
||||
|
||||
if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
|
||||
ret = sigmadsp_ctrl_write(sigmadsp, ctrl, data);
|
||||
|
||||
if (ret == 0) {
|
||||
memcpy(ctrl->cache, data, ctrl->num_bytes);
|
||||
ctrl->cached = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&sigmadsp->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
|
||||
struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&sigmadsp->lock);
|
||||
|
||||
if (!ctrl->cached) {
|
||||
ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache,
|
||||
ctrl->num_bytes);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ctrl->cached = true;
|
||||
memcpy(ucontrol->value.bytes.data, ctrl->cache,
|
||||
ctrl->num_bytes);
|
||||
}
|
||||
|
||||
mutex_unlock(&sigmadsp->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sigmadsp_control_free(struct snd_kcontrol *kcontrol)
|
||||
{
|
||||
struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
|
||||
|
||||
ctrl->kcontrol = NULL;
|
||||
}
|
||||
|
||||
static bool sigma_fw_validate_control_name(const char *name, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
/* Normal ASCII characters are valid */
|
||||
if (name[i] < ' ' || name[i] > '~')
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int sigma_fw_load_control(struct sigmadsp *sigmadsp,
|
||||
const struct sigma_fw_chunk *chunk, unsigned int length)
|
||||
{
|
||||
const struct sigma_fw_chunk_control *ctrl_chunk;
|
||||
struct sigmadsp_control *ctrl;
|
||||
unsigned int num_bytes;
|
||||
size_t name_len;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
if (length <= sizeof(*ctrl_chunk))
|
||||
return -EINVAL;
|
||||
|
||||
ctrl_chunk = (const struct sigma_fw_chunk_control *)chunk;
|
||||
|
||||
name_len = length - sizeof(*ctrl_chunk);
|
||||
if (name_len >= SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
|
||||
name_len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1;
|
||||
|
||||
/* Make sure there are no non-displayable characaters in the string */
|
||||
if (!sigma_fw_validate_control_name(ctrl_chunk->name, name_len))
|
||||
return -EINVAL;
|
||||
|
||||
num_bytes = le16_to_cpu(ctrl_chunk->num_bytes);
|
||||
ctrl = kzalloc(sizeof(*ctrl) + num_bytes, GFP_KERNEL);
|
||||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
name = kzalloc(name_len + 1, GFP_KERNEL);
|
||||
if (!name) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_ctrl;
|
||||
}
|
||||
memcpy(name, ctrl_chunk->name, name_len);
|
||||
name[name_len] = '\0';
|
||||
ctrl->name = name;
|
||||
|
||||
ctrl->addr = le16_to_cpu(ctrl_chunk->addr);
|
||||
ctrl->num_bytes = num_bytes;
|
||||
ctrl->samplerates = le32_to_cpu(chunk->samplerates);
|
||||
|
||||
list_add_tail(&ctrl->head, &sigmadsp->ctrl_list);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_ctrl:
|
||||
kfree(ctrl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sigma_fw_load_data(struct sigmadsp *sigmadsp,
|
||||
const struct sigma_fw_chunk *chunk, unsigned int length)
|
||||
{
|
||||
const struct sigma_fw_chunk_data *data_chunk;
|
||||
struct sigmadsp_data *data;
|
||||
|
||||
if (length <= sizeof(*data_chunk))
|
||||
return -EINVAL;
|
||||
|
||||
data_chunk = (struct sigma_fw_chunk_data *)chunk;
|
||||
|
||||
length -= sizeof(*data_chunk);
|
||||
|
||||
data = kzalloc(sizeof(*data) + length, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->addr = le16_to_cpu(data_chunk->addr);
|
||||
data->length = length;
|
||||
data->samplerates = le32_to_cpu(chunk->samplerates);
|
||||
memcpy(data->data, data_chunk->data, length);
|
||||
list_add_tail(&data->head, &sigmadsp->data_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sigma_fw_load_samplerates(struct sigmadsp *sigmadsp,
|
||||
const struct sigma_fw_chunk *chunk, unsigned int length)
|
||||
{
|
||||
const struct sigma_fw_chunk_samplerate *rate_chunk;
|
||||
unsigned int num_rates;
|
||||
unsigned int *rates;
|
||||
unsigned int i;
|
||||
|
||||
rate_chunk = (const struct sigma_fw_chunk_samplerate *)chunk;
|
||||
|
||||
num_rates = (length - sizeof(*rate_chunk)) / sizeof(__le32);
|
||||
|
||||
if (num_rates > 32 || num_rates == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* We only allow one samplerates block per file */
|
||||
if (sigmadsp->rate_constraints.count)
|
||||
return -EINVAL;
|
||||
|
||||
rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL);
|
||||
if (!rates)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_rates; i++)
|
||||
rates[i] = le32_to_cpu(rate_chunk->samplerates[i]);
|
||||
|
||||
sigmadsp->rate_constraints.count = num_rates;
|
||||
sigmadsp->rate_constraints.list = rates;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sigmadsp_fw_load_v2(struct sigmadsp *sigmadsp,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
struct sigma_fw_chunk *chunk;
|
||||
unsigned int length, pos;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Make sure that there is at least one chunk to avoid integer
|
||||
* underflows later on. Empty firmware is still valid though.
|
||||
*/
|
||||
if (fw->size < sizeof(*chunk) + sizeof(struct sigma_firmware_header))
|
||||
return 0;
|
||||
|
||||
pos = sizeof(struct sigma_firmware_header);
|
||||
|
||||
while (pos < fw->size - sizeof(*chunk)) {
|
||||
chunk = (struct sigma_fw_chunk *)(fw->data + pos);
|
||||
|
||||
length = le32_to_cpu(chunk->length);
|
||||
|
||||
if (length > fw->size - pos || length < sizeof(*chunk))
|
||||
return -EINVAL;
|
||||
|
||||
switch (le32_to_cpu(chunk->tag)) {
|
||||
case SIGMA_FW_CHUNK_TYPE_DATA:
|
||||
ret = sigma_fw_load_data(sigmadsp, chunk, length);
|
||||
break;
|
||||
case SIGMA_FW_CHUNK_TYPE_CONTROL:
|
||||
ret = sigma_fw_load_control(sigmadsp, chunk, length);
|
||||
break;
|
||||
case SIGMA_FW_CHUNK_TYPE_SAMPLERATES:
|
||||
ret = sigma_fw_load_samplerates(sigmadsp, chunk, length);
|
||||
break;
|
||||
default:
|
||||
dev_warn(sigmadsp->dev, "Unknown chunk type: %d\n",
|
||||
chunk->tag);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* This can not overflow since if length is larger than the
|
||||
* maximum firmware size (0x4000000) we'll error out earilier.
|
||||
*/
|
||||
pos += ALIGN(length, sizeof(__le32));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 sigma_action_len(struct sigma_action *sa)
|
||||
{
|
||||
return (sa->len_hi << 16) | le16_to_cpu(sa->len);
|
||||
|
@ -62,11 +387,11 @@ static size_t sigma_action_size(struct sigma_action *sa)
|
|||
* Returns a negative error value in case of an error, 0 if processing of
|
||||
* the firmware should be stopped after this action, 1 otherwise.
|
||||
*/
|
||||
static int
|
||||
process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
|
||||
static int process_sigma_action(struct sigmadsp *sigmadsp,
|
||||
struct sigma_action *sa)
|
||||
{
|
||||
size_t len = sigma_action_len(sa);
|
||||
int ret;
|
||||
struct sigmadsp_data *data;
|
||||
|
||||
pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
|
||||
sa->instr, sa->addr, len);
|
||||
|
@ -75,13 +400,17 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
|
|||
case SIGMA_ACTION_WRITEXBYTES:
|
||||
case SIGMA_ACTION_WRITESINGLE:
|
||||
case SIGMA_ACTION_WRITESAFELOAD:
|
||||
ret = ssfw->write(ssfw->control_data, sa, len);
|
||||
if (ret < 0)
|
||||
if (len < 3)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case SIGMA_ACTION_DELAY:
|
||||
udelay(len);
|
||||
len = 0;
|
||||
|
||||
data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->addr = be16_to_cpu(sa->addr);
|
||||
data->length = len - 2;
|
||||
memcpy(data->data, sa->payload, data->length);
|
||||
list_add_tail(&data->head, &sigmadsp->data_list);
|
||||
break;
|
||||
case SIGMA_ACTION_END:
|
||||
return 0;
|
||||
|
@ -92,22 +421,24 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
process_sigma_actions(struct sigma_firmware *ssfw)
|
||||
static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
struct sigma_action *sa;
|
||||
size_t size;
|
||||
size_t size, pos;
|
||||
int ret;
|
||||
|
||||
while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
|
||||
sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
|
||||
pos = sizeof(struct sigma_firmware_header);
|
||||
|
||||
while (pos + sizeof(*sa) <= fw->size) {
|
||||
sa = (struct sigma_action *)(fw->data + pos);
|
||||
|
||||
size = sigma_action_size(sa);
|
||||
ssfw->pos += size;
|
||||
if (ssfw->pos > ssfw->fw->size || size == 0)
|
||||
pos += size;
|
||||
if (pos > fw->size || size == 0)
|
||||
break;
|
||||
|
||||
ret = process_sigma_action(ssfw, sa);
|
||||
ret = process_sigma_action(sigmadsp, sa);
|
||||
|
||||
pr_debug("%s: action returned %i\n", __func__, ret);
|
||||
|
||||
|
@ -115,29 +446,47 @@ process_sigma_actions(struct sigma_firmware *ssfw)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (ssfw->pos != ssfw->fw->size)
|
||||
if (pos != fw->size)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _process_sigma_firmware(struct device *dev,
|
||||
struct sigma_firmware *ssfw, const char *name)
|
||||
static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp)
|
||||
{
|
||||
int ret;
|
||||
struct sigma_firmware_header *ssfw_head;
|
||||
struct sigmadsp_control *ctrl, *_ctrl;
|
||||
struct sigmadsp_data *data, *_data;
|
||||
|
||||
list_for_each_entry_safe(ctrl, _ctrl, &sigmadsp->ctrl_list, head) {
|
||||
kfree(ctrl->name);
|
||||
kfree(ctrl);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head)
|
||||
kfree(data);
|
||||
|
||||
INIT_LIST_HEAD(&sigmadsp->ctrl_list);
|
||||
INIT_LIST_HEAD(&sigmadsp->data_list);
|
||||
}
|
||||
|
||||
static void devm_sigmadsp_release(struct device *dev, void *res)
|
||||
{
|
||||
sigmadsp_firmware_release((struct sigmadsp *)res);
|
||||
}
|
||||
|
||||
static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
|
||||
{
|
||||
const struct sigma_firmware_header *ssfw_head;
|
||||
const struct firmware *fw;
|
||||
int ret;
|
||||
u32 crc;
|
||||
|
||||
pr_debug("%s: loading firmware %s\n", __func__, name);
|
||||
|
||||
/* first load the blob */
|
||||
ret = request_firmware(&fw, name, dev);
|
||||
ret = request_firmware(&fw, name, sigmadsp->dev);
|
||||
if (ret) {
|
||||
pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
|
||||
return ret;
|
||||
goto done;
|
||||
}
|
||||
ssfw->fw = fw;
|
||||
|
||||
/* then verify the header */
|
||||
ret = -EINVAL;
|
||||
|
@ -149,13 +498,13 @@ int _process_sigma_firmware(struct device *dev,
|
|||
* overflows later in the loading process.
|
||||
*/
|
||||
if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
|
||||
dev_err(dev, "Failed to load firmware: Invalid size\n");
|
||||
dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ssfw_head = (void *)fw->data;
|
||||
if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
|
||||
dev_err(dev, "Failed to load firmware: Invalid magic\n");
|
||||
dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -163,23 +512,303 @@ int _process_sigma_firmware(struct device *dev,
|
|||
fw->size - sizeof(*ssfw_head));
|
||||
pr_debug("%s: crc=%x\n", __func__, crc);
|
||||
if (crc != le32_to_cpu(ssfw_head->crc)) {
|
||||
dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
|
||||
dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
|
||||
le32_to_cpu(ssfw_head->crc), crc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ssfw->pos = sizeof(*ssfw_head);
|
||||
switch (ssfw_head->version) {
|
||||
case 1:
|
||||
ret = sigmadsp_fw_load_v1(sigmadsp, fw);
|
||||
break;
|
||||
case 2:
|
||||
ret = sigmadsp_fw_load_v2(sigmadsp, fw);
|
||||
break;
|
||||
default:
|
||||
dev_err(sigmadsp->dev,
|
||||
"Failed to load firmware: Invalid version %d. Supported firmware versions: 1, 2\n",
|
||||
ssfw_head->version);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* finally process all of the actions */
|
||||
ret = process_sigma_actions(ssfw);
|
||||
if (ret)
|
||||
sigmadsp_firmware_release(sigmadsp);
|
||||
|
||||
done:
|
||||
done:
|
||||
release_firmware(fw);
|
||||
|
||||
pr_debug("%s: loaded %s\n", __func__, name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(_process_sigma_firmware);
|
||||
|
||||
static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev,
|
||||
const struct sigmadsp_ops *ops, const char *firmware_name)
|
||||
{
|
||||
sigmadsp->ops = ops;
|
||||
sigmadsp->dev = dev;
|
||||
|
||||
INIT_LIST_HEAD(&sigmadsp->ctrl_list);
|
||||
INIT_LIST_HEAD(&sigmadsp->data_list);
|
||||
mutex_init(&sigmadsp->lock);
|
||||
|
||||
return sigmadsp_firmware_load(sigmadsp, firmware_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_sigmadsp_init() - Initialize SigmaDSP instance
|
||||
* @dev: The parent device
|
||||
* @ops: The sigmadsp_ops to use for this instance
|
||||
* @firmware_name: Name of the firmware file to load
|
||||
*
|
||||
* Allocates a SigmaDSP instance and loads the specified firmware file.
|
||||
*
|
||||
* Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
|
||||
*/
|
||||
struct sigmadsp *devm_sigmadsp_init(struct device *dev,
|
||||
const struct sigmadsp_ops *ops, const char *firmware_name)
|
||||
{
|
||||
struct sigmadsp *sigmadsp;
|
||||
int ret;
|
||||
|
||||
sigmadsp = devres_alloc(devm_sigmadsp_release, sizeof(*sigmadsp),
|
||||
GFP_KERNEL);
|
||||
if (!sigmadsp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = sigmadsp_init(sigmadsp, dev, ops, firmware_name);
|
||||
if (ret) {
|
||||
devres_free(sigmadsp);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
devres_add(dev, sigmadsp);
|
||||
|
||||
return sigmadsp;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_sigmadsp_init);
|
||||
|
||||
static int sigmadsp_rate_to_index(struct sigmadsp *sigmadsp, unsigned int rate)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sigmadsp->rate_constraints.count; i++) {
|
||||
if (sigmadsp->rate_constraints.list[i] == rate)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static unsigned int sigmadsp_get_samplerate_mask(struct sigmadsp *sigmadsp,
|
||||
unsigned int samplerate)
|
||||
{
|
||||
int samplerate_index;
|
||||
|
||||
if (samplerate == 0)
|
||||
return 0;
|
||||
|
||||
if (sigmadsp->rate_constraints.count) {
|
||||
samplerate_index = sigmadsp_rate_to_index(sigmadsp, samplerate);
|
||||
if (samplerate_index < 0)
|
||||
return 0;
|
||||
|
||||
return BIT(samplerate_index);
|
||||
} else {
|
||||
return ~0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool sigmadsp_samplerate_valid(unsigned int supported,
|
||||
unsigned int requested)
|
||||
{
|
||||
/* All samplerates are supported */
|
||||
if (!supported)
|
||||
return true;
|
||||
|
||||
return supported & requested;
|
||||
}
|
||||
|
||||
static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp,
|
||||
struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
|
||||
{
|
||||
struct snd_kcontrol_new template;
|
||||
struct snd_kcontrol *kcontrol;
|
||||
|
||||
memset(&template, 0, sizeof(template));
|
||||
template.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
template.name = ctrl->name;
|
||||
template.info = sigmadsp_ctrl_info;
|
||||
template.get = sigmadsp_ctrl_get;
|
||||
template.put = sigmadsp_ctrl_put;
|
||||
template.private_value = (unsigned long)ctrl;
|
||||
template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
if (!sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask))
|
||||
template.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
|
||||
kcontrol = snd_ctl_new1(&template, sigmadsp);
|
||||
if (!kcontrol)
|
||||
return -ENOMEM;
|
||||
|
||||
kcontrol->private_free = sigmadsp_control_free;
|
||||
ctrl->kcontrol = kcontrol;
|
||||
|
||||
return snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol);
|
||||
}
|
||||
|
||||
static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp,
|
||||
struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
|
||||
{
|
||||
struct snd_card *card = sigmadsp->component->card->snd_card;
|
||||
struct snd_kcontrol_volatile *vd;
|
||||
struct snd_ctl_elem_id id;
|
||||
bool active;
|
||||
bool changed = false;
|
||||
|
||||
active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask);
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
if (!ctrl->kcontrol) {
|
||||
up_write(&card->controls_rwsem);
|
||||
return;
|
||||
}
|
||||
|
||||
id = ctrl->kcontrol->id;
|
||||
vd = &ctrl->kcontrol->vd[0];
|
||||
if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) {
|
||||
vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
changed = true;
|
||||
}
|
||||
up_write(&card->controls_rwsem);
|
||||
|
||||
if (active && changed) {
|
||||
mutex_lock(&sigmadsp->lock);
|
||||
if (ctrl->cached)
|
||||
sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
|
||||
mutex_unlock(&sigmadsp->lock);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id);
|
||||
}
|
||||
|
||||
/**
|
||||
* sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component
|
||||
* @sigmadsp: The sigmadsp instance to attach
|
||||
* @component: The component to attach to
|
||||
*
|
||||
* Typically called in the components probe callback.
|
||||
*
|
||||
* Note, once this function has been called the firmware must not be released
|
||||
* until after the ALSA snd_card that the component belongs to has been
|
||||
* disconnected, even if sigmadsp_attach() returns an error.
|
||||
*/
|
||||
int sigmadsp_attach(struct sigmadsp *sigmadsp,
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
struct sigmadsp_control *ctrl;
|
||||
unsigned int samplerate_mask;
|
||||
int ret;
|
||||
|
||||
sigmadsp->component = component;
|
||||
|
||||
samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp,
|
||||
sigmadsp->current_samplerate);
|
||||
|
||||
list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) {
|
||||
ret = sigmadsp_alloc_control(sigmadsp, ctrl, samplerate_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sigmadsp_attach);
|
||||
|
||||
/**
|
||||
* sigmadsp_setup() - Setup the DSP for the specified samplerate
|
||||
* @sigmadsp: The sigmadsp instance to configure
|
||||
* @samplerate: The samplerate the DSP should be configured for
|
||||
*
|
||||
* Loads the appropriate firmware program and parameter memory (if not already
|
||||
* loaded) and enables the controls for the specified samplerate. Any control
|
||||
* parameter changes that have been made previously will be restored.
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate)
|
||||
{
|
||||
struct sigmadsp_control *ctrl;
|
||||
unsigned int samplerate_mask;
|
||||
struct sigmadsp_data *data;
|
||||
int ret;
|
||||
|
||||
if (sigmadsp->current_samplerate == samplerate)
|
||||
return 0;
|
||||
|
||||
samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, samplerate);
|
||||
if (samplerate_mask == 0)
|
||||
return -EINVAL;
|
||||
|
||||
list_for_each_entry(data, &sigmadsp->data_list, head) {
|
||||
if (!sigmadsp_samplerate_valid(data->samplerates,
|
||||
samplerate_mask))
|
||||
continue;
|
||||
ret = sigmadsp_write(sigmadsp, data->addr, data->data,
|
||||
data->length);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head)
|
||||
sigmadsp_activate_ctrl(sigmadsp, ctrl, samplerate_mask);
|
||||
|
||||
sigmadsp->current_samplerate = samplerate;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
sigmadsp_reset(sigmadsp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sigmadsp_setup);
|
||||
|
||||
/**
|
||||
* sigmadsp_reset() - Notify the sigmadsp instance that the DSP has been reset
|
||||
* @sigmadsp: The sigmadsp instance to reset
|
||||
*
|
||||
* Should be called whenever the DSP has been reset and parameter and program
|
||||
* memory need to be re-loaded.
|
||||
*/
|
||||
void sigmadsp_reset(struct sigmadsp *sigmadsp)
|
||||
{
|
||||
struct sigmadsp_control *ctrl;
|
||||
|
||||
list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head)
|
||||
sigmadsp_activate_ctrl(sigmadsp, ctrl, false);
|
||||
|
||||
sigmadsp->current_samplerate = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sigmadsp_reset);
|
||||
|
||||
/**
|
||||
* sigmadsp_restrict_params() - Applies DSP firmware specific constraints
|
||||
* @sigmadsp: The sigmadsp instance
|
||||
* @substream: The substream to restrict
|
||||
*
|
||||
* Applies samplerate constraints that may be required by the firmware Should
|
||||
* typically be called from the CODEC/component drivers startup callback.
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
if (sigmadsp->rate_constraints.count == 0)
|
||||
return 0;
|
||||
|
||||
return snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE, &sigmadsp->rate_constraints);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sigmadsp_restrict_params);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -11,31 +11,56 @@
|
|||
|
||||
#include <linux/device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
struct sigma_action {
|
||||
u8 instr;
|
||||
u8 len_hi;
|
||||
__le16 len;
|
||||
__be16 addr;
|
||||
unsigned char payload[];
|
||||
} __packed;
|
||||
#include <sound/pcm.h>
|
||||
|
||||
struct sigma_firmware {
|
||||
const struct firmware *fw;
|
||||
size_t pos;
|
||||
struct sigmadsp;
|
||||
struct snd_soc_component;
|
||||
struct snd_pcm_substream;
|
||||
|
||||
void *control_data;
|
||||
int (*write)(void *control_data, const struct sigma_action *sa,
|
||||
size_t len);
|
||||
struct sigmadsp_ops {
|
||||
int (*safeload)(struct sigmadsp *sigmadsp, unsigned int addr,
|
||||
const uint8_t *data, size_t len);
|
||||
};
|
||||
|
||||
int _process_sigma_firmware(struct device *dev,
|
||||
struct sigma_firmware *ssfw, const char *name);
|
||||
struct sigmadsp {
|
||||
const struct sigmadsp_ops *ops;
|
||||
|
||||
struct list_head ctrl_list;
|
||||
struct list_head data_list;
|
||||
|
||||
struct snd_pcm_hw_constraint_list rate_constraints;
|
||||
|
||||
unsigned int current_samplerate;
|
||||
struct snd_soc_component *component;
|
||||
struct device *dev;
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
void *control_data;
|
||||
int (*write)(void *, unsigned int, const uint8_t *, size_t);
|
||||
int (*read)(void *, unsigned int, uint8_t *, size_t);
|
||||
};
|
||||
|
||||
struct sigmadsp *devm_sigmadsp_init(struct device *dev,
|
||||
const struct sigmadsp_ops *ops, const char *firmware_name);
|
||||
void sigmadsp_reset(struct sigmadsp *sigmadsp);
|
||||
|
||||
int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
|
||||
struct snd_pcm_substream *substream);
|
||||
|
||||
struct i2c_client;
|
||||
|
||||
extern int process_sigma_firmware(struct i2c_client *client, const char *name);
|
||||
extern int process_sigma_firmware_regmap(struct device *dev,
|
||||
struct regmap *regmap, const char *name);
|
||||
struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
|
||||
struct regmap *regmap, const struct sigmadsp_ops *ops,
|
||||
const char *firmware_name);
|
||||
struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
|
||||
const struct sigmadsp_ops *ops, const char *firmware_name);
|
||||
|
||||
int sigmadsp_attach(struct sigmadsp *sigmadsp,
|
||||
struct snd_soc_component *component);
|
||||
int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate);
|
||||
void sigmadsp_reset(struct sigmadsp *sigmadsp);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -120,7 +120,8 @@ static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
|
|||
{
|
||||
#define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
|
||||
#define ATLAS6_CODEC_RESET_BITS (1 << 28)
|
||||
struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
enable_and_reset_codec(sirf_audio_codec->regmap,
|
||||
|
@ -142,7 +143,8 @@ static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
|
|||
{
|
||||
#define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
|
||||
#define PRIMA2_CODEC_RESET_BITS (1 << 26)
|
||||
struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
enable_and_reset_codec(sirf_audio_codec->regmap,
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче