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:
Mark Brown 2014-12-16 11:52:34 +00:00
Коммит c52e5698ef
244 изменённых файлов: 17509 добавлений и 5793 удалений

Просмотреть файл

@ -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 = <&reg_3p3v>;
VDDIO-supply = <&reg_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");

11
sound/soc/codecs/cs4271.h Normal file
Просмотреть файл

@ -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,

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше