mirror of https://gitee.com/openkylin/linux.git
Merge remote-tracking branch 'asoc/fix/ab8500' into asoc-linus
This commit is contained in:
commit
8b880f48ee
|
@ -0,0 +1,22 @@
|
|||
CS42L73 audio CODEC
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "cirrus,cs42l73"
|
||||
|
||||
- reg : the I2C address of the device for I2C
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset_gpio : a GPIO spec for the reset pin.
|
||||
- chgfreq : Charge Pump Frequency values 0x00-0x0F
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
codec: cs42l73@4a {
|
||||
compatible = "cirrus,cs42l73";
|
||||
reg = <0x4a>;
|
||||
reset_gpio = <&gpio 10 0>;
|
||||
chgfreq = <0x05>;
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
* Texas Instruments SoC audio setups with TLV320AIC3X Codec
|
||||
|
||||
Required properties:
|
||||
- compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx
|
||||
- ti,model : The user-visible name of this sound complex.
|
||||
- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
|
||||
- ti,mcasp-controller : The phandle of the McASP controller
|
||||
- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec
|
||||
- ti,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 for sources and
|
||||
sinks are the codec's pins, and the jacks on the board:
|
||||
|
||||
Board connectors:
|
||||
|
||||
* Headphone Jack
|
||||
* Line Out
|
||||
* Mic Jack
|
||||
* Line In
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "ti,da830-evm-audio";
|
||||
ti,model = "DA830 EVM";
|
||||
ti,audio-codec = <&tlv320aic3x>;
|
||||
ti,mcasp-controller = <&mcasp1>;
|
||||
ti,codec-clock-rate = <12000000>;
|
||||
ti,audio-routing =
|
||||
"Headphone Jack", "HPLOUT",
|
||||
"Headphone Jack", "HPROUT",
|
||||
"Line Out", "LLOUT",
|
||||
"Line Out", "RLOUT",
|
||||
"MIC3L", "Mic Bias 2V",
|
||||
"MIC3R", "Mic Bias 2V",
|
||||
"Mic Bias 2V", "Mic Jack",
|
||||
"LINE1L", "Line In",
|
||||
"LINE2L", "Line In",
|
||||
"LINE1R", "Line In",
|
||||
"LINE2R", "Line In";
|
||||
};
|
|
@ -4,17 +4,25 @@ Required properties:
|
|||
- compatible :
|
||||
"ti,dm646x-mcasp-audio" : for DM646x platforms
|
||||
"ti,da830-mcasp-audio" : for both DA830 & DA850 platforms
|
||||
"ti,omap2-mcasp-audio" : for OMAP2 platforms (TI81xx, AM33xx)
|
||||
|
||||
- reg : Should contain McASP registers offset and length
|
||||
- interrupts : Interrupt number for McASP
|
||||
- op-mode : I2S/DIT ops mode.
|
||||
- tdm-slots : Slots for TDM operation.
|
||||
- num-serializer : Serializers used by McASP.
|
||||
- serial-dir : A list of serializer pin mode. The list number should be equal
|
||||
to "num-serializer" parameter. Each entry is a number indication
|
||||
serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX)
|
||||
"ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, TI81xx)
|
||||
|
||||
- reg : Should contain reg specifiers for the entries in the reg-names property.
|
||||
- reg-names : Should contain:
|
||||
* "mpu" for the main registers (required). For compatibility with
|
||||
existing software, it is recommended this is the first entry.
|
||||
* "dat" for separate data port register access (optional).
|
||||
- op-mode : I2S/DIT ops mode. 0 for I2S mode. 1 for DIT mode used for S/PDIF,
|
||||
IEC60958-1, and AES-3 formats.
|
||||
- tdm-slots : Slots for TDM operation. Indicates number of channels transmitted
|
||||
or received over one serializer.
|
||||
- serial-dir : A list of serializer configuration. Each entry is a number
|
||||
indication for serializer pin direction.
|
||||
(0 - INACTIVE, 1 - TX, 2 - RX)
|
||||
- dmas: two element list of DMA controller phandles and DMA request line
|
||||
ordered pairs.
|
||||
- dma-names: identifier string for each DMA request line in the dmas property.
|
||||
These strings correspond 1:1 with the ordered pairs in dmas. The dma
|
||||
identifiers must be "rx" and "tx".
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
@ -23,18 +31,23 @@ 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
|
||||
- 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
|
||||
please refer to pinctrl-bindings.txt
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
mcasp0: mcasp0@1d00000 {
|
||||
compatible = "ti,da830-mcasp-audio";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x100000 0x3000>;
|
||||
interrupts = <82 83>;
|
||||
reg-names "mpu";
|
||||
interrupts = <82>, <83>;
|
||||
interrupts-names = "tx", "rx";
|
||||
op-mode = <0>; /* MCASP_IIS_MODE */
|
||||
tdm-slots = <2>;
|
||||
num-serializer = <16>;
|
||||
serial-dir = <
|
||||
0 0 0 0 /* 0: INACTIVE, 1: TX, 2: RX */
|
||||
0 0 0 0
|
||||
|
|
|
@ -24,10 +24,36 @@ Optional properties:
|
|||
3 - MICBIAS output is connected to AVDD,
|
||||
If this node is not mentioned or if the value is incorrect, then MicBias
|
||||
is powered down.
|
||||
- AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the
|
||||
device as covered in Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
CODEC output pins:
|
||||
* LLOUT
|
||||
* RLOUT
|
||||
* MONO_LOUT
|
||||
* HPLOUT
|
||||
* HPROUT
|
||||
* HPLCOM
|
||||
* HPRCOM
|
||||
|
||||
CODEC input pins:
|
||||
* MIC3L
|
||||
* MIC3R
|
||||
* LINE1L
|
||||
* LINE2L
|
||||
* LINE1R
|
||||
* LINE2R
|
||||
|
||||
The pins can be used in referring sound node's audio-routing property.
|
||||
|
||||
Example:
|
||||
|
||||
tlv320aic3x: tlv320aic3x@1b {
|
||||
compatible = "ti,tlv320aic3x";
|
||||
reg = <0x1b>;
|
||||
|
||||
AVDD-supply = <®ulator>;
|
||||
IOVDD-supply = <®ulator>;
|
||||
DRVDD-supply = <®ulator>;
|
||||
DVDD-supply = <®ulator>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
Texas Instruments - tpa6130a2 Codec module
|
||||
|
||||
The tpa6130a2 serial control bus communicates through I2C protocols
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible - "string" - One of:
|
||||
"ti,tpa6130a2" - TPA6130A2
|
||||
"ti,tpa6140a2" - TPA6140A2
|
||||
|
||||
|
||||
- reg - <int> - I2C slave address
|
||||
|
||||
- Vdd-supply - <phandle> - power supply regulator
|
||||
|
||||
Optional properties:
|
||||
|
||||
- power-gpio - gpio pin to power the device
|
||||
|
||||
Example:
|
||||
|
||||
tpa6130a2: tpa6130a2@60 {
|
||||
compatible = "ti,tpa6130a2";
|
||||
reg = <0x60>;
|
||||
Vdd-supply = <&vmmc2>;
|
||||
power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>;
|
||||
};
|
|
@ -0,0 +1,380 @@
|
|||
Dynamic PCM
|
||||
===========
|
||||
|
||||
1. Description
|
||||
==============
|
||||
|
||||
Dynamic PCM allows an ALSA PCM device to digitally route its PCM audio to
|
||||
various digital endpoints during the PCM stream runtime. e.g. PCM0 can route
|
||||
digital audio to I2S DAI0, I2S DAI1 or PDM DAI2. This is useful for on SoC DSP
|
||||
drivers that expose several ALSA PCMs and can route to multiple DAIs.
|
||||
|
||||
The DPCM runtime routing is determined by the ALSA mixer settings in the same
|
||||
way as the analog signal is routed in an ASoC codec driver. DPCM uses a DAPM
|
||||
graph representing the DSP internal audio paths and uses the mixer settings to
|
||||
determine the patch used by each ALSA PCM.
|
||||
|
||||
DPCM re-uses all the existing component codec, platform and DAI drivers without
|
||||
any modifications.
|
||||
|
||||
|
||||
Phone Audio System with SoC based DSP
|
||||
-------------------------------------
|
||||
|
||||
Consider the following phone audio subsystem. This will be used in this
|
||||
document for all examples :-
|
||||
|
||||
| Front End PCMs | SoC DSP | Back End DAIs | Audio devices |
|
||||
|
||||
*************
|
||||
PCM0 <------------> * * <----DAI0-----> Codec Headset
|
||||
* *
|
||||
PCM1 <------------> * * <----DAI1-----> Codec Speakers
|
||||
* DSP *
|
||||
PCM2 <------------> * * <----DAI2-----> MODEM
|
||||
* *
|
||||
PCM3 <------------> * * <----DAI3-----> BT
|
||||
* *
|
||||
* * <----DAI4-----> DMIC
|
||||
* *
|
||||
* * <----DAI5-----> FM
|
||||
*************
|
||||
|
||||
This diagram shows a simple smart phone audio subsystem. It supports Bluetooth,
|
||||
FM digital radio, Speakers, Headset Jack, digital microphones and cellular
|
||||
modem. This sound card exposes 4 DSP front end (FE) ALSA PCM devices and
|
||||
supports 6 back end (BE) DAIs. Each FE PCM can digitally route audio data to any
|
||||
of the BE DAIs. The FE PCM devices can also route audio to more than 1 BE DAI.
|
||||
|
||||
|
||||
|
||||
Example - DPCM Switching playback from DAI0 to DAI1
|
||||
---------------------------------------------------
|
||||
|
||||
Audio is being played to the Headset. After a while the user removes the headset
|
||||
and audio continues playing on the speakers.
|
||||
|
||||
Playback on PCM0 to Headset would look like :-
|
||||
|
||||
*************
|
||||
PCM0 <============> * * <====DAI0=====> Codec Headset
|
||||
* *
|
||||
PCM1 <------------> * * <----DAI1-----> Codec Speakers
|
||||
* DSP *
|
||||
PCM2 <------------> * * <----DAI2-----> MODEM
|
||||
* *
|
||||
PCM3 <------------> * * <----DAI3-----> BT
|
||||
* *
|
||||
* * <----DAI4-----> DMIC
|
||||
* *
|
||||
* * <----DAI5-----> FM
|
||||
*************
|
||||
|
||||
The headset is removed from the jack by user so the speakers must now be used :-
|
||||
|
||||
*************
|
||||
PCM0 <============> * * <----DAI0-----> Codec Headset
|
||||
* *
|
||||
PCM1 <------------> * * <====DAI1=====> Codec Speakers
|
||||
* DSP *
|
||||
PCM2 <------------> * * <----DAI2-----> MODEM
|
||||
* *
|
||||
PCM3 <------------> * * <----DAI3-----> BT
|
||||
* *
|
||||
* * <----DAI4-----> DMIC
|
||||
* *
|
||||
* * <----DAI5-----> FM
|
||||
*************
|
||||
|
||||
The audio driver processes this as follows :-
|
||||
|
||||
1) Machine driver receives Jack removal event.
|
||||
|
||||
2) Machine driver OR audio HAL disables the Headset path.
|
||||
|
||||
3) DPCM runs the PCM trigger(stop), hw_free(), shutdown() operations on DAI0
|
||||
for headset since the path is now disabled.
|
||||
|
||||
4) Machine driver or audio HAL enables the speaker path.
|
||||
|
||||
5) DPCM runs the PCM ops for startup(), hw_params(), prepapre() and
|
||||
trigger(start) for DAI1 Speakers since the path is enabled.
|
||||
|
||||
In this example, the machine driver or userspace audio HAL can alter the routing
|
||||
and then DPCM will take care of managing the DAI PCM operations to either bring
|
||||
the link up or down. Audio playback does not stop during this transition.
|
||||
|
||||
|
||||
|
||||
DPCM machine driver
|
||||
===================
|
||||
|
||||
The DPCM enabled ASoC machine driver is similar to normal machine drivers
|
||||
except that we also have to :-
|
||||
|
||||
1) Define the FE and BE DAI links.
|
||||
|
||||
2) Define any FE/BE PCM operations.
|
||||
|
||||
3) Define widget graph connections.
|
||||
|
||||
|
||||
1 FE and BE DAI links
|
||||
---------------------
|
||||
|
||||
| Front End PCMs | SoC DSP | Back End DAIs | Audio devices |
|
||||
|
||||
*************
|
||||
PCM0 <------------> * * <----DAI0-----> Codec Headset
|
||||
* *
|
||||
PCM1 <------------> * * <----DAI1-----> Codec Speakers
|
||||
* DSP *
|
||||
PCM2 <------------> * * <----DAI2-----> MODEM
|
||||
* *
|
||||
PCM3 <------------> * * <----DAI3-----> BT
|
||||
* *
|
||||
* * <----DAI4-----> DMIC
|
||||
* *
|
||||
* * <----DAI5-----> FM
|
||||
*************
|
||||
|
||||
For the example above we have to define 4 FE DAI links and 6 BE DAI links. The
|
||||
FE DAI links are defined as follows :-
|
||||
|
||||
static struct snd_soc_dai_link machine_dais[] = {
|
||||
{
|
||||
.name = "PCM0 System",
|
||||
.stream_name = "System Playback",
|
||||
.cpu_dai_name = "System Pin",
|
||||
.platform_name = "dsp-audio",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.dynamic = 1,
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_playback = 1,
|
||||
},
|
||||
.....< other FE and BE DAI links here >
|
||||
};
|
||||
|
||||
This FE DAI link is pretty similar to a regular DAI link except that we also
|
||||
set the DAI link to a DPCM FE with the "dynamic = 1". The supported FE stream
|
||||
directions should also be set with the "dpcm_playback" and "dpcm_capture"
|
||||
flags. There is also an option to specify the ordering of the trigger call for
|
||||
each FE. This allows the ASoC core to trigger the DSP before or after the other
|
||||
components (as some DSPs have strong requirements for the ordering DAI/DSP
|
||||
start and stop sequences).
|
||||
|
||||
The FE DAI above sets the codec and code DAIs to dummy devices since the BE is
|
||||
dynamic and will change depending on runtime config.
|
||||
|
||||
The BE DAIs are configured as follows :-
|
||||
|
||||
static struct snd_soc_dai_link machine_dais[] = {
|
||||
.....< FE DAI links here >
|
||||
{
|
||||
.name = "Codec Headset",
|
||||
.cpu_dai_name = "ssp-dai.0",
|
||||
.platform_name = "snd-soc-dummy",
|
||||
.no_pcm = 1,
|
||||
.codec_name = "rt5640.0-001c",
|
||||
.codec_dai_name = "rt5640-aif1",
|
||||
.ignore_suspend = 1,
|
||||
.ignore_pmdown_time = 1,
|
||||
.be_hw_params_fixup = hswult_ssp0_fixup,
|
||||
.ops = &haswell_ops,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
.....< other BE DAI links here >
|
||||
};
|
||||
|
||||
This BE DAI link connects DAI0 to the codec (in this case RT5460 AIF1). It sets
|
||||
the "no_pcm" flag to mark it has a BE and sets flags for supported stream
|
||||
directions using "dpcm_playback" and "dpcm_capture" above.
|
||||
|
||||
The BE has also flags set for ignoreing suspend and PM down time. This allows
|
||||
the BE to work in a hostless mode where the host CPU is not transferring data
|
||||
like a BT phone call :-
|
||||
|
||||
*************
|
||||
PCM0 <------------> * * <----DAI0-----> Codec Headset
|
||||
* *
|
||||
PCM1 <------------> * * <----DAI1-----> Codec Speakers
|
||||
* DSP *
|
||||
PCM2 <------------> * * <====DAI2=====> MODEM
|
||||
* *
|
||||
PCM3 <------------> * * <====DAI3=====> BT
|
||||
* *
|
||||
* * <----DAI4-----> DMIC
|
||||
* *
|
||||
* * <----DAI5-----> FM
|
||||
*************
|
||||
|
||||
This allows the host CPU to sleep whilst the DSP, MODEM DAI and the BT DAI are
|
||||
still in operation.
|
||||
|
||||
A BE DAI link can also set the codec to a dummy device if the code is a device
|
||||
that is managed externally.
|
||||
|
||||
Likewise a BE DAI can also set a dummy cpu DAI if the CPU DAI is managed by the
|
||||
DSP firmware.
|
||||
|
||||
|
||||
2 FE/BE PCM operations
|
||||
----------------------
|
||||
|
||||
The BE above also exports some PCM operations and a "fixup" callback. The fixup
|
||||
callback is used by the machine driver to (re)configure the DAI based upon the
|
||||
FE hw params. i.e. the DSP may perform SRC or ASRC from the FE to BE.
|
||||
|
||||
e.g. DSP converts all FE hw params to run at fixed rate of 48k, 16bit, stereo for
|
||||
DAI0. This means all FE hw_params have to be fixed in the machine driver for
|
||||
DAI0 so that the DAI is running at desired configuration regardless of the FE
|
||||
configuration.
|
||||
|
||||
static int dai0_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_interval *rate = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_RATE);
|
||||
struct snd_interval *channels = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||
|
||||
/* The DSP will covert the FE rate to 48k, stereo */
|
||||
rate->min = rate->max = 48000;
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set DAI0 to 16 bit */
|
||||
snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT -
|
||||
SNDRV_PCM_HW_PARAM_FIRST_MASK],
|
||||
SNDRV_PCM_FORMAT_S16_LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
The other PCM operation are the same as for regular DAI links. Use as necessary.
|
||||
|
||||
|
||||
3 Widget graph connections
|
||||
--------------------------
|
||||
|
||||
The BE DAI links will normally be connected to the graph at initialisation time
|
||||
by the ASoC DAPM core. However, if the BE codec or BE DAI is a dummy then this
|
||||
has to be set explicitly in the driver :-
|
||||
|
||||
/* BE for codec Headset - DAI0 is dummy and managed by DSP FW */
|
||||
{"DAI0 CODEC IN", NULL, "AIF1 Capture"},
|
||||
{"AIF1 Playback", NULL, "DAI0 CODEC OUT"},
|
||||
|
||||
|
||||
Writing a DPCM DSP driver
|
||||
=========================
|
||||
|
||||
The DPCM DSP driver looks much like a standard platform class ASoC driver
|
||||
combined with elements from a codec class driver. A DSP platform driver must
|
||||
implement :-
|
||||
|
||||
1) Front End PCM DAIs - i.e. struct snd_soc_dai_driver.
|
||||
|
||||
2) DAPM graph showing DSP audio routing from FE DAIs to BEs.
|
||||
|
||||
3) DAPM widgets from DSP graph.
|
||||
|
||||
4) Mixers for gains, routing, etc.
|
||||
|
||||
5) DMA configuration.
|
||||
|
||||
6) BE AIF widgets.
|
||||
|
||||
Items 6 is important for routing the audio outside of the DSP. AIF need to be
|
||||
defined for each BE and each stream direction. e.g for BE DAI0 above we would
|
||||
have :-
|
||||
|
||||
SND_SOC_DAPM_AIF_IN("DAI0 RX", NULL, 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("DAI0 TX", NULL, 0, SND_SOC_NOPM, 0, 0),
|
||||
|
||||
The BE AIF are used to connect the DSP graph to the graphs for the other
|
||||
component drivers (e.g. codec graph).
|
||||
|
||||
|
||||
Hostless PCM streams
|
||||
====================
|
||||
|
||||
A hostless PCM stream is a stream that is not routed through the host CPU. An
|
||||
example of this would be a phone call from handset to modem.
|
||||
|
||||
|
||||
*************
|
||||
PCM0 <------------> * * <----DAI0-----> Codec Headset
|
||||
* *
|
||||
PCM1 <------------> * * <====DAI1=====> Codec Speakers/Mic
|
||||
* DSP *
|
||||
PCM2 <------------> * * <====DAI2=====> MODEM
|
||||
* *
|
||||
PCM3 <------------> * * <----DAI3-----> BT
|
||||
* *
|
||||
* * <----DAI4-----> DMIC
|
||||
* *
|
||||
* * <----DAI5-----> FM
|
||||
*************
|
||||
|
||||
In this case the PCM data is routed via the DSP. The host CPU in this use case
|
||||
is only used for control and can sleep during the runtime of the stream.
|
||||
|
||||
The host can control the hostless link either by :-
|
||||
|
||||
1) Configuring the link as a CODEC <-> CODEC style link. In this case the link
|
||||
is enabled or disabled by the state of the DAPM graph. This usually means
|
||||
there is a mixer control that can be used to connect or disconnect the path
|
||||
between both DAIs.
|
||||
|
||||
2) Hostless FE. This FE has a virtual connection to the BE DAI links on the DAPM
|
||||
graph. Control is then carried out by the FE as regualar PCM operations.
|
||||
This method gives more control over the DAI links, but requires much more
|
||||
userspace code to control the link. Its recommended to use CODEC<->CODEC
|
||||
unless your HW needs more fine grained sequencing of the PCM ops.
|
||||
|
||||
|
||||
CODEC <-> CODEC link
|
||||
--------------------
|
||||
|
||||
This DAI link is enabled when DAPM detects a valid path within the DAPM graph.
|
||||
The machine driver sets some additional parameters to the DAI link i.e.
|
||||
|
||||
static const struct snd_soc_pcm_stream dai_params = {
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 8000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link dais[] = {
|
||||
< ... more DAI links above ... >
|
||||
{
|
||||
.name = "MODEM",
|
||||
.stream_name = "MODEM",
|
||||
.cpu_dai_name = "dai2",
|
||||
.codec_dai_name = "modem-aif1",
|
||||
.codec_name = "modem",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBM_CFM,
|
||||
.params = &dai_params,
|
||||
}
|
||||
< ... more DAI links here ... >
|
||||
|
||||
These parameters are used to configure the DAI hw_params() when DAPM detects a
|
||||
valid path and then calls the PCM operations to start the link. DAPM will also
|
||||
call the appropriate PCM operations to disable the DAI when the path is no
|
||||
longer valid.
|
||||
|
||||
|
||||
Hostless FE
|
||||
-----------
|
||||
|
||||
The DAI link(s) are enabled by a FE that does not read or write any PCM data.
|
||||
This means creating a new FE that is connected with a virtual path to both
|
||||
DAI links. The DAI links will be started when the FE PCM is started and stopped
|
||||
when the FE PCM is stopped. Note that the FE PCM cannot read or write data in
|
||||
this configuration.
|
||||
|
||||
|
|
@ -1,22 +1,23 @@
|
|||
ASoC Codec Driver
|
||||
=================
|
||||
ASoC Codec Class Driver
|
||||
=======================
|
||||
|
||||
The codec driver is generic and hardware independent code that configures the
|
||||
codec to provide audio capture and playback. It should contain no code that is
|
||||
specific to the target platform or machine. All platform and machine specific
|
||||
code should be added to the platform and machine drivers respectively.
|
||||
The codec class driver is generic and hardware independent code that configures
|
||||
the codec, FM, MODEM, BT or external DSP to provide audio capture and playback.
|
||||
It should contain no code that is specific to the target platform or machine.
|
||||
All platform and machine specific code should be added to the platform and
|
||||
machine drivers respectively.
|
||||
|
||||
Each codec driver *must* provide the following features:-
|
||||
Each codec class driver *must* provide the following features:-
|
||||
|
||||
1) Codec DAI and PCM configuration
|
||||
2) Codec control IO - using I2C, 3 Wire(SPI) or both APIs
|
||||
2) Codec control IO - using RegMap API
|
||||
3) Mixers and audio controls
|
||||
4) Codec audio operations
|
||||
5) DAPM description.
|
||||
6) DAPM event handler.
|
||||
|
||||
Optionally, codec drivers can also provide:-
|
||||
|
||||
5) DAPM description.
|
||||
6) DAPM event handler.
|
||||
7) DAC Digital mute control.
|
||||
|
||||
Its probably best to use this guide in conjunction with the existing codec
|
||||
|
@ -64,26 +65,9 @@ struct snd_soc_dai_driver wm8731_dai = {
|
|||
2 - Codec control IO
|
||||
--------------------
|
||||
The codec can usually be controlled via an I2C or SPI style interface
|
||||
(AC97 combines control with data in the DAI). The codec drivers provide
|
||||
functions to read and write the codec registers along with supplying a
|
||||
register cache:-
|
||||
|
||||
/* IO control data and register cache */
|
||||
void *control_data; /* codec control (i2c/3wire) data */
|
||||
void *reg_cache;
|
||||
|
||||
Codec read/write should do any data formatting and call the hardware
|
||||
read write below to perform the IO. These functions are called by the
|
||||
core and ALSA when performing DAPM or changing the mixer:-
|
||||
|
||||
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
|
||||
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
|
||||
|
||||
Codec hardware IO functions - usually points to either the I2C, SPI or AC97
|
||||
read/write:-
|
||||
|
||||
hw_write_t hw_write;
|
||||
hw_read_t hw_read;
|
||||
(AC97 combines control with data in the DAI). The codec driver should use the
|
||||
Regmap API for all codec IO. Please see include/linux/regmap.h and existing
|
||||
codec drivers for example regmap usage.
|
||||
|
||||
|
||||
3 - Mixers and audio controls
|
||||
|
@ -127,7 +111,7 @@ Defines a stereo enumerated control
|
|||
|
||||
4 - Codec Audio Operations
|
||||
--------------------------
|
||||
The codec driver also supports the following ALSA operations:-
|
||||
The codec driver also supports the following ALSA PCM operations:-
|
||||
|
||||
/* SoC audio ops */
|
||||
struct snd_soc_ops {
|
||||
|
|
|
@ -21,7 +21,7 @@ level power systems.
|
|||
|
||||
There are 4 power domains within DAPM
|
||||
|
||||
1. Codec domain - VREF, VMID (core codec and audio power)
|
||||
1. Codec bias domain - VREF, VMID (core codec and audio power)
|
||||
Usually controlled at codec probe/remove and suspend/resume, although
|
||||
can be set at stream time if power is not needed for sidetone, etc.
|
||||
|
||||
|
@ -63,14 +63,22 @@ Audio DAPM widgets fall into a number of types:-
|
|||
o Line - Line Input/Output (and optional Jack)
|
||||
o Speaker - Speaker
|
||||
o Supply - Power or clock supply widget used by other widgets.
|
||||
o Regulator - External regulator that supplies power to audio components.
|
||||
o Clock - External clock that supplies clock to audio componnents.
|
||||
o AIF IN - Audio Interface Input (with TDM slot mask).
|
||||
o AIF OUT - Audio Interface Output (with TDM slot mask).
|
||||
o Siggen - Signal Generator.
|
||||
o DAI IN - Digital Audio Interface Input.
|
||||
o DAI OUT - Digital Audio Interface Output.
|
||||
o DAI Link - DAI Link between two DAI structures */
|
||||
o Pre - Special PRE widget (exec before all others)
|
||||
o Post - Special POST widget (exec after all others)
|
||||
|
||||
(Widgets are defined in include/sound/soc-dapm.h)
|
||||
|
||||
Widgets are usually added in the codec driver and the machine driver. There are
|
||||
convenience macros defined in soc-dapm.h that can be used to quickly build a
|
||||
list of widgets of the codecs and machines DAPM widgets.
|
||||
Widgets can be added to the sound card by any of the component driver types.
|
||||
There are convenience macros defined in soc-dapm.h that can be used to quickly
|
||||
build a list of widgets of the codecs and machines DAPM widgets.
|
||||
|
||||
Most widgets have a name, register, shift and invert. Some widgets have extra
|
||||
parameters for stream name and kcontrols.
|
||||
|
@ -80,11 +88,13 @@ parameters for stream name and kcontrols.
|
|||
-------------------------
|
||||
|
||||
Stream Widgets relate to the stream power domain and only consist of ADCs
|
||||
(analog to digital converters) and DACs (digital to analog converters).
|
||||
(analog to digital converters), DACs (digital to analog converters),
|
||||
AIF IN and AIF OUT.
|
||||
|
||||
Stream widgets have the following format:-
|
||||
|
||||
SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
|
||||
SND_SOC_DAPM_AIF_IN(name, stream, slot, reg, shift, invert)
|
||||
|
||||
NOTE: the stream name must match the corresponding stream name in your codec
|
||||
snd_soc_codec_dai.
|
||||
|
@ -94,6 +104,11 @@ e.g. stream widgets for HiFi playback and capture
|
|||
SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1),
|
||||
SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1),
|
||||
|
||||
e.g. stream widgets for AIF
|
||||
|
||||
SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
|
||||
|
||||
|
||||
2.2 Path Domain Widgets
|
||||
-----------------------
|
||||
|
@ -121,12 +136,14 @@ If you dont want the mixer elements prefixed with the name of the mixer widget,
|
|||
you can use SND_SOC_DAPM_MIXER_NAMED_CTL instead. the parameters are the same
|
||||
as for SND_SOC_DAPM_MIXER.
|
||||
|
||||
2.3 Platform/Machine domain Widgets
|
||||
-----------------------------------
|
||||
|
||||
2.3 Machine domain Widgets
|
||||
--------------------------
|
||||
|
||||
Machine widgets are different from codec widgets in that they don't have a
|
||||
codec register bit associated with them. A machine widget is assigned to each
|
||||
machine audio component (non codec) that can be independently powered. e.g.
|
||||
machine audio component (non codec or DSP) that can be independently
|
||||
powered. e.g.
|
||||
|
||||
o Speaker Amp
|
||||
o Microphone Bias
|
||||
|
@ -146,12 +163,12 @@ static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event)
|
|||
SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
|
||||
|
||||
|
||||
2.4 Codec Domain
|
||||
----------------
|
||||
2.4 Codec (BIAS) Domain
|
||||
-----------------------
|
||||
|
||||
The codec power domain has no widgets and is handled by the codecs DAPM event
|
||||
handler. This handler is called when the codec powerstate is changed wrt to any
|
||||
stream event or by kernel PM events.
|
||||
The codec bias power domain has no widgets and is handled by the codecs DAPM
|
||||
event handler. This handler is called when the codec powerstate is changed wrt
|
||||
to any stream event or by kernel PM events.
|
||||
|
||||
|
||||
2.5 Virtual Widgets
|
||||
|
@ -169,15 +186,16 @@ After all the widgets have been defined, they can then be added to the DAPM
|
|||
subsystem individually with a call to snd_soc_dapm_new_control().
|
||||
|
||||
|
||||
3. Codec Widget Interconnections
|
||||
================================
|
||||
3. Codec/DSP Widget Interconnections
|
||||
====================================
|
||||
|
||||
Widgets are connected to each other within the codec and machine by audio paths
|
||||
(called interconnections). Each interconnection must be defined in order to
|
||||
create a map of all audio paths between widgets.
|
||||
Widgets are connected to each other within the codec, platform and machine by
|
||||
audio paths (called interconnections). Each interconnection must be defined in
|
||||
order to create a map of all audio paths between widgets.
|
||||
|
||||
This is easiest with a diagram of the codec (and schematic of the machine audio
|
||||
system), as it requires joining widgets together via their audio signal paths.
|
||||
This is easiest with a diagram of the codec or DSP (and schematic of the machine
|
||||
audio system), as it requires joining widgets together via their audio signal
|
||||
paths.
|
||||
|
||||
e.g., from the WM8731 output mixer (wm8731.c)
|
||||
|
||||
|
@ -247,16 +265,9 @@ machine and includes the codec. e.g.
|
|||
o Mic Jack
|
||||
o Codec Pins
|
||||
|
||||
When a codec pin is NC it can be marked as not used with a call to
|
||||
|
||||
snd_soc_dapm_set_endpoint(codec, "Widget Name", 0);
|
||||
|
||||
The last argument is 0 for inactive and 1 for active. This way the pin and its
|
||||
input widget will never be powered up and consume power.
|
||||
|
||||
This also applies to machine widgets. e.g. if a headphone is connected to a
|
||||
jack then the jack can be marked active. If the headphone is removed, then
|
||||
the headphone jack can be marked inactive.
|
||||
Endpoints are added to the DAPM graph so that their usage can be determined in
|
||||
order to save power. e.g. NC codecs pins will be switched OFF, unconnected
|
||||
jacks can also be switched OFF.
|
||||
|
||||
|
||||
5 DAPM Widget Events
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
ASoC Machine Driver
|
||||
===================
|
||||
|
||||
The ASoC machine (or board) driver is the code that glues together the platform
|
||||
and codec drivers.
|
||||
The ASoC machine (or board) driver is the code that glues together all the
|
||||
component drivers (e.g. codecs, platforms and DAIs). It also describes the
|
||||
relationships between each componnent which include audio paths, GPIOs,
|
||||
interrupts, clocking, jacks and voltage regulators.
|
||||
|
||||
The machine driver can contain codec and platform specific code. It registers
|
||||
the audio subsystem with the kernel as a platform device and is represented by
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
ASoC Platform Driver
|
||||
====================
|
||||
|
||||
An ASoC platform driver can be divided into audio DMA and SoC DAI configuration
|
||||
and control. The platform drivers only target the SoC CPU and must have no board
|
||||
specific code.
|
||||
An ASoC platform driver class can be divided into audio DMA drivers, SoC DAI
|
||||
drivers and DSP drivers. The platform drivers only target the SoC CPU and must
|
||||
have no board specific code.
|
||||
|
||||
Audio DMA
|
||||
=========
|
||||
|
@ -64,3 +64,16 @@ Each SoC DAI driver must provide the following features:-
|
|||
5) Suspend and resume (optional)
|
||||
|
||||
Please see codec.txt for a description of items 1 - 4.
|
||||
|
||||
|
||||
SoC DSP Drivers
|
||||
===============
|
||||
|
||||
Each SoC DSP driver usually supplies the following features :-
|
||||
|
||||
1) DAPM graph
|
||||
2) Mixer controls
|
||||
3) DMA IO to/from DSP buffers (if applicable)
|
||||
4) Definition of DSP front end (FE) PCM devices.
|
||||
|
||||
Please see DPCM.txt for a description of item 4.
|
||||
|
|
|
@ -44,7 +44,6 @@ struct regmap_format {
|
|||
|
||||
struct regmap_async {
|
||||
struct list_head list;
|
||||
struct work_struct cleanup;
|
||||
struct regmap *map;
|
||||
void *work_buf;
|
||||
};
|
||||
|
@ -64,9 +63,11 @@ struct regmap {
|
|||
void *bus_context;
|
||||
const char *name;
|
||||
|
||||
bool async;
|
||||
spinlock_t async_lock;
|
||||
wait_queue_head_t async_waitq;
|
||||
struct list_head async_list;
|
||||
struct list_head async_free;
|
||||
int async_ret;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
@ -179,6 +180,9 @@ struct regmap_field {
|
|||
/* lsb */
|
||||
unsigned int shift;
|
||||
unsigned int reg;
|
||||
|
||||
unsigned int id_size;
|
||||
unsigned int id_offset;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
@ -218,7 +222,7 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
|
|||
int regcache_lookup_reg(struct regmap *map, unsigned int reg);
|
||||
|
||||
int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
||||
const void *val, size_t val_len, bool async);
|
||||
const void *val, size_t val_len);
|
||||
|
||||
void regmap_async_complete_cb(struct regmap_async *async, int ret);
|
||||
|
||||
|
|
|
@ -631,8 +631,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
|
|||
|
||||
map->cache_bypass = 1;
|
||||
|
||||
ret = _regmap_raw_write(map, base, *data, count * val_bytes,
|
||||
false);
|
||||
ret = _regmap_raw_write(map, base, *data, count * val_bytes);
|
||||
|
||||
map->cache_bypass = 0;
|
||||
|
||||
|
|
|
@ -42,15 +42,6 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
|
|||
static int _regmap_bus_raw_write(void *context, unsigned int reg,
|
||||
unsigned int val);
|
||||
|
||||
static void async_cleanup(struct work_struct *work)
|
||||
{
|
||||
struct regmap_async *async = container_of(work, struct regmap_async,
|
||||
cleanup);
|
||||
|
||||
kfree(async->work_buf);
|
||||
kfree(async);
|
||||
}
|
||||
|
||||
bool regmap_reg_in_ranges(unsigned int reg,
|
||||
const struct regmap_range *ranges,
|
||||
unsigned int nranges)
|
||||
|
@ -465,6 +456,7 @@ struct regmap *regmap_init(struct device *dev,
|
|||
|
||||
spin_lock_init(&map->async_lock);
|
||||
INIT_LIST_HEAD(&map->async_list);
|
||||
INIT_LIST_HEAD(&map->async_free);
|
||||
init_waitqueue_head(&map->async_waitq);
|
||||
|
||||
if (config->read_flag_mask || config->write_flag_mask) {
|
||||
|
@ -821,6 +813,8 @@ static void regmap_field_init(struct regmap_field *rm_field,
|
|||
rm_field->reg = reg_field.reg;
|
||||
rm_field->shift = reg_field.lsb;
|
||||
rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb);
|
||||
rm_field->id_size = reg_field.id_size;
|
||||
rm_field->id_offset = reg_field.id_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -942,12 +936,22 @@ EXPORT_SYMBOL_GPL(regmap_reinit_cache);
|
|||
*/
|
||||
void regmap_exit(struct regmap *map)
|
||||
{
|
||||
struct regmap_async *async;
|
||||
|
||||
regcache_exit(map);
|
||||
regmap_debugfs_exit(map);
|
||||
regmap_range_exit(map);
|
||||
if (map->bus && map->bus->free_context)
|
||||
map->bus->free_context(map->bus_context);
|
||||
kfree(map->work_buf);
|
||||
while (!list_empty(&map->async_free)) {
|
||||
async = list_first_entry_or_null(&map->async_free,
|
||||
struct regmap_async,
|
||||
list);
|
||||
list_del(&async->list);
|
||||
kfree(async->work_buf);
|
||||
kfree(async);
|
||||
}
|
||||
kfree(map);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_exit);
|
||||
|
@ -1039,7 +1043,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
|
|||
}
|
||||
|
||||
int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
||||
const void *val, size_t val_len, bool async)
|
||||
const void *val, size_t val_len)
|
||||
{
|
||||
struct regmap_range_node *range;
|
||||
unsigned long flags;
|
||||
|
@ -1091,7 +1095,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
|||
dev_dbg(map->dev, "Writing window %d/%zu\n",
|
||||
win_residue, val_len / map->format.val_bytes);
|
||||
ret = _regmap_raw_write(map, reg, val, win_residue *
|
||||
map->format.val_bytes, async);
|
||||
map->format.val_bytes);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
|
@ -1114,21 +1118,42 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
|||
|
||||
u8[0] |= map->write_flag_mask;
|
||||
|
||||
if (async && map->bus->async_write) {
|
||||
struct regmap_async *async = map->bus->async_alloc();
|
||||
if (!async)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* Essentially all I/O mechanisms will be faster with a single
|
||||
* buffer to write. Since register syncs often generate raw
|
||||
* writes of single registers optimise that case.
|
||||
*/
|
||||
if (val != work_val && val_len == map->format.val_bytes) {
|
||||
memcpy(work_val, val, map->format.val_bytes);
|
||||
val = work_val;
|
||||
}
|
||||
|
||||
if (map->async && map->bus->async_write) {
|
||||
struct regmap_async *async;
|
||||
|
||||
trace_regmap_async_write_start(map->dev, reg, val_len);
|
||||
|
||||
async->work_buf = kzalloc(map->format.buf_size,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!async->work_buf) {
|
||||
kfree(async);
|
||||
return -ENOMEM;
|
||||
spin_lock_irqsave(&map->async_lock, flags);
|
||||
async = list_first_entry_or_null(&map->async_free,
|
||||
struct regmap_async,
|
||||
list);
|
||||
if (async)
|
||||
list_del(&async->list);
|
||||
spin_unlock_irqrestore(&map->async_lock, flags);
|
||||
|
||||
if (!async) {
|
||||
async = map->bus->async_alloc();
|
||||
if (!async)
|
||||
return -ENOMEM;
|
||||
|
||||
async->work_buf = kzalloc(map->format.buf_size,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!async->work_buf) {
|
||||
kfree(async);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
INIT_WORK(&async->cleanup, async_cleanup);
|
||||
async->map = map;
|
||||
|
||||
/* If the caller supplied the value we can use it safely. */
|
||||
|
@ -1152,11 +1177,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
|
|||
ret);
|
||||
|
||||
spin_lock_irqsave(&map->async_lock, flags);
|
||||
list_del(&async->list);
|
||||
list_move(&async->list, &map->async_free);
|
||||
spin_unlock_irqrestore(&map->async_lock, flags);
|
||||
|
||||
kfree(async->work_buf);
|
||||
kfree(async);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1253,7 +1275,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
|
|||
map->work_buf +
|
||||
map->format.reg_bytes +
|
||||
map->format.pad_bytes,
|
||||
map->format.val_bytes, false);
|
||||
map->format.val_bytes);
|
||||
}
|
||||
|
||||
static inline void *_regmap_map_get_context(struct regmap *map)
|
||||
|
@ -1317,6 +1339,37 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_write);
|
||||
|
||||
/**
|
||||
* regmap_write_async(): Write a value to a single register asynchronously
|
||||
*
|
||||
* @map: Register map to write to
|
||||
* @reg: Register to write to
|
||||
* @val: Value to be written
|
||||
*
|
||||
* A value of zero will be returned on success, a negative errno will
|
||||
* be returned in error cases.
|
||||
*/
|
||||
int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
||||
map->async = true;
|
||||
|
||||
ret = _regmap_write(map, reg, val);
|
||||
|
||||
map->async = false;
|
||||
|
||||
map->unlock(map->lock_arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_write_async);
|
||||
|
||||
/**
|
||||
* regmap_raw_write(): Write raw values to one or more registers
|
||||
*
|
||||
|
@ -1345,7 +1398,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
|
|||
|
||||
map->lock(map->lock_arg);
|
||||
|
||||
ret = _regmap_raw_write(map, reg, val, val_len, false);
|
||||
ret = _regmap_raw_write(map, reg, val, val_len);
|
||||
|
||||
map->unlock(map->lock_arg);
|
||||
|
||||
|
@ -1369,6 +1422,74 @@ int regmap_field_write(struct regmap_field *field, unsigned int val)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_field_write);
|
||||
|
||||
/**
|
||||
* regmap_field_update_bits(): Perform a read/modify/write cycle
|
||||
* on the register field
|
||||
*
|
||||
* @field: Register field to write to
|
||||
* @mask: Bitmask to change
|
||||
* @val: Value to be written
|
||||
*
|
||||
* A value of zero will be returned on success, a negative errno will
|
||||
* be returned in error cases.
|
||||
*/
|
||||
int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val)
|
||||
{
|
||||
mask = (mask << field->shift) & field->mask;
|
||||
|
||||
return regmap_update_bits(field->regmap, field->reg,
|
||||
mask, val << field->shift);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_field_update_bits);
|
||||
|
||||
/**
|
||||
* regmap_fields_write(): Write a value to a single register field with port ID
|
||||
*
|
||||
* @field: Register field to write to
|
||||
* @id: port ID
|
||||
* @val: Value to be written
|
||||
*
|
||||
* A value of zero will be returned on success, a negative errno will
|
||||
* be returned in error cases.
|
||||
*/
|
||||
int regmap_fields_write(struct regmap_field *field, unsigned int id,
|
||||
unsigned int val)
|
||||
{
|
||||
if (id >= field->id_size)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_update_bits(field->regmap,
|
||||
field->reg + (field->id_offset * id),
|
||||
field->mask, val << field->shift);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_fields_write);
|
||||
|
||||
/**
|
||||
* regmap_fields_update_bits(): Perform a read/modify/write cycle
|
||||
* on the register field
|
||||
*
|
||||
* @field: Register field to write to
|
||||
* @id: port ID
|
||||
* @mask: Bitmask to change
|
||||
* @val: Value to be written
|
||||
*
|
||||
* A value of zero will be returned on success, a negative errno will
|
||||
* be returned in error cases.
|
||||
*/
|
||||
int regmap_fields_update_bits(struct regmap_field *field, unsigned int id,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
if (id >= field->id_size)
|
||||
return -EINVAL;
|
||||
|
||||
mask = (mask << field->shift) & field->mask;
|
||||
|
||||
return regmap_update_bits(field->regmap,
|
||||
field->reg + (field->id_offset * id),
|
||||
mask, val << field->shift);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_fields_update_bits);
|
||||
|
||||
/*
|
||||
* regmap_bulk_write(): Write multiple registers to the device
|
||||
*
|
||||
|
@ -1426,8 +1547,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
|||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count,
|
||||
false);
|
||||
ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count);
|
||||
}
|
||||
|
||||
if (val_bytes != 1)
|
||||
|
@ -1473,7 +1593,11 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
|
|||
|
||||
map->lock(map->lock_arg);
|
||||
|
||||
ret = _regmap_raw_write(map, reg, val, val_len, true);
|
||||
map->async = true;
|
||||
|
||||
ret = _regmap_raw_write(map, reg, val, val_len);
|
||||
|
||||
map->async = false;
|
||||
|
||||
map->unlock(map->lock_arg);
|
||||
|
||||
|
@ -1676,6 +1800,39 @@ int regmap_field_read(struct regmap_field *field, unsigned int *val)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_field_read);
|
||||
|
||||
/**
|
||||
* regmap_fields_read(): Read a value to a single register field with port ID
|
||||
*
|
||||
* @field: Register field to read from
|
||||
* @id: port ID
|
||||
* @val: Pointer to store read value
|
||||
*
|
||||
* A value of zero will be returned on success, a negative errno will
|
||||
* be returned in error cases.
|
||||
*/
|
||||
int regmap_fields_read(struct regmap_field *field, unsigned int id,
|
||||
unsigned int *val)
|
||||
{
|
||||
int ret;
|
||||
unsigned int reg_val;
|
||||
|
||||
if (id >= field->id_size)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_read(field->regmap,
|
||||
field->reg + (field->id_offset * id),
|
||||
®_val);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
reg_val &= field->mask;
|
||||
reg_val >>= field->shift;
|
||||
*val = reg_val;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_fields_read);
|
||||
|
||||
/**
|
||||
* regmap_bulk_read(): Read multiple registers from the device
|
||||
*
|
||||
|
@ -1787,6 +1944,41 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_update_bits);
|
||||
|
||||
/**
|
||||
* regmap_update_bits_async: Perform a read/modify/write cycle on the register
|
||||
* map asynchronously
|
||||
*
|
||||
* @map: Register map to update
|
||||
* @reg: Register to update
|
||||
* @mask: Bitmask to change
|
||||
* @val: New value for bitmask
|
||||
*
|
||||
* With most buses the read must be done synchronously so this is most
|
||||
* useful for devices with a cache which do not need to interact with
|
||||
* the hardware to determine the current register value.
|
||||
*
|
||||
* Returns zero for success, a negative number on error.
|
||||
*/
|
||||
int regmap_update_bits_async(struct regmap *map, unsigned int reg,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
bool change;
|
||||
int ret;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
||||
map->async = true;
|
||||
|
||||
ret = _regmap_update_bits(map, reg, mask, val, &change);
|
||||
|
||||
map->async = false;
|
||||
|
||||
map->unlock(map->lock_arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_update_bits_async);
|
||||
|
||||
/**
|
||||
* regmap_update_bits_check: Perform a read/modify/write cycle on the
|
||||
* register map and report if updated
|
||||
|
@ -1812,6 +2004,43 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_update_bits_check);
|
||||
|
||||
/**
|
||||
* regmap_update_bits_check_async: Perform a read/modify/write cycle on the
|
||||
* register map asynchronously and report if
|
||||
* updated
|
||||
*
|
||||
* @map: Register map to update
|
||||
* @reg: Register to update
|
||||
* @mask: Bitmask to change
|
||||
* @val: New value for bitmask
|
||||
* @change: Boolean indicating if a write was done
|
||||
*
|
||||
* With most buses the read must be done synchronously so this is most
|
||||
* useful for devices with a cache which do not need to interact with
|
||||
* the hardware to determine the current register value.
|
||||
*
|
||||
* Returns zero for success, a negative number on error.
|
||||
*/
|
||||
int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
|
||||
unsigned int mask, unsigned int val,
|
||||
bool *change)
|
||||
{
|
||||
int ret;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
||||
map->async = true;
|
||||
|
||||
ret = _regmap_update_bits(map, reg, mask, val, change);
|
||||
|
||||
map->async = false;
|
||||
|
||||
map->unlock(map->lock_arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_update_bits_check_async);
|
||||
|
||||
void regmap_async_complete_cb(struct regmap_async *async, int ret)
|
||||
{
|
||||
struct regmap *map = async->map;
|
||||
|
@ -1820,8 +2049,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
|
|||
trace_regmap_async_io_complete(map->dev);
|
||||
|
||||
spin_lock(&map->async_lock);
|
||||
|
||||
list_del(&async->list);
|
||||
list_move(&async->list, &map->async_free);
|
||||
wake = list_empty(&map->async_list);
|
||||
|
||||
if (ret != 0)
|
||||
|
@ -1829,8 +2057,6 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
|
|||
|
||||
spin_unlock(&map->async_lock);
|
||||
|
||||
schedule_work(&async->cleanup);
|
||||
|
||||
if (wake)
|
||||
wake_up(&map->async_waitq);
|
||||
}
|
||||
|
|
|
@ -158,8 +158,6 @@ int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
|
|||
{
|
||||
int ret;
|
||||
|
||||
BUG_ON(!mutex_is_locked(&mc13xxx->lock));
|
||||
|
||||
if (offset > MC13XXX_NUMREGS)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -172,8 +170,6 @@ EXPORT_SYMBOL(mc13xxx_reg_read);
|
|||
|
||||
int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
|
||||
{
|
||||
BUG_ON(!mutex_is_locked(&mc13xxx->lock));
|
||||
|
||||
dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val);
|
||||
|
||||
if (offset > MC13XXX_NUMREGS || val > 0xffffff)
|
||||
|
@ -186,7 +182,6 @@ EXPORT_SYMBOL(mc13xxx_reg_write);
|
|||
int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
|
||||
u32 mask, u32 val)
|
||||
{
|
||||
BUG_ON(!mutex_is_locked(&mc13xxx->lock));
|
||||
BUG_ON(val & ~mask);
|
||||
dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x (mask: 0x%06x)\n",
|
||||
offset, val, mask);
|
||||
|
|
|
@ -94,10 +94,15 @@ static int mc13xxx_spi_write(void *context, const void *data, size_t count)
|
|||
{
|
||||
struct device *dev = context;
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
const char *reg = data;
|
||||
|
||||
if (count != 4)
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* include errata fix for spi audio problems */
|
||||
if (*reg == MC13783_AUDIO_CODEC || *reg == MC13783_AUDIO_DAC)
|
||||
spi_write(spi, data, count);
|
||||
|
||||
return spi_write(spi, data, count);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,13 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx,
|
|||
unsigned int mode, unsigned int channel,
|
||||
u8 ato, bool atox, unsigned int *sample);
|
||||
|
||||
#define MC13783_AUDIO_RX0 36
|
||||
#define MC13783_AUDIO_RX1 37
|
||||
#define MC13783_AUDIO_TX 38
|
||||
#define MC13783_SSI_NETWORK 39
|
||||
#define MC13783_AUDIO_CODEC 40
|
||||
#define MC13783_AUDIO_DAC 41
|
||||
|
||||
#define MC13XXX_IRQ_ADCDONE 0
|
||||
#define MC13XXX_IRQ_ADCBISDONE 1
|
||||
#define MC13XXX_IRQ_TS 2
|
||||
|
|
|
@ -84,6 +84,8 @@ struct snd_platform_data {
|
|||
u8 version;
|
||||
u8 txnumevt;
|
||||
u8 rxnumevt;
|
||||
int tx_dma_channel;
|
||||
int rx_dma_channel;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
@ -374,6 +374,7 @@ int regmap_reinit_cache(struct regmap *map,
|
|||
const struct regmap_config *config);
|
||||
struct regmap *dev_get_regmap(struct device *dev, const char *name);
|
||||
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
|
||||
int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val);
|
||||
int regmap_raw_write(struct regmap *map, unsigned int reg,
|
||||
const void *val, size_t val_len);
|
||||
int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
||||
|
@ -387,9 +388,14 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
|
|||
size_t val_count);
|
||||
int regmap_update_bits(struct regmap *map, unsigned int reg,
|
||||
unsigned int mask, unsigned int val);
|
||||
int regmap_update_bits_async(struct regmap *map, unsigned int reg,
|
||||
unsigned int mask, unsigned int val);
|
||||
int regmap_update_bits_check(struct regmap *map, unsigned int reg,
|
||||
unsigned int mask, unsigned int val,
|
||||
bool *change);
|
||||
int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
|
||||
unsigned int mask, unsigned int val,
|
||||
bool *change);
|
||||
int regmap_get_val_bytes(struct regmap *map);
|
||||
int regmap_async_complete(struct regmap *map);
|
||||
bool regmap_can_raw_write(struct regmap *map);
|
||||
|
@ -425,11 +431,15 @@ bool regmap_reg_in_ranges(unsigned int reg,
|
|||
* @reg: Offset of the register within the regmap bank
|
||||
* @lsb: lsb of the register field.
|
||||
* @reg: msb of the register field.
|
||||
* @id_size: port size if it has some ports
|
||||
* @id_offset: address offset for each ports
|
||||
*/
|
||||
struct reg_field {
|
||||
unsigned int reg;
|
||||
unsigned int lsb;
|
||||
unsigned int msb;
|
||||
unsigned int id_size;
|
||||
unsigned int id_offset;
|
||||
};
|
||||
|
||||
#define REG_FIELD(_reg, _lsb, _msb) { \
|
||||
|
@ -448,6 +458,15 @@ void devm_regmap_field_free(struct device *dev, struct regmap_field *field);
|
|||
|
||||
int regmap_field_read(struct regmap_field *field, unsigned int *val);
|
||||
int regmap_field_write(struct regmap_field *field, unsigned int val);
|
||||
int regmap_field_update_bits(struct regmap_field *field,
|
||||
unsigned int mask, unsigned int val);
|
||||
|
||||
int regmap_fields_write(struct regmap_field *field, unsigned int id,
|
||||
unsigned int val);
|
||||
int regmap_fields_read(struct regmap_field *field, unsigned int id,
|
||||
unsigned int *val);
|
||||
int regmap_fields_update_bits(struct regmap_field *field, unsigned int id,
|
||||
unsigned int mask, unsigned int val);
|
||||
|
||||
/**
|
||||
* Description of an IRQ for the generic regmap irq_chip.
|
||||
|
@ -527,6 +546,13 @@ static inline int regmap_write(struct regmap *map, unsigned int reg,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_write_async(struct regmap *map, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
WARN_ONCE(1, "regmap API is disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_raw_write(struct regmap *map, unsigned int reg,
|
||||
const void *val, size_t val_len)
|
||||
{
|
||||
|
@ -576,6 +602,14 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_update_bits_async(struct regmap *map,
|
||||
unsigned int reg,
|
||||
unsigned int mask, unsigned int val)
|
||||
{
|
||||
WARN_ONCE(1, "regmap API is disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_update_bits_check(struct regmap *map,
|
||||
unsigned int reg,
|
||||
unsigned int mask, unsigned int val,
|
||||
|
@ -585,6 +619,16 @@ static inline int regmap_update_bits_check(struct regmap *map,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_update_bits_check_async(struct regmap *map,
|
||||
unsigned int reg,
|
||||
unsigned int mask,
|
||||
unsigned int val,
|
||||
bool *change)
|
||||
{
|
||||
WARN_ONCE(1, "regmap API is disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_get_val_bytes(struct regmap *map)
|
||||
{
|
||||
WARN_ONCE(1, "regmap API is disabled");
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* linux/sound/cs42l73.h -- Platform data for CS42L73
|
||||
*
|
||||
* Copyright (c) 2012 Cirrus Logic Inc.
|
||||
*
|
||||
* 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 __CS42L73_H
|
||||
#define __CS42L73_H
|
||||
|
||||
struct cs42l73_platform_data {
|
||||
/* RST GPIO */
|
||||
unsigned int reset_gpio;
|
||||
unsigned int chgfreq;
|
||||
int jack_detection;
|
||||
unsigned int mclk_freq;
|
||||
};
|
||||
|
||||
#endif /* __CS42L73_H */
|
|
@ -61,6 +61,8 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
|
|||
* @slave_id: Slave requester id for the DMA channel.
|
||||
* @filter_data: Custom DMA channel filter data, this will usually be used when
|
||||
* requesting the DMA channel.
|
||||
* @chan_name: Custom channel name to use when requesting DMA channel.
|
||||
* @fifo_size: FIFO size of the DAI controller in bytes
|
||||
*/
|
||||
struct snd_dmaengine_dai_dma_data {
|
||||
dma_addr_t addr;
|
||||
|
@ -68,6 +70,8 @@ struct snd_dmaengine_dai_dma_data {
|
|||
u32 maxburst;
|
||||
unsigned int slave_id;
|
||||
void *filter_data;
|
||||
const char *chan_name;
|
||||
unsigned int fifo_size;
|
||||
};
|
||||
|
||||
void snd_dmaengine_pcm_set_config_from_dai_data(
|
||||
|
@ -96,6 +100,10 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
|
|||
* playback.
|
||||
*/
|
||||
#define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3)
|
||||
/*
|
||||
* The PCM streams have custom channel names specified.
|
||||
*/
|
||||
#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4)
|
||||
|
||||
/**
|
||||
* struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
|
||||
#define RSND_SSI_CLK_FROM_ADG (1 << 30) /* clock parent is master */
|
||||
#define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */
|
||||
#define RSND_SSI_DEPENDENT (1 << 28) /* SSI needs SRU/SCU */
|
||||
|
||||
#define RSND_SSI_PLAY (1 << 24)
|
||||
|
||||
|
|
|
@ -105,6 +105,8 @@ int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
|
|||
int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
|
||||
int pll_id, int source, unsigned int freq_in, unsigned int freq_out);
|
||||
|
||||
int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio);
|
||||
|
||||
/* Digital Audio interface formatting */
|
||||
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
|
||||
|
||||
|
@ -131,6 +133,7 @@ struct snd_soc_dai_ops {
|
|||
int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out);
|
||||
int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
|
||||
int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio);
|
||||
|
||||
/*
|
||||
* DAI format configuration
|
||||
|
@ -166,6 +169,13 @@ struct snd_soc_dai_ops {
|
|||
struct snd_soc_dai *);
|
||||
int (*prepare)(struct snd_pcm_substream *,
|
||||
struct snd_soc_dai *);
|
||||
/*
|
||||
* NOTE: Commands passed to the trigger function are not necessarily
|
||||
* compatible with the current state of the dai. For example this
|
||||
* sequence of commands is possible: START STOP STOP.
|
||||
* So do not unconditionally use refcounting functions in the trigger
|
||||
* function, e.g. clk_enable/disable.
|
||||
*/
|
||||
int (*trigger)(struct snd_pcm_substream *, int,
|
||||
struct snd_soc_dai *);
|
||||
int (*bespoke_trigger)(struct snd_pcm_substream *, int,
|
||||
|
@ -276,6 +286,13 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
|
|||
dai->capture_dma_data = data;
|
||||
}
|
||||
|
||||
static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai,
|
||||
void *playback, void *capture)
|
||||
{
|
||||
dai->playback_dma_data = playback;
|
||||
dai->capture_dma_data = capture;
|
||||
}
|
||||
|
||||
static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
|
||||
void *data)
|
||||
{
|
||||
|
|
|
@ -286,6 +286,8 @@ struct device;
|
|||
.info = snd_soc_info_volsw, \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
|
||||
#define SOC_DAPM_SINGLE_VIRT(xname, max) \
|
||||
SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0)
|
||||
#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_volsw, \
|
||||
|
@ -300,6 +302,8 @@ struct device;
|
|||
.tlv.p = (tlv_array), \
|
||||
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
|
||||
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
|
||||
#define SOC_DAPM_SINGLE_TLV_VIRT(xname, max, tlv_array) \
|
||||
SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array)
|
||||
#define SOC_DAPM_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_enum_double, \
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef __LINUX_SND_SOC_H
|
||||
#define __LINUX_SND_SOC_H
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/notifier.h>
|
||||
|
@ -330,7 +331,6 @@ struct soc_enum;
|
|||
struct snd_soc_jack;
|
||||
struct snd_soc_jack_zone;
|
||||
struct snd_soc_jack_pin;
|
||||
struct snd_soc_cache_ops;
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/soc-dpcm.h>
|
||||
|
||||
|
@ -348,10 +348,6 @@ enum snd_soc_control_type {
|
|||
SND_SOC_REGMAP,
|
||||
};
|
||||
|
||||
enum snd_soc_compress_type {
|
||||
SND_SOC_FLAT_COMPRESSION = 1,
|
||||
};
|
||||
|
||||
enum snd_soc_pcm_subclass {
|
||||
SND_SOC_PCM_CLASS_PCM = 0,
|
||||
SND_SOC_PCM_CLASS_BE = 1,
|
||||
|
@ -369,6 +365,7 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
|
|||
|
||||
int snd_soc_register_card(struct snd_soc_card *card);
|
||||
int snd_soc_unregister_card(struct snd_soc_card *card);
|
||||
int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card);
|
||||
int snd_soc_suspend(struct device *dev);
|
||||
int snd_soc_resume(struct device *dev);
|
||||
int snd_soc_poweroff(struct device *dev);
|
||||
|
@ -386,6 +383,9 @@ void snd_soc_unregister_codec(struct device *dev);
|
|||
int 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);
|
||||
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_codec_volatile_register(struct snd_soc_codec *codec,
|
||||
unsigned int reg);
|
||||
|
@ -403,12 +403,6 @@ 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_default_volatile_register(struct snd_soc_codec *codec,
|
||||
unsigned int reg);
|
||||
int snd_soc_default_readable_register(struct snd_soc_codec *codec,
|
||||
unsigned int reg);
|
||||
int snd_soc_default_writable_register(struct snd_soc_codec *codec,
|
||||
unsigned int reg);
|
||||
int snd_soc_platform_read(struct snd_soc_platform *platform,
|
||||
unsigned int reg);
|
||||
int snd_soc_platform_write(struct snd_soc_platform *platform,
|
||||
|
@ -541,22 +535,6 @@ int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
|
|||
int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
|
||||
/**
|
||||
* struct snd_soc_reg_access - Describes whether a given register is
|
||||
* readable, writable or volatile.
|
||||
*
|
||||
* @reg: the register number
|
||||
* @read: whether this register is readable
|
||||
* @write: whether this register is writable
|
||||
* @vol: whether this register is volatile
|
||||
*/
|
||||
struct snd_soc_reg_access {
|
||||
u16 reg;
|
||||
u16 read;
|
||||
u16 write;
|
||||
u16 vol;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct snd_soc_jack_pin - Describes a pin to update based on jack detection
|
||||
*
|
||||
|
@ -657,17 +635,26 @@ struct snd_soc_compr_ops {
|
|||
int (*trigger)(struct snd_compr_stream *);
|
||||
};
|
||||
|
||||
/* SoC cache ops */
|
||||
struct snd_soc_cache_ops {
|
||||
/* component interface */
|
||||
struct snd_soc_component_driver {
|
||||
const char *name;
|
||||
enum snd_soc_compress_type id;
|
||||
int (*init)(struct snd_soc_codec *codec);
|
||||
int (*exit)(struct snd_soc_codec *codec);
|
||||
int (*read)(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int *value);
|
||||
int (*write)(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value);
|
||||
int (*sync)(struct snd_soc_codec *codec);
|
||||
|
||||
/* DT */
|
||||
int (*of_xlate_dai_name)(struct snd_soc_component *component,
|
||||
struct of_phandle_args *args,
|
||||
const char **dai_name);
|
||||
};
|
||||
|
||||
struct snd_soc_component {
|
||||
const char *name;
|
||||
int id;
|
||||
struct device *dev;
|
||||
struct list_head list;
|
||||
|
||||
struct snd_soc_dai_driver *dai_drv;
|
||||
int num_dai;
|
||||
|
||||
const struct snd_soc_component_driver *driver;
|
||||
};
|
||||
|
||||
/* SoC Audio Codec device */
|
||||
|
@ -683,8 +670,6 @@ struct snd_soc_codec {
|
|||
struct list_head list;
|
||||
struct list_head card_list;
|
||||
int num_dai;
|
||||
enum snd_soc_compress_type compress_type;
|
||||
size_t reg_size; /* reg_cache_size * reg_word_size */
|
||||
int (*volatile_register)(struct snd_soc_codec *, unsigned int);
|
||||
int (*readable_register)(struct snd_soc_codec *, unsigned int);
|
||||
int (*writable_register)(struct snd_soc_codec *, unsigned int);
|
||||
|
@ -708,13 +693,13 @@ struct snd_soc_codec {
|
|||
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
|
||||
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
|
||||
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
|
||||
int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t);
|
||||
void *reg_cache;
|
||||
const void *reg_def_copy;
|
||||
const struct snd_soc_cache_ops *cache_ops;
|
||||
struct mutex cache_rw_mutex;
|
||||
int val_bytes;
|
||||
|
||||
/* component */
|
||||
struct snd_soc_component component;
|
||||
|
||||
/* dapm */
|
||||
struct snd_soc_dapm_context dapm;
|
||||
unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
|
||||
|
@ -733,6 +718,7 @@ struct snd_soc_codec_driver {
|
|||
int (*remove)(struct snd_soc_codec *);
|
||||
int (*suspend)(struct snd_soc_codec *);
|
||||
int (*resume)(struct snd_soc_codec *);
|
||||
struct snd_soc_component_driver component_driver;
|
||||
|
||||
/* Default control and setup, added after probe() is run */
|
||||
const struct snd_kcontrol_new *controls;
|
||||
|
@ -760,9 +746,6 @@ struct snd_soc_codec_driver {
|
|||
short reg_cache_step;
|
||||
short reg_word_size;
|
||||
const void *reg_cache_default;
|
||||
short reg_access_size;
|
||||
const struct snd_soc_reg_access *reg_access_default;
|
||||
enum snd_soc_compress_type compress_type;
|
||||
|
||||
/* codec bias level */
|
||||
int (*set_bias_level)(struct snd_soc_codec *,
|
||||
|
@ -849,20 +832,6 @@ struct snd_soc_platform {
|
|||
#endif
|
||||
};
|
||||
|
||||
struct snd_soc_component_driver {
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct snd_soc_component {
|
||||
const char *name;
|
||||
int id;
|
||||
int num_dai;
|
||||
struct device *dev;
|
||||
struct list_head list;
|
||||
|
||||
const struct snd_soc_component_driver *driver;
|
||||
};
|
||||
|
||||
struct snd_soc_dai_link {
|
||||
/* config - must be set by machine driver */
|
||||
const char *name; /* Codec name */
|
||||
|
@ -944,12 +913,6 @@ struct snd_soc_codec_conf {
|
|||
* associated per device
|
||||
*/
|
||||
const char *name_prefix;
|
||||
|
||||
/*
|
||||
* set this to the desired compression type if you want to
|
||||
* override the one supplied in codec->driver->compress_type
|
||||
*/
|
||||
enum snd_soc_compress_type compress_type;
|
||||
};
|
||||
|
||||
struct snd_soc_aux_dev {
|
||||
|
@ -1088,7 +1051,8 @@ struct snd_soc_pcm_runtime {
|
|||
/* mixer control */
|
||||
struct soc_mixer_control {
|
||||
int min, max, platform_max;
|
||||
unsigned int reg, rreg, shift, rshift;
|
||||
int reg, rreg;
|
||||
unsigned int shift, rshift;
|
||||
unsigned int invert:1;
|
||||
unsigned int autodisable:1;
|
||||
};
|
||||
|
@ -1121,8 +1085,6 @@ struct soc_enum {
|
|||
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
|
||||
unsigned int snd_soc_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int val);
|
||||
unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
|
||||
unsigned int reg, const void *data, size_t len);
|
||||
|
||||
/* device driver data */
|
||||
|
||||
|
@ -1201,6 +1163,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
|
|||
const char *propname);
|
||||
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
|
||||
const char *prefix);
|
||||
int snd_soc_of_get_dai_name(struct device_node *of_node,
|
||||
const char **dai_name);
|
||||
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ struct snd_soc_codec;
|
|||
struct snd_soc_platform;
|
||||
struct snd_soc_card;
|
||||
struct snd_soc_dapm_widget;
|
||||
struct snd_soc_dapm_path;
|
||||
|
||||
/*
|
||||
* Log register events
|
||||
|
|
|
@ -117,8 +117,7 @@ static inline void pxa_ac97_warm_pxa25x(void)
|
|||
{
|
||||
gsr_bits = 0;
|
||||
|
||||
GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
|
||||
wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
|
||||
GCR |= GCR_WARM_RST;
|
||||
}
|
||||
|
||||
static inline void pxa_ac97_cold_pxa25x(void)
|
||||
|
@ -129,8 +128,6 @@ static inline void pxa_ac97_cold_pxa25x(void)
|
|||
gsr_bits = 0;
|
||||
|
||||
GCR = GCR_COLD_RST;
|
||||
GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
|
||||
wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -149,8 +146,6 @@ static inline void pxa_ac97_warm_pxa27x(void)
|
|||
|
||||
static inline void pxa_ac97_cold_pxa27x(void)
|
||||
{
|
||||
unsigned int timeout;
|
||||
|
||||
GCR &= GCR_COLD_RST; /* clear everything but nCRST */
|
||||
GCR &= ~GCR_COLD_RST; /* then assert nCRST */
|
||||
|
||||
|
@ -161,29 +156,20 @@ static inline void pxa_ac97_cold_pxa27x(void)
|
|||
udelay(5);
|
||||
clk_disable(ac97conf_clk);
|
||||
GCR = GCR_COLD_RST | GCR_WARM_RST;
|
||||
timeout = 100; /* wait for the codec-ready bit to be set */
|
||||
while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
|
||||
mdelay(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PXA3xx
|
||||
static inline void pxa_ac97_warm_pxa3xx(void)
|
||||
{
|
||||
int timeout = 100;
|
||||
|
||||
gsr_bits = 0;
|
||||
|
||||
/* Can't use interrupts */
|
||||
GCR |= GCR_WARM_RST;
|
||||
while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
static inline void pxa_ac97_cold_pxa3xx(void)
|
||||
{
|
||||
int timeout = 1000;
|
||||
|
||||
/* Hold CLKBPB for 100us */
|
||||
GCR = 0;
|
||||
GCR = GCR_CLKBPB;
|
||||
|
@ -199,14 +185,13 @@ static inline void pxa_ac97_cold_pxa3xx(void)
|
|||
GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
|
||||
|
||||
GCR = GCR_WARM_RST | GCR_COLD_RST;
|
||||
while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
|
||||
mdelay(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
unsigned long gsr;
|
||||
unsigned int timeout = 100;
|
||||
|
||||
#ifdef CONFIG_PXA25x
|
||||
if (cpu_is_pxa25x())
|
||||
|
@ -224,6 +209,10 @@ bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
|
|||
else
|
||||
#endif
|
||||
BUG();
|
||||
|
||||
while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
|
||||
mdelay(1);
|
||||
|
||||
gsr = GSR | gsr_bits;
|
||||
if (!(gsr & (GSR_PCR | GSR_SCR))) {
|
||||
printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
|
||||
|
@ -239,6 +228,7 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
|
|||
bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
unsigned long gsr;
|
||||
unsigned int timeout = 1000;
|
||||
|
||||
#ifdef CONFIG_PXA25x
|
||||
if (cpu_is_pxa25x())
|
||||
|
@ -257,6 +247,9 @@ bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
|
|||
#endif
|
||||
BUG();
|
||||
|
||||
while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
|
||||
mdelay(1);
|
||||
|
||||
gsr = GSR | gsr_bits;
|
||||
if (!(gsr & (GSR_PCR | GSR_SCR))) {
|
||||
printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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
|
||||
snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o
|
||||
|
||||
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
|
||||
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
|
||||
|
|
|
@ -50,7 +50,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
|
|||
buf->area = dma_alloc_coherent(pcm->card->dev, size,
|
||||
&buf->addr, GFP_KERNEL);
|
||||
pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
|
||||
(void *)buf->area, (void *)buf->addr, size);
|
||||
(void *)buf->area, (void *)(long)buf->addr, size);
|
||||
|
||||
if (!buf->area)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
|
@ -155,15 +154,8 @@ static int atmel_asoc_wm8904_probe(struct platform_device *pdev)
|
|||
struct snd_soc_card *card = &atmel_asoc_wm8904_card;
|
||||
struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
|
||||
struct clk *clk_src;
|
||||
struct pinctrl *pinctrl;
|
||||
int id, ret;
|
||||
|
||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl)) {
|
||||
dev_err(&pdev->dev, "failed to request pinctrl\n");
|
||||
return PTR_ERR(pinctrl);
|
||||
}
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
ret = atmel_asoc_wm8904_dt_init(pdev);
|
||||
if (ret) {
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/atmel-ssc.h>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config SND_EP93XX_SOC
|
||||
tristate "SoC Audio support for the Cirrus Logic EP93xx series"
|
||||
depends on ARCH_EP93XX && SND_SOC
|
||||
depends on (ARCH_EP93XX || COMPILE_TEST) && SND_SOC
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
help
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
|
|
|
@ -57,9 +57,22 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
|
|||
return false;
|
||||
}
|
||||
|
||||
static struct dma_chan *ep93xx_compat_request_channel(
|
||||
struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
|
||||
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
|
||||
return snd_dmaengine_pcm_request_channel(ep93xx_pcm_dma_filter,
|
||||
dma_data);
|
||||
}
|
||||
|
||||
static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = {
|
||||
.pcm_hardware = &ep93xx_pcm_hardware,
|
||||
.compat_filter_fn = ep93xx_pcm_dma_filter,
|
||||
.compat_request_channel = ep93xx_compat_request_channel,
|
||||
.prealloc_buffer_size = 131072,
|
||||
};
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/mfd/88pm860x.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
@ -140,6 +141,7 @@ struct pm860x_priv {
|
|||
unsigned int filter;
|
||||
struct snd_soc_codec *codec;
|
||||
struct i2c_client *i2c;
|
||||
struct regmap *regmap;
|
||||
struct pm860x_chip *chip;
|
||||
struct pm860x_det det;
|
||||
|
||||
|
@ -269,48 +271,6 @@ static struct st_gain st_table[] = {
|
|||
{ -86, 29, 0}, { -56, 30, 0}, { -28, 31, 0}, { 0, 0, 0},
|
||||
};
|
||||
|
||||
static int pm860x_volatile(unsigned int reg)
|
||||
{
|
||||
BUG_ON(reg >= REG_CACHE_SIZE);
|
||||
|
||||
switch (reg) {
|
||||
case PM860X_AUDIO_SUPPLIES_2:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
unsigned char *cache = codec->reg_cache;
|
||||
|
||||
BUG_ON(reg >= REG_CACHE_SIZE);
|
||||
|
||||
if (pm860x_volatile(reg))
|
||||
return cache[reg];
|
||||
|
||||
reg += REG_CACHE_BASE;
|
||||
|
||||
return pm860x_reg_read(codec->control_data, reg);
|
||||
}
|
||||
|
||||
static int pm860x_write_reg_cache(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
unsigned char *cache = codec->reg_cache;
|
||||
|
||||
BUG_ON(reg >= REG_CACHE_SIZE);
|
||||
|
||||
if (!pm860x_volatile(reg))
|
||||
cache[reg] = (unsigned char)value;
|
||||
|
||||
reg += REG_CACHE_BASE;
|
||||
|
||||
return pm860x_reg_write(codec->control_data, reg, value);
|
||||
}
|
||||
|
||||
static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
|
@ -1169,6 +1129,7 @@ static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
static int pm860x_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
|
||||
int data;
|
||||
|
||||
switch (level) {
|
||||
|
@ -1182,17 +1143,17 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
|
|||
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
|
||||
/* Enable Audio PLL & Audio section */
|
||||
data = AUDIO_PLL | AUDIO_SECTION_ON;
|
||||
pm860x_reg_write(codec->control_data, REG_MISC2, data);
|
||||
pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
|
||||
udelay(300);
|
||||
data = AUDIO_PLL | AUDIO_SECTION_RESET
|
||||
| AUDIO_SECTION_ON;
|
||||
pm860x_reg_write(codec->control_data, REG_MISC2, data);
|
||||
pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
|
||||
pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
|
||||
pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
|
@ -1322,17 +1283,17 @@ int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
|
|||
pm860x->det.lo_shrt = lo_shrt;
|
||||
|
||||
if (det & SND_JACK_HEADPHONE)
|
||||
pm860x_set_bits(codec->control_data, REG_HS_DET,
|
||||
pm860x_set_bits(pm860x->i2c, REG_HS_DET,
|
||||
EN_HS_DET, EN_HS_DET);
|
||||
/* headset short detect */
|
||||
if (hs_shrt) {
|
||||
data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
|
||||
pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
|
||||
pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);
|
||||
}
|
||||
/* Lineout short detect */
|
||||
if (lo_shrt) {
|
||||
data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
|
||||
pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
|
||||
pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);
|
||||
}
|
||||
|
||||
/* sync status */
|
||||
|
@ -1350,7 +1311,7 @@ int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
|
|||
pm860x->det.mic_det = det;
|
||||
|
||||
if (det & SND_JACK_MICROPHONE)
|
||||
pm860x_set_bits(codec->control_data, REG_MIC_DET,
|
||||
pm860x_set_bits(pm860x->i2c, REG_MIC_DET,
|
||||
MICDET_MASK, MICDET_MASK);
|
||||
|
||||
/* sync status */
|
||||
|
@ -1366,7 +1327,7 @@ static int pm860x_probe(struct snd_soc_codec *codec)
|
|||
|
||||
pm860x->codec = codec;
|
||||
|
||||
codec->control_data = pm860x->i2c;
|
||||
codec->control_data = pm860x->regmap;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = request_threaded_irq(pm860x->irq[i], NULL,
|
||||
|
@ -1380,14 +1341,6 @@ static int pm860x_probe(struct snd_soc_codec *codec)
|
|||
|
||||
pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE,
|
||||
REG_CACHE_SIZE, codec->reg_cache);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to fill register cache: %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
|
@ -1410,10 +1363,6 @@ static int pm860x_remove(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
|
||||
.probe = pm860x_probe,
|
||||
.remove = pm860x_remove,
|
||||
.read = pm860x_read_reg_cache,
|
||||
.write = pm860x_write_reg_cache,
|
||||
.reg_cache_size = REG_CACHE_SIZE,
|
||||
.reg_word_size = sizeof(u8),
|
||||
.set_bias_level = pm860x_set_bias_level,
|
||||
|
||||
.controls = pm860x_snd_controls,
|
||||
|
@ -1439,6 +1388,8 @@ static int pm860x_codec_probe(struct platform_device *pdev)
|
|||
pm860x->chip = chip;
|
||||
pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
|
||||
: chip->companion;
|
||||
pm860x->regmap = (chip->id == CHIP_PM8607) ? chip->regmap
|
||||
: chip->regmap_companion;
|
||||
platform_set_drvdata(pdev, pm860x);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
|
|
|
@ -12,67 +12,66 @@
|
|||
#ifndef __88PM860X_H
|
||||
#define __88PM860X_H
|
||||
|
||||
/* The offset of these registers are 0xb0 */
|
||||
#define PM860X_PCM_IFACE_1 0x00
|
||||
#define PM860X_PCM_IFACE_2 0x01
|
||||
#define PM860X_PCM_IFACE_3 0x02
|
||||
#define PM860X_PCM_RATE 0x03
|
||||
#define PM860X_EC_PATH 0x04
|
||||
#define PM860X_SIDETONE_L_GAIN 0x05
|
||||
#define PM860X_SIDETONE_R_GAIN 0x06
|
||||
#define PM860X_SIDETONE_SHIFT 0x07
|
||||
#define PM860X_ADC_OFFSET_1 0x08
|
||||
#define PM860X_ADC_OFFSET_2 0x09
|
||||
#define PM860X_DMIC_DELAY 0x0a
|
||||
#define PM860X_PCM_IFACE_1 0xb0
|
||||
#define PM860X_PCM_IFACE_2 0xb1
|
||||
#define PM860X_PCM_IFACE_3 0xb2
|
||||
#define PM860X_PCM_RATE 0xb3
|
||||
#define PM860X_EC_PATH 0xb4
|
||||
#define PM860X_SIDETONE_L_GAIN 0xb5
|
||||
#define PM860X_SIDETONE_R_GAIN 0xb6
|
||||
#define PM860X_SIDETONE_SHIFT 0xb7
|
||||
#define PM860X_ADC_OFFSET_1 0xb8
|
||||
#define PM860X_ADC_OFFSET_2 0xb9
|
||||
#define PM860X_DMIC_DELAY 0xba
|
||||
|
||||
#define PM860X_I2S_IFACE_1 0x0b
|
||||
#define PM860X_I2S_IFACE_2 0x0c
|
||||
#define PM860X_I2S_IFACE_3 0x0d
|
||||
#define PM860X_I2S_IFACE_4 0x0e
|
||||
#define PM860X_EQUALIZER_N0_1 0x0f
|
||||
#define PM860X_EQUALIZER_N0_2 0x10
|
||||
#define PM860X_EQUALIZER_N1_1 0x11
|
||||
#define PM860X_EQUALIZER_N1_2 0x12
|
||||
#define PM860X_EQUALIZER_D1_1 0x13
|
||||
#define PM860X_EQUALIZER_D1_2 0x14
|
||||
#define PM860X_LOFI_GAIN_LEFT 0x15
|
||||
#define PM860X_LOFI_GAIN_RIGHT 0x16
|
||||
#define PM860X_HIFIL_GAIN_LEFT 0x17
|
||||
#define PM860X_HIFIL_GAIN_RIGHT 0x18
|
||||
#define PM860X_HIFIR_GAIN_LEFT 0x19
|
||||
#define PM860X_HIFIR_GAIN_RIGHT 0x1a
|
||||
#define PM860X_DAC_OFFSET 0x1b
|
||||
#define PM860X_OFFSET_LEFT_1 0x1c
|
||||
#define PM860X_OFFSET_LEFT_2 0x1d
|
||||
#define PM860X_OFFSET_RIGHT_1 0x1e
|
||||
#define PM860X_OFFSET_RIGHT_2 0x1f
|
||||
#define PM860X_ADC_ANA_1 0x20
|
||||
#define PM860X_ADC_ANA_2 0x21
|
||||
#define PM860X_ADC_ANA_3 0x22
|
||||
#define PM860X_ADC_ANA_4 0x23
|
||||
#define PM860X_ANA_TO_ANA 0x24
|
||||
#define PM860X_HS1_CTRL 0x25
|
||||
#define PM860X_HS2_CTRL 0x26
|
||||
#define PM860X_LO1_CTRL 0x27
|
||||
#define PM860X_LO2_CTRL 0x28
|
||||
#define PM860X_EAR_CTRL_1 0x29
|
||||
#define PM860X_EAR_CTRL_2 0x2a
|
||||
#define PM860X_AUDIO_SUPPLIES_1 0x2b
|
||||
#define PM860X_AUDIO_SUPPLIES_2 0x2c
|
||||
#define PM860X_ADC_EN_1 0x2d
|
||||
#define PM860X_ADC_EN_2 0x2e
|
||||
#define PM860X_DAC_EN_1 0x2f
|
||||
#define PM860X_DAC_EN_2 0x31
|
||||
#define PM860X_AUDIO_CAL_1 0x32
|
||||
#define PM860X_AUDIO_CAL_2 0x33
|
||||
#define PM860X_AUDIO_CAL_3 0x34
|
||||
#define PM860X_AUDIO_CAL_4 0x35
|
||||
#define PM860X_AUDIO_CAL_5 0x36
|
||||
#define PM860X_ANA_INPUT_SEL_1 0x37
|
||||
#define PM860X_ANA_INPUT_SEL_2 0x38
|
||||
#define PM860X_I2S_IFACE_1 0xbb
|
||||
#define PM860X_I2S_IFACE_2 0xbc
|
||||
#define PM860X_I2S_IFACE_3 0xbd
|
||||
#define PM860X_I2S_IFACE_4 0xbe
|
||||
#define PM860X_EQUALIZER_N0_1 0xbf
|
||||
#define PM860X_EQUALIZER_N0_2 0xc0
|
||||
#define PM860X_EQUALIZER_N1_1 0xc1
|
||||
#define PM860X_EQUALIZER_N1_2 0xc2
|
||||
#define PM860X_EQUALIZER_D1_1 0xc3
|
||||
#define PM860X_EQUALIZER_D1_2 0xc4
|
||||
#define PM860X_LOFI_GAIN_LEFT 0xc5
|
||||
#define PM860X_LOFI_GAIN_RIGHT 0xc6
|
||||
#define PM860X_HIFIL_GAIN_LEFT 0xc7
|
||||
#define PM860X_HIFIL_GAIN_RIGHT 0xc8
|
||||
#define PM860X_HIFIR_GAIN_LEFT 0xc9
|
||||
#define PM860X_HIFIR_GAIN_RIGHT 0xca
|
||||
#define PM860X_DAC_OFFSET 0xcb
|
||||
#define PM860X_OFFSET_LEFT_1 0xcc
|
||||
#define PM860X_OFFSET_LEFT_2 0xcd
|
||||
#define PM860X_OFFSET_RIGHT_1 0xce
|
||||
#define PM860X_OFFSET_RIGHT_2 0xcf
|
||||
#define PM860X_ADC_ANA_1 0xd0
|
||||
#define PM860X_ADC_ANA_2 0xd1
|
||||
#define PM860X_ADC_ANA_3 0xd2
|
||||
#define PM860X_ADC_ANA_4 0xd3
|
||||
#define PM860X_ANA_TO_ANA 0xd4
|
||||
#define PM860X_HS1_CTRL 0xd5
|
||||
#define PM860X_HS2_CTRL 0xd6
|
||||
#define PM860X_LO1_CTRL 0xd7
|
||||
#define PM860X_LO2_CTRL 0xd8
|
||||
#define PM860X_EAR_CTRL_1 0xd9
|
||||
#define PM860X_EAR_CTRL_2 0xda
|
||||
#define PM860X_AUDIO_SUPPLIES_1 0xdb
|
||||
#define PM860X_AUDIO_SUPPLIES_2 0xdc
|
||||
#define PM860X_ADC_EN_1 0xdd
|
||||
#define PM860X_ADC_EN_2 0xde
|
||||
#define PM860X_DAC_EN_1 0xdf
|
||||
#define PM860X_DAC_EN_2 0xe1
|
||||
#define PM860X_AUDIO_CAL_1 0xe2
|
||||
#define PM860X_AUDIO_CAL_2 0xe3
|
||||
#define PM860X_AUDIO_CAL_3 0xe4
|
||||
#define PM860X_AUDIO_CAL_4 0xe5
|
||||
#define PM860X_AUDIO_CAL_5 0xe6
|
||||
#define PM860X_ANA_INPUT_SEL_1 0xe7
|
||||
#define PM860X_ANA_INPUT_SEL_2 0xe8
|
||||
|
||||
#define PM860X_PCM_IFACE_4 0x39
|
||||
#define PM860X_I2S_IFACE_5 0x3a
|
||||
#define PM860X_PCM_IFACE_4 0xe9
|
||||
#define PM860X_I2S_IFACE_5 0xea
|
||||
|
||||
#define PM860X_SHORTS 0x3b
|
||||
#define PM860X_PLL_ADJ_1 0x3c
|
||||
|
|
|
@ -2532,12 +2532,10 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
|
|||
}
|
||||
|
||||
/* Override HW-defaults */
|
||||
ab8500_codec_write_reg(codec,
|
||||
AB8500_ANACONF5,
|
||||
BIT(AB8500_ANACONF5_HSAUTOEN));
|
||||
ab8500_codec_write_reg(codec,
|
||||
AB8500_SHORTCIRCONF,
|
||||
BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
|
||||
snd_soc_write(codec, AB8500_ANACONF5,
|
||||
BIT(AB8500_ANACONF5_HSAUTOEN));
|
||||
snd_soc_write(codec, AB8500_SHORTCIRCONF,
|
||||
BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
|
||||
|
||||
/* Add filter controls */
|
||||
status = snd_soc_add_codec_controls(codec, ab8500_filter_controls,
|
||||
|
@ -2606,7 +2604,7 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)
|
|||
|
||||
static int ab8500_codec_driver_remove(struct platform_device *pdev)
|
||||
{
|
||||
dev_info(&pdev->dev, "%s Enter.\n", __func__);
|
||||
dev_dbg(&pdev->dev, "%s Enter.\n", __func__);
|
||||
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ struct adau1373_dai {
|
|||
};
|
||||
|
||||
struct adau1373 {
|
||||
struct regmap *regmap;
|
||||
struct adau1373_dai dais[3];
|
||||
};
|
||||
|
||||
|
@ -73,7 +74,6 @@ struct adau1373 {
|
|||
#define ADAU1373_PLL_CTRL4(x) (0x2c + (x) * 7)
|
||||
#define ADAU1373_PLL_CTRL5(x) (0x2d + (x) * 7)
|
||||
#define ADAU1373_PLL_CTRL6(x) (0x2e + (x) * 7)
|
||||
#define ADAU1373_PLL_CTRL7(x) (0x2f + (x) * 7)
|
||||
#define ADAU1373_HEADDECT 0x36
|
||||
#define ADAU1373_ADC_DAC_STATUS 0x37
|
||||
#define ADAU1373_ADC_CTRL 0x3c
|
||||
|
@ -152,37 +152,172 @@ struct adau1373 {
|
|||
#define ADAU1373_EP_CTRL_MICBIAS1_OFFSET 4
|
||||
#define ADAU1373_EP_CTRL_MICBIAS2_OFFSET 2
|
||||
|
||||
static const uint8_t adau1373_default_regs[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* 0x30 */
|
||||
0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x00, /* 0x40 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x80 */
|
||||
0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00,
|
||||
0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x90 */
|
||||
0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00,
|
||||
0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0xa0 */
|
||||
0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, /* 0xe0 */
|
||||
0x00, 0x1f, 0x0f, 0x00, 0x00,
|
||||
static const struct reg_default adau1373_reg_defaults[] = {
|
||||
{ ADAU1373_INPUT_MODE, 0x00 },
|
||||
{ ADAU1373_AINL_CTRL(0), 0x00 },
|
||||
{ ADAU1373_AINR_CTRL(0), 0x00 },
|
||||
{ ADAU1373_AINL_CTRL(1), 0x00 },
|
||||
{ ADAU1373_AINR_CTRL(1), 0x00 },
|
||||
{ ADAU1373_AINL_CTRL(2), 0x00 },
|
||||
{ ADAU1373_AINR_CTRL(2), 0x00 },
|
||||
{ ADAU1373_AINL_CTRL(3), 0x00 },
|
||||
{ ADAU1373_AINR_CTRL(3), 0x00 },
|
||||
{ ADAU1373_LLINE_OUT(0), 0x00 },
|
||||
{ ADAU1373_RLINE_OUT(0), 0x00 },
|
||||
{ ADAU1373_LLINE_OUT(1), 0x00 },
|
||||
{ ADAU1373_RLINE_OUT(1), 0x00 },
|
||||
{ ADAU1373_LSPK_OUT, 0x00 },
|
||||
{ ADAU1373_RSPK_OUT, 0x00 },
|
||||
{ ADAU1373_LHP_OUT, 0x00 },
|
||||
{ ADAU1373_RHP_OUT, 0x00 },
|
||||
{ ADAU1373_ADC_GAIN, 0x00 },
|
||||
{ ADAU1373_LADC_MIXER, 0x00 },
|
||||
{ ADAU1373_RADC_MIXER, 0x00 },
|
||||
{ ADAU1373_LLINE1_MIX, 0x00 },
|
||||
{ ADAU1373_RLINE1_MIX, 0x00 },
|
||||
{ ADAU1373_LLINE2_MIX, 0x00 },
|
||||
{ ADAU1373_RLINE2_MIX, 0x00 },
|
||||
{ ADAU1373_LSPK_MIX, 0x00 },
|
||||
{ ADAU1373_RSPK_MIX, 0x00 },
|
||||
{ ADAU1373_LHP_MIX, 0x00 },
|
||||
{ ADAU1373_RHP_MIX, 0x00 },
|
||||
{ ADAU1373_EP_MIX, 0x00 },
|
||||
{ ADAU1373_HP_CTRL, 0x00 },
|
||||
{ ADAU1373_HP_CTRL2, 0x00 },
|
||||
{ ADAU1373_LS_CTRL, 0x00 },
|
||||
{ ADAU1373_EP_CTRL, 0x00 },
|
||||
{ ADAU1373_MICBIAS_CTRL1, 0x00 },
|
||||
{ ADAU1373_MICBIAS_CTRL2, 0x00 },
|
||||
{ ADAU1373_OUTPUT_CTRL, 0x00 },
|
||||
{ ADAU1373_PWDN_CTRL1, 0x00 },
|
||||
{ ADAU1373_PWDN_CTRL2, 0x00 },
|
||||
{ ADAU1373_PWDN_CTRL3, 0x00 },
|
||||
{ ADAU1373_DPLL_CTRL(0), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL1(0), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL2(0), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL3(0), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL4(0), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL5(0), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL6(0), 0x02 },
|
||||
{ ADAU1373_DPLL_CTRL(1), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL1(1), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL2(1), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL3(1), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL4(1), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL5(1), 0x00 },
|
||||
{ ADAU1373_PLL_CTRL6(1), 0x02 },
|
||||
{ ADAU1373_HEADDECT, 0x00 },
|
||||
{ ADAU1373_ADC_CTRL, 0x00 },
|
||||
{ ADAU1373_CLK_SRC_DIV(0), 0x00 },
|
||||
{ ADAU1373_CLK_SRC_DIV(1), 0x00 },
|
||||
{ ADAU1373_DAI(0), 0x0a },
|
||||
{ ADAU1373_DAI(1), 0x0a },
|
||||
{ ADAU1373_DAI(2), 0x0a },
|
||||
{ ADAU1373_BCLKDIV(0), 0x00 },
|
||||
{ ADAU1373_BCLKDIV(1), 0x00 },
|
||||
{ ADAU1373_BCLKDIV(2), 0x00 },
|
||||
{ ADAU1373_SRC_RATIOA(0), 0x00 },
|
||||
{ ADAU1373_SRC_RATIOB(0), 0x00 },
|
||||
{ ADAU1373_SRC_RATIOA(1), 0x00 },
|
||||
{ ADAU1373_SRC_RATIOB(1), 0x00 },
|
||||
{ ADAU1373_SRC_RATIOA(2), 0x00 },
|
||||
{ ADAU1373_SRC_RATIOB(2), 0x00 },
|
||||
{ ADAU1373_DEEMP_CTRL, 0x00 },
|
||||
{ ADAU1373_SRC_DAI_CTRL(0), 0x08 },
|
||||
{ ADAU1373_SRC_DAI_CTRL(1), 0x08 },
|
||||
{ ADAU1373_SRC_DAI_CTRL(2), 0x08 },
|
||||
{ ADAU1373_DIN_MIX_CTRL(0), 0x00 },
|
||||
{ ADAU1373_DIN_MIX_CTRL(1), 0x00 },
|
||||
{ ADAU1373_DIN_MIX_CTRL(2), 0x00 },
|
||||
{ ADAU1373_DIN_MIX_CTRL(3), 0x00 },
|
||||
{ ADAU1373_DIN_MIX_CTRL(4), 0x00 },
|
||||
{ ADAU1373_DOUT_MIX_CTRL(0), 0x00 },
|
||||
{ ADAU1373_DOUT_MIX_CTRL(1), 0x00 },
|
||||
{ ADAU1373_DOUT_MIX_CTRL(2), 0x00 },
|
||||
{ ADAU1373_DOUT_MIX_CTRL(3), 0x00 },
|
||||
{ ADAU1373_DOUT_MIX_CTRL(4), 0x00 },
|
||||
{ ADAU1373_DAI_PBL_VOL(0), 0x00 },
|
||||
{ ADAU1373_DAI_PBR_VOL(0), 0x00 },
|
||||
{ ADAU1373_DAI_PBL_VOL(1), 0x00 },
|
||||
{ ADAU1373_DAI_PBR_VOL(1), 0x00 },
|
||||
{ ADAU1373_DAI_PBL_VOL(2), 0x00 },
|
||||
{ ADAU1373_DAI_PBR_VOL(2), 0x00 },
|
||||
{ ADAU1373_DAI_RECL_VOL(0), 0x00 },
|
||||
{ ADAU1373_DAI_RECR_VOL(0), 0x00 },
|
||||
{ ADAU1373_DAI_RECL_VOL(1), 0x00 },
|
||||
{ ADAU1373_DAI_RECR_VOL(1), 0x00 },
|
||||
{ ADAU1373_DAI_RECL_VOL(2), 0x00 },
|
||||
{ ADAU1373_DAI_RECR_VOL(2), 0x00 },
|
||||
{ ADAU1373_DAC1_PBL_VOL, 0x00 },
|
||||
{ ADAU1373_DAC1_PBR_VOL, 0x00 },
|
||||
{ ADAU1373_DAC2_PBL_VOL, 0x00 },
|
||||
{ ADAU1373_DAC2_PBR_VOL, 0x00 },
|
||||
{ ADAU1373_ADC_RECL_VOL, 0x00 },
|
||||
{ ADAU1373_ADC_RECR_VOL, 0x00 },
|
||||
{ ADAU1373_DMIC_RECL_VOL, 0x00 },
|
||||
{ ADAU1373_DMIC_RECR_VOL, 0x00 },
|
||||
{ ADAU1373_VOL_GAIN1, 0x00 },
|
||||
{ ADAU1373_VOL_GAIN2, 0x00 },
|
||||
{ ADAU1373_VOL_GAIN3, 0x00 },
|
||||
{ ADAU1373_HPF_CTRL, 0x00 },
|
||||
{ ADAU1373_BASS1, 0x00 },
|
||||
{ ADAU1373_BASS2, 0x00 },
|
||||
{ ADAU1373_DRC(0) + 0x0, 0x78 },
|
||||
{ ADAU1373_DRC(0) + 0x1, 0x18 },
|
||||
{ ADAU1373_DRC(0) + 0x2, 0x00 },
|
||||
{ ADAU1373_DRC(0) + 0x3, 0x00 },
|
||||
{ ADAU1373_DRC(0) + 0x4, 0x00 },
|
||||
{ ADAU1373_DRC(0) + 0x5, 0xc0 },
|
||||
{ ADAU1373_DRC(0) + 0x6, 0x00 },
|
||||
{ ADAU1373_DRC(0) + 0x7, 0x00 },
|
||||
{ ADAU1373_DRC(0) + 0x8, 0x00 },
|
||||
{ ADAU1373_DRC(0) + 0x9, 0xc0 },
|
||||
{ ADAU1373_DRC(0) + 0xa, 0x88 },
|
||||
{ ADAU1373_DRC(0) + 0xb, 0x7a },
|
||||
{ ADAU1373_DRC(0) + 0xc, 0xdf },
|
||||
{ ADAU1373_DRC(0) + 0xd, 0x20 },
|
||||
{ ADAU1373_DRC(0) + 0xe, 0x00 },
|
||||
{ ADAU1373_DRC(0) + 0xf, 0x00 },
|
||||
{ ADAU1373_DRC(1) + 0x0, 0x78 },
|
||||
{ ADAU1373_DRC(1) + 0x1, 0x18 },
|
||||
{ ADAU1373_DRC(1) + 0x2, 0x00 },
|
||||
{ ADAU1373_DRC(1) + 0x3, 0x00 },
|
||||
{ ADAU1373_DRC(1) + 0x4, 0x00 },
|
||||
{ ADAU1373_DRC(1) + 0x5, 0xc0 },
|
||||
{ ADAU1373_DRC(1) + 0x6, 0x00 },
|
||||
{ ADAU1373_DRC(1) + 0x7, 0x00 },
|
||||
{ ADAU1373_DRC(1) + 0x8, 0x00 },
|
||||
{ ADAU1373_DRC(1) + 0x9, 0xc0 },
|
||||
{ ADAU1373_DRC(1) + 0xa, 0x88 },
|
||||
{ ADAU1373_DRC(1) + 0xb, 0x7a },
|
||||
{ ADAU1373_DRC(1) + 0xc, 0xdf },
|
||||
{ ADAU1373_DRC(1) + 0xd, 0x20 },
|
||||
{ ADAU1373_DRC(1) + 0xe, 0x00 },
|
||||
{ ADAU1373_DRC(1) + 0xf, 0x00 },
|
||||
{ ADAU1373_DRC(2) + 0x0, 0x78 },
|
||||
{ ADAU1373_DRC(2) + 0x1, 0x18 },
|
||||
{ ADAU1373_DRC(2) + 0x2, 0x00 },
|
||||
{ ADAU1373_DRC(2) + 0x3, 0x00 },
|
||||
{ ADAU1373_DRC(2) + 0x4, 0x00 },
|
||||
{ ADAU1373_DRC(2) + 0x5, 0xc0 },
|
||||
{ ADAU1373_DRC(2) + 0x6, 0x00 },
|
||||
{ ADAU1373_DRC(2) + 0x7, 0x00 },
|
||||
{ ADAU1373_DRC(2) + 0x8, 0x00 },
|
||||
{ ADAU1373_DRC(2) + 0x9, 0xc0 },
|
||||
{ ADAU1373_DRC(2) + 0xa, 0x88 },
|
||||
{ ADAU1373_DRC(2) + 0xb, 0x7a },
|
||||
{ ADAU1373_DRC(2) + 0xc, 0xdf },
|
||||
{ ADAU1373_DRC(2) + 0xd, 0x20 },
|
||||
{ ADAU1373_DRC(2) + 0xe, 0x00 },
|
||||
{ ADAU1373_DRC(2) + 0xf, 0x00 },
|
||||
{ ADAU1373_3D_CTRL1, 0x00 },
|
||||
{ ADAU1373_3D_CTRL2, 0x00 },
|
||||
{ ADAU1373_FDSP_SEL1, 0x00 },
|
||||
{ ADAU1373_FDSP_SEL2, 0x00 },
|
||||
{ ADAU1373_FDSP_SEL2, 0x00 },
|
||||
{ ADAU1373_FDSP_SEL4, 0x00 },
|
||||
{ ADAU1373_DIGMICCTRL, 0x00 },
|
||||
{ ADAU1373_DIGEN, 0x00 },
|
||||
};
|
||||
|
||||
static const unsigned int adau1373_out_tlv[] = {
|
||||
|
@ -418,6 +553,7 @@ 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 adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int pll_id = w->name[3] - '1';
|
||||
unsigned int val;
|
||||
|
||||
|
@ -426,7 +562,7 @@ static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
|
|||
else
|
||||
val = 0;
|
||||
|
||||
snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id),
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),
|
||||
ADAU1373_PLL_CTRL6_PLL_EN, val);
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event))
|
||||
|
@ -938,7 +1074,7 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
adau1373_dai->enable_src = (div != 0);
|
||||
|
||||
snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id),
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id),
|
||||
ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,
|
||||
(div << 2) | ADAU1373_BCLKDIV_64);
|
||||
|
||||
|
@ -959,7 +1095,7 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
return snd_soc_update_bits(codec, ADAU1373_DAI(dai->id),
|
||||
return regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id),
|
||||
ADAU1373_DAI_WLEN_MASK, ctrl);
|
||||
}
|
||||
|
||||
|
@ -1016,7 +1152,7 @@ static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, ADAU1373_DAI(dai->id),
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id),
|
||||
~ADAU1373_DAI_WLEN_MASK, ctrl);
|
||||
|
||||
return 0;
|
||||
|
@ -1039,7 +1175,7 @@ static int adau1373_set_dai_sysclk(struct snd_soc_dai *dai,
|
|||
adau1373_dai->sysclk = freq;
|
||||
adau1373_dai->clk_src = clk_id;
|
||||
|
||||
snd_soc_update_bits(dai->codec, ADAU1373_BCLKDIV(dai->id),
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id),
|
||||
ADAU1373_BCLKDIV_SOURCE, clk_id << 5);
|
||||
|
||||
return 0;
|
||||
|
@ -1120,6 +1256,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {
|
|||
static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
|
||||
int source, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int dpll_div = 0;
|
||||
unsigned int x, r, n, m, i, j, mode;
|
||||
|
||||
|
@ -1187,36 +1324,36 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
|
|||
|
||||
if (dpll_div) {
|
||||
dpll_div = 11 - dpll_div;
|
||||
snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id),
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),
|
||||
ADAU1373_PLL_CTRL6_DPLL_BYPASS, 0);
|
||||
} else {
|
||||
snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id),
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),
|
||||
ADAU1373_PLL_CTRL6_DPLL_BYPASS,
|
||||
ADAU1373_PLL_CTRL6_DPLL_BYPASS);
|
||||
}
|
||||
|
||||
snd_soc_write(codec, ADAU1373_DPLL_CTRL(pll_id),
|
||||
regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id),
|
||||
(source << 4) | dpll_div);
|
||||
snd_soc_write(codec, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
|
||||
snd_soc_write(codec, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
|
||||
snd_soc_write(codec, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
|
||||
snd_soc_write(codec, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
|
||||
snd_soc_write(codec, ADAU1373_PLL_CTRL5(pll_id),
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
|
||||
regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id),
|
||||
(r << 3) | (x << 1) | mode);
|
||||
|
||||
/* Set sysclk to pll_rate / 4 */
|
||||
snd_soc_update_bits(codec, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adau1373_load_drc_settings(struct snd_soc_codec *codec,
|
||||
static void adau1373_load_drc_settings(struct adau1373 *adau1373,
|
||||
unsigned int nr, uint8_t *drc)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ADAU1373_DRC_SIZE; ++i)
|
||||
snd_soc_write(codec, ADAU1373_DRC(nr) + i, drc[i]);
|
||||
regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]);
|
||||
}
|
||||
|
||||
static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
|
||||
|
@ -1235,13 +1372,14 @@ static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
|
|||
|
||||
static int adau1373_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
struct adau1373_platform_data *pdata = codec->dev->platform_data;
|
||||
bool lineout_differential = false;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -1256,7 +1394,7 @@ static int adau1373_probe(struct snd_soc_codec *codec)
|
|||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < pdata->num_drc; ++i) {
|
||||
adau1373_load_drc_settings(codec, i,
|
||||
adau1373_load_drc_settings(adau1373, i,
|
||||
pdata->drc_setting[i]);
|
||||
}
|
||||
|
||||
|
@ -1268,18 +1406,18 @@ static int adau1373_probe(struct snd_soc_codec *codec)
|
|||
if (pdata->input_differential[i])
|
||||
val |= BIT(i);
|
||||
}
|
||||
snd_soc_write(codec, ADAU1373_INPUT_MODE, val);
|
||||
regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val);
|
||||
|
||||
val = 0;
|
||||
if (pdata->lineout_differential)
|
||||
val |= ADAU1373_OUTPUT_CTRL_LDIFF;
|
||||
if (pdata->lineout_ground_sense)
|
||||
val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
|
||||
snd_soc_write(codec, ADAU1373_OUTPUT_CTRL, val);
|
||||
regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);
|
||||
|
||||
lineout_differential = pdata->lineout_differential;
|
||||
|
||||
snd_soc_write(codec, ADAU1373_EP_CTRL,
|
||||
regmap_write(adau1373->regmap, ADAU1373_EP_CTRL,
|
||||
(pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
|
||||
(pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
|
||||
}
|
||||
|
@ -1289,7 +1427,7 @@ static int adau1373_probe(struct snd_soc_codec *codec)
|
|||
ARRAY_SIZE(adau1373_lineout2_controls));
|
||||
}
|
||||
|
||||
snd_soc_write(codec, ADAU1373_ADC_CTRL,
|
||||
regmap_write(adau1373->regmap, ADAU1373_ADC_CTRL,
|
||||
ADAU1373_ADC_CTRL_RESET_FORCE | ADAU1373_ADC_CTRL_PEAK_DETECT);
|
||||
|
||||
return 0;
|
||||
|
@ -1298,17 +1436,19 @@ static int adau1373_probe(struct snd_soc_codec *codec)
|
|||
static int adau1373_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3,
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3,
|
||||
ADAU1373_PWDN_CTRL3_PWR_EN, ADAU1373_PWDN_CTRL3_PWR_EN);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3,
|
||||
regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3,
|
||||
ADAU1373_PWDN_CTRL3_PWR_EN, 0);
|
||||
break;
|
||||
}
|
||||
|
@ -1324,17 +1464,49 @@ static int adau1373_remove(struct snd_soc_codec *codec)
|
|||
|
||||
static int adau1373_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
return adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
regcache_cache_only(adau1373->regmap, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adau1373_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regcache_cache_only(adau1373->regmap, false);
|
||||
adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
snd_soc_cache_sync(codec);
|
||||
regcache_sync(adau1373->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool adau1373_register_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADAU1373_SOFT_RESET:
|
||||
case ADAU1373_ADC_DAC_STATUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config adau1373_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 8,
|
||||
|
||||
.volatile_reg = adau1373_register_volatile,
|
||||
.max_register = ADAU1373_SOFT_RESET,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = adau1373_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults),
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_driver adau1373_codec_driver = {
|
||||
.probe = adau1373_probe,
|
||||
.remove = adau1373_remove,
|
||||
|
@ -1342,9 +1514,6 @@ static struct snd_soc_codec_driver adau1373_codec_driver = {
|
|||
.resume = adau1373_resume,
|
||||
.set_bias_level = adau1373_set_bias_level,
|
||||
.idle_bias_off = true,
|
||||
.reg_cache_size = ARRAY_SIZE(adau1373_default_regs),
|
||||
.reg_cache_default = adau1373_default_regs,
|
||||
.reg_word_size = sizeof(uint8_t),
|
||||
|
||||
.set_pll = adau1373_set_pll,
|
||||
|
||||
|
@ -1366,6 +1535,13 @@ static int adau1373_i2c_probe(struct i2c_client *client,
|
|||
if (!adau1373)
|
||||
return -ENOMEM;
|
||||
|
||||
adau1373->regmap = devm_regmap_init_i2c(client,
|
||||
&adau1373_regmap_config);
|
||||
if (IS_ERR(adau1373->regmap))
|
||||
return PTR_ERR(adau1373->regmap);
|
||||
|
||||
regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00);
|
||||
|
||||
dev_set_drvdata(&client->dev, adau1373);
|
||||
|
||||
ret = snd_soc_register_codec(&client->dev, &adau1373_codec_driver,
|
||||
|
|
|
@ -115,22 +115,34 @@
|
|||
|
||||
#define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x))
|
||||
|
||||
static u8 adav80x_default_regs[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00,
|
||||
0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37,
|
||||
0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b,
|
||||
0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00,
|
||||
0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee,
|
||||
0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x52, 0x00,
|
||||
static struct reg_default adav80x_reg_defaults[] = {
|
||||
{ ADAV80X_PLAYBACK_CTRL, 0x01 },
|
||||
{ ADAV80X_AUX_IN_CTRL, 0x01 },
|
||||
{ ADAV80X_REC_CTRL, 0x02 },
|
||||
{ ADAV80X_AUX_OUT_CTRL, 0x01 },
|
||||
{ ADAV80X_DPATH_CTRL1, 0xc0 },
|
||||
{ ADAV80X_DPATH_CTRL2, 0x11 },
|
||||
{ ADAV80X_DAC_CTRL1, 0x00 },
|
||||
{ ADAV80X_DAC_CTRL2, 0x00 },
|
||||
{ ADAV80X_DAC_CTRL3, 0x00 },
|
||||
{ ADAV80X_DAC_L_VOL, 0xff },
|
||||
{ ADAV80X_DAC_R_VOL, 0xff },
|
||||
{ ADAV80X_PGA_L_VOL, 0x00 },
|
||||
{ ADAV80X_PGA_R_VOL, 0x00 },
|
||||
{ ADAV80X_ADC_CTRL1, 0x00 },
|
||||
{ ADAV80X_ADC_CTRL2, 0x00 },
|
||||
{ ADAV80X_ADC_L_VOL, 0xff },
|
||||
{ ADAV80X_ADC_R_VOL, 0xff },
|
||||
{ ADAV80X_PLL_CTRL1, 0x00 },
|
||||
{ ADAV80X_PLL_CTRL2, 0x00 },
|
||||
{ ADAV80X_ICLK_CTRL1, 0x00 },
|
||||
{ ADAV80X_ICLK_CTRL2, 0x00 },
|
||||
{ ADAV80X_PLL_CLK_SRC, 0x00 },
|
||||
{ ADAV80X_PLL_OUTE, 0x00 },
|
||||
};
|
||||
|
||||
struct adav80x {
|
||||
enum snd_soc_control_type control_type;
|
||||
struct regmap *regmap;
|
||||
|
||||
enum adav80x_clk_src clk_src;
|
||||
unsigned int sysclk;
|
||||
|
@ -298,7 +310,7 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec)
|
|||
val = ADAV80X_DAC_CTRL2_DEEMPH_NONE;
|
||||
}
|
||||
|
||||
return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2,
|
||||
return regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,
|
||||
ADAV80X_DAC_CTRL2_DEEMPH_MASK, val);
|
||||
}
|
||||
|
||||
|
@ -394,10 +406,11 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0],
|
||||
regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],
|
||||
ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER,
|
||||
capture);
|
||||
snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback);
|
||||
regmap_write(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1],
|
||||
playback);
|
||||
|
||||
adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
|
||||
|
@ -407,6 +420,7 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
|
||||
unsigned int sample_rate)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
if (sample_rate <= 48000)
|
||||
|
@ -414,7 +428,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
|
|||
else
|
||||
val = ADAV80X_ADC_CTRL1_MODULATOR_64FS;
|
||||
|
||||
snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1,
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_ADC_CTRL1,
|
||||
ADAV80X_ADC_CTRL1_MODULATOR_MASK, val);
|
||||
|
||||
return 0;
|
||||
|
@ -423,6 +437,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
|
|||
static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
|
||||
unsigned int sample_rate)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
if (sample_rate <= 48000)
|
||||
|
@ -430,7 +445,7 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
|
|||
else
|
||||
val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS;
|
||||
|
||||
snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2,
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,
|
||||
ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK,
|
||||
val);
|
||||
|
||||
|
@ -440,6 +455,7 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
|
|||
static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec,
|
||||
struct snd_soc_dai *dai, snd_pcm_format_t format)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int val;
|
||||
|
||||
switch (format) {
|
||||
|
@ -459,7 +475,7 @@ static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0],
|
||||
regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],
|
||||
ADAV80X_CAPTURE_WORD_LEN_MASK, val);
|
||||
|
||||
return 0;
|
||||
|
@ -491,7 +507,7 @@ static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1],
|
||||
regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1],
|
||||
ADAV80X_PLAYBACK_MODE_MASK, val);
|
||||
|
||||
return 0;
|
||||
|
@ -554,8 +570,10 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
|
|||
ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id);
|
||||
iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id);
|
||||
|
||||
snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1);
|
||||
snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2);
|
||||
regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL1,
|
||||
iclk_ctrl1);
|
||||
regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2,
|
||||
iclk_ctrl2);
|
||||
|
||||
snd_soc_dapm_sync(&codec->dapm);
|
||||
}
|
||||
|
@ -575,10 +593,12 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
|
|||
mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id);
|
||||
|
||||
if (freq == 0) {
|
||||
snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask);
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE,
|
||||
mask, mask);
|
||||
adav80x->sysclk_pd[clk_id] = true;
|
||||
} else {
|
||||
snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0);
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE,
|
||||
mask, 0);
|
||||
adav80x->sysclk_pd[clk_id] = false;
|
||||
}
|
||||
|
||||
|
@ -650,9 +670,9 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV,
|
||||
pll_ctrl1);
|
||||
snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2,
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL1,
|
||||
ADAV80X_PLL_CTRL1_PLLDIV, pll_ctrl1);
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL2,
|
||||
ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2);
|
||||
|
||||
if (source != adav80x->pll_src) {
|
||||
|
@ -661,7 +681,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
|
|||
else
|
||||
pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id);
|
||||
|
||||
snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC,
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CLK_SRC,
|
||||
ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src);
|
||||
|
||||
adav80x->pll_src = source;
|
||||
|
@ -675,6 +695,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
|
|||
static int adav80x_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int mask = ADAV80X_DAC_CTRL1_PD;
|
||||
|
||||
switch (level) {
|
||||
|
@ -683,10 +704,12 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec,
|
|||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00);
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask,
|
||||
0x00);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask);
|
||||
regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask,
|
||||
mask);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -780,7 +803,7 @@ static int adav80x_probe(struct snd_soc_codec *codec)
|
|||
int ret;
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -791,23 +814,31 @@ static int adav80x_probe(struct snd_soc_codec *codec)
|
|||
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
|
||||
|
||||
/* Power down S/PDIF receiver, since it is currently not supported */
|
||||
snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20);
|
||||
regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);
|
||||
/* Disable DAC zero flag */
|
||||
snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6);
|
||||
regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6);
|
||||
|
||||
return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
}
|
||||
|
||||
static int adav80x_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
regcache_cache_only(adav80x->regmap, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adav80x_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regcache_cache_only(adav80x->regmap, false);
|
||||
adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
codec->cache_sync = 1;
|
||||
snd_soc_cache_sync(codec);
|
||||
regcache_sync(adav80x->regmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -827,10 +858,6 @@ static struct snd_soc_codec_driver adav80x_codec_driver = {
|
|||
.set_pll = adav80x_set_pll,
|
||||
.set_sysclk = adav80x_set_sysclk,
|
||||
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_size = ARRAY_SIZE(adav80x_default_regs),
|
||||
.reg_cache_default = adav80x_default_regs,
|
||||
|
||||
.controls = adav80x_controls,
|
||||
.num_controls = ARRAY_SIZE(adav80x_controls),
|
||||
.dapm_widgets = adav80x_dapm_widgets,
|
||||
|
@ -839,18 +866,21 @@ static struct snd_soc_codec_driver adav80x_codec_driver = {
|
|||
.num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes),
|
||||
};
|
||||
|
||||
static int adav80x_bus_probe(struct device *dev,
|
||||
enum snd_soc_control_type control_type)
|
||||
static int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct adav80x *adav80x;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL);
|
||||
if (!adav80x)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
dev_set_drvdata(dev, adav80x);
|
||||
adav80x->control_type = control_type;
|
||||
adav80x->regmap = regmap;
|
||||
|
||||
ret = snd_soc_register_codec(dev, &adav80x_codec_driver,
|
||||
adav80x_dais, ARRAY_SIZE(adav80x_dais));
|
||||
|
@ -868,6 +898,19 @@ static int adav80x_bus_remove(struct device *dev)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static const struct regmap_config adav80x_spi_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.pad_bits = 1,
|
||||
.reg_bits = 7,
|
||||
.read_flag_mask = 0x01,
|
||||
|
||||
.max_register = ADAV80X_PLL_OUTE,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = adav80x_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
|
||||
};
|
||||
|
||||
static const struct spi_device_id adav80x_spi_id[] = {
|
||||
{ "adav801", 0 },
|
||||
{ }
|
||||
|
@ -876,7 +919,8 @@ MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
|
|||
|
||||
static int adav80x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
return adav80x_bus_probe(&spi->dev, SND_SOC_SPI);
|
||||
return adav80x_bus_probe(&spi->dev,
|
||||
devm_regmap_init_spi(spi, &adav80x_spi_regmap_config));
|
||||
}
|
||||
|
||||
static int adav80x_spi_remove(struct spi_device *spi)
|
||||
|
@ -896,6 +940,18 @@ static struct spi_driver adav80x_spi_driver = {
|
|||
#endif
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static const struct regmap_config adav80x_i2c_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.pad_bits = 1,
|
||||
.reg_bits = 7,
|
||||
|
||||
.max_register = ADAV80X_PLL_OUTE,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = adav80x_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
|
||||
};
|
||||
|
||||
static const struct i2c_device_id adav80x_i2c_id[] = {
|
||||
{ "adav803", 0 },
|
||||
{ }
|
||||
|
@ -905,7 +961,8 @@ MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id);
|
|||
static int adav80x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
return adav80x_bus_probe(&client->dev, SND_SOC_I2C);
|
||||
return adav80x_bus_probe(&client->dev,
|
||||
devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config));
|
||||
}
|
||||
|
||||
static int adav80x_i2c_remove(struct i2c_client *client)
|
||||
|
|
|
@ -45,8 +45,6 @@
|
|||
#define AK4104_TX_TXE (1 << 0)
|
||||
#define AK4104_TX_V (1 << 1)
|
||||
|
||||
#define DRV_NAME "ak4104-codec"
|
||||
|
||||
struct ak4104_private {
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
@ -291,12 +289,19 @@ static const struct of_device_id ak4104_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, ak4104_of_match);
|
||||
|
||||
static const struct spi_device_id ak4104_id_table[] = {
|
||||
{ "ak4104", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ak4104_id_table);
|
||||
|
||||
static struct spi_driver ak4104_spi_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.name = "ak4104",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ak4104_of_match,
|
||||
},
|
||||
.id_table = ak4104_id_table,
|
||||
.probe = ak4104_spi_probe,
|
||||
.remove = ak4104_spi_remove,
|
||||
};
|
||||
|
|
|
@ -352,7 +352,6 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
|||
*/
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
snd_soc_update_bits(codec, MD_CTL1, DIF_MASK, data);
|
||||
|
||||
|
@ -405,7 +404,6 @@ static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
|
|||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate);
|
||||
|
||||
|
|
|
@ -1477,21 +1477,25 @@ static void arizona_enable_fll(struct arizona_fll *fll,
|
|||
{
|
||||
struct arizona *arizona = fll->arizona;
|
||||
int ret;
|
||||
bool use_sync = false;
|
||||
|
||||
/*
|
||||
* If we have both REFCLK and SYNCCLK then enable both,
|
||||
* otherwise apply the SYNCCLK settings to REFCLK.
|
||||
*/
|
||||
if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
|
||||
if (fll->ref_src >= 0 && fll->ref_freq &&
|
||||
fll->ref_src != fll->sync_src) {
|
||||
regmap_update_bits(arizona->regmap, fll->base + 5,
|
||||
ARIZONA_FLL1_OUTDIV_MASK,
|
||||
ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
|
||||
|
||||
arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
|
||||
false);
|
||||
if (fll->sync_src >= 0)
|
||||
if (fll->sync_src >= 0) {
|
||||
arizona_apply_fll(arizona, fll->base + 0x10, sync,
|
||||
fll->sync_src, true);
|
||||
use_sync = true;
|
||||
}
|
||||
} else if (fll->sync_src >= 0) {
|
||||
regmap_update_bits(arizona->regmap, fll->base + 5,
|
||||
ARIZONA_FLL1_OUTDIV_MASK,
|
||||
|
@ -1511,7 +1515,7 @@ static void arizona_enable_fll(struct arizona_fll *fll,
|
|||
* Increase the bandwidth if we're not using a low frequency
|
||||
* sync source.
|
||||
*/
|
||||
if (fll->sync_src >= 0 && fll->sync_freq > 100000)
|
||||
if (use_sync && fll->sync_freq > 100000)
|
||||
regmap_update_bits(arizona->regmap, fll->base + 0x17,
|
||||
ARIZONA_FLL1_SYNC_BW, 0);
|
||||
else
|
||||
|
@ -1526,8 +1530,7 @@ static void arizona_enable_fll(struct arizona_fll *fll,
|
|||
|
||||
regmap_update_bits(arizona->regmap, fll->base + 1,
|
||||
ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
|
||||
if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
|
||||
fll->ref_src != fll->sync_src)
|
||||
if (use_sync)
|
||||
regmap_update_bits(arizona->regmap, fll->base + 0x11,
|
||||
ARIZONA_FLL1_SYNC_ENA,
|
||||
ARIZONA_FLL1_SYNC_ENA);
|
||||
|
@ -1561,10 +1564,12 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
|
|||
if (fll->ref_src == source && fll->ref_freq == Fref)
|
||||
return 0;
|
||||
|
||||
if (fll->fout && Fref > 0) {
|
||||
ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (fll->fout) {
|
||||
if (Fref > 0) {
|
||||
ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fll->sync_src >= 0) {
|
||||
ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
|
||||
|
|
|
@ -38,24 +38,6 @@
|
|||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct davinci_vc *davinci_vc = codec->control_data;
|
||||
|
||||
return readl(davinci_vc->base + reg);
|
||||
}
|
||||
|
||||
static inline int cq93vc_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct davinci_vc *davinci_vc = codec->control_data;
|
||||
|
||||
writel(value, davinci_vc->base + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new cq93vc_snd_controls[] = {
|
||||
SOC_SINGLE("PGA Capture Volume", DAVINCI_VC_REG05, 0, 0x03, 0),
|
||||
SOC_SINGLE("Mono DAC Playback Volume", DAVINCI_VC_REG09, 0, 0x3f, 0),
|
||||
|
@ -64,13 +46,15 @@ static const struct snd_kcontrol_new cq93vc_snd_controls[] = {
|
|||
static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
u8 reg = cq93vc_read(codec, DAVINCI_VC_REG09) & ~DAVINCI_VC_REG09_MUTE;
|
||||
u8 reg;
|
||||
|
||||
if (mute)
|
||||
cq93vc_write(codec, DAVINCI_VC_REG09,
|
||||
reg | DAVINCI_VC_REG09_MUTE);
|
||||
reg = DAVINCI_VC_REG09_MUTE;
|
||||
else
|
||||
cq93vc_write(codec, DAVINCI_VC_REG09, reg);
|
||||
reg = 0;
|
||||
|
||||
snd_soc_update_bits(codec, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE,
|
||||
reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -79,7 +63,7 @@ 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->control_data;
|
||||
struct davinci_vc *davinci_vc = codec->dev->platform_data;
|
||||
|
||||
switch (freq) {
|
||||
case 22579200:
|
||||
|
@ -97,18 +81,18 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
|
|||
{
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
cq93vc_write(codec, DAVINCI_VC_REG12,
|
||||
snd_soc_write(codec, DAVINCI_VC_REG12,
|
||||
DAVINCI_VC_REG12_POWER_ALL_ON);
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
cq93vc_write(codec, DAVINCI_VC_REG12,
|
||||
snd_soc_write(codec, DAVINCI_VC_REG12,
|
||||
DAVINCI_VC_REG12_POWER_ALL_OFF);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
/* force all power off */
|
||||
cq93vc_write(codec, DAVINCI_VC_REG12,
|
||||
snd_soc_write(codec, DAVINCI_VC_REG12,
|
||||
DAVINCI_VC_REG12_POWER_ALL_OFF);
|
||||
break;
|
||||
}
|
||||
|
@ -154,11 +138,9 @@ static int cq93vc_probe(struct snd_soc_codec *codec)
|
|||
struct davinci_vc *davinci_vc = codec->dev->platform_data;
|
||||
|
||||
davinci_vc->cq93vc.codec = codec;
|
||||
codec->control_data = davinci_vc;
|
||||
codec->control_data = davinci_vc->regmap;
|
||||
|
||||
/* Set controls */
|
||||
snd_soc_add_codec_controls(codec, cq93vc_snd_controls,
|
||||
ARRAY_SIZE(cq93vc_snd_controls));
|
||||
snd_soc_codec_set_cache_io(codec, 32, 32, SND_SOC_REGMAP);
|
||||
|
||||
/* Off, with power on */
|
||||
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
@ -174,12 +156,12 @@ static int cq93vc_remove(struct snd_soc_codec *codec)
|
|||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
|
||||
.read = cq93vc_read,
|
||||
.write = cq93vc_write,
|
||||
.set_bias_level = cq93vc_set_bias_level,
|
||||
.probe = cq93vc_probe,
|
||||
.remove = cq93vc_remove,
|
||||
.resume = cq93vc_resume,
|
||||
.controls = cq93vc_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
|
||||
};
|
||||
|
||||
static int cq93vc_platform_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#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>
|
||||
#include <sound/pcm.h>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
|
@ -28,6 +29,7 @@
|
|||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/cs42l73.h>
|
||||
#include "cs42l73.h"
|
||||
|
||||
struct sp_config {
|
||||
|
@ -35,6 +37,7 @@ struct sp_config {
|
|||
u32 srate;
|
||||
};
|
||||
struct cs42l73_private {
|
||||
struct cs42l73_platform_data pdata;
|
||||
struct sp_config config[3];
|
||||
struct regmap *regmap;
|
||||
u32 sysclk;
|
||||
|
@ -310,15 +313,6 @@ static const struct soc_enum ng_delay_enum =
|
|||
SOC_ENUM_SINGLE(CS42L73_NGCAB, 0,
|
||||
ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text);
|
||||
|
||||
static const char * const charge_pump_freq_text[] = {
|
||||
"0", "1", "2", "3", "4",
|
||||
"5", "6", "7", "8", "9",
|
||||
"10", "11", "12", "13", "14", "15" };
|
||||
|
||||
static const struct soc_enum charge_pump_enum =
|
||||
SOC_ENUM_SINGLE(CS42L73_CPFCHC, 4,
|
||||
ARRAY_SIZE(charge_pump_freq_text), charge_pump_freq_text);
|
||||
|
||||
static const char * const cs42l73_mono_mix_texts[] = {
|
||||
"Left", "Right", "Mono Mix"};
|
||||
|
||||
|
@ -511,8 +505,6 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
|
|||
SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0),
|
||||
SOC_ENUM("NG Delay", ng_delay_enum),
|
||||
|
||||
SOC_ENUM("Charge Pump Frequency", charge_pump_enum),
|
||||
|
||||
SOC_DOUBLE_R_TLV("XSP-IP Volume",
|
||||
CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1,
|
||||
attn_tlv),
|
||||
|
@ -1055,11 +1047,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
|||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
mmcc |= MS_MASTER;
|
||||
mmcc |= CS42L73_MS_MASTER;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
mmcc &= ~MS_MASTER;
|
||||
mmcc &= ~CS42L73_MS_MASTER;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1071,11 +1063,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
|||
|
||||
switch (format) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
spc &= ~SPDIF_PCM;
|
||||
spc &= ~CS42L73_SPDIF_PCM;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
if (mmcc & MS_MASTER) {
|
||||
if (mmcc & CS42L73_MS_MASTER) {
|
||||
dev_err(codec->dev,
|
||||
"PCM format in slave mode only\n");
|
||||
return -EINVAL;
|
||||
|
@ -1085,25 +1077,25 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
|||
"PCM format is not supported on ASP port\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
spc |= SPDIF_PCM;
|
||||
spc |= CS42L73_SPDIF_PCM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (spc & SPDIF_PCM) {
|
||||
if (spc & CS42L73_SPDIF_PCM) {
|
||||
/* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */
|
||||
spc &= ~(PCM_MODE_MASK | PCM_BIT_ORDER);
|
||||
spc &= ~(CS42L73_PCM_MODE_MASK | CS42L73_PCM_BIT_ORDER);
|
||||
switch (format) {
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
if (inv == SND_SOC_DAIFMT_IB_IF)
|
||||
spc |= PCM_MODE0;
|
||||
spc |= CS42L73_PCM_MODE0;
|
||||
if (inv == SND_SOC_DAIFMT_IB_NF)
|
||||
spc |= PCM_MODE1;
|
||||
spc |= CS42L73_PCM_MODE1;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
if (inv == SND_SOC_DAIFMT_IB_IF)
|
||||
spc |= PCM_MODE1;
|
||||
spc |= CS42L73_PCM_MODE1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -1163,7 +1155,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
int mclk_coeff;
|
||||
int srate = params_rate(params);
|
||||
|
||||
if (priv->config[id].mmcc & MS_MASTER) {
|
||||
if (priv->config[id].mmcc & CS42L73_MS_MASTER) {
|
||||
/* CS42L73 Master */
|
||||
/* MCLK -> srate */
|
||||
mclk_coeff =
|
||||
|
@ -1182,13 +1174,13 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
priv->config[id].spc &= 0xFC;
|
||||
/* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */
|
||||
if (priv->mclk >= 6400000)
|
||||
priv->config[id].spc |= MCK_SCLK_64FS;
|
||||
priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;
|
||||
else
|
||||
priv->config[id].spc |= MCK_SCLK_MCLK;
|
||||
priv->config[id].spc |= CS42L73_MCK_SCLK_MCLK;
|
||||
} else {
|
||||
/* CS42L73 Slave */
|
||||
priv->config[id].spc &= 0xFC;
|
||||
priv->config[id].spc |= MCK_SCLK_64FS;
|
||||
priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;
|
||||
}
|
||||
/* Update ASRCs */
|
||||
priv->config[id].srate = srate;
|
||||
|
@ -1208,8 +1200,8 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
|
|||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 0);
|
||||
snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 0);
|
||||
snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 0);
|
||||
snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 0);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
|
@ -1220,11 +1212,11 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
|
|||
regcache_cache_only(cs42l73->regmap, false);
|
||||
regcache_sync(cs42l73->regmap);
|
||||
}
|
||||
snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1);
|
||||
snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1);
|
||||
snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1);
|
||||
if (cs42l73->shutdwn_delay > 0) {
|
||||
mdelay(cs42l73->shutdwn_delay);
|
||||
cs42l73->shutdwn_delay = 0;
|
||||
|
@ -1233,7 +1225,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
|
|||
* down.
|
||||
*/
|
||||
}
|
||||
snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1);
|
||||
snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
|
@ -1367,11 +1359,16 @@ static int cs42l73_probe(struct snd_soc_codec *codec)
|
|||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(cs42l73->regmap, true);
|
||||
|
||||
cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
cs42l73->mclksel = CS42L73_CLKID_MCLK1; /* MCLK1 as master clk */
|
||||
/* Set Charge Pump Frequency */
|
||||
if (cs42l73->pdata.chgfreq)
|
||||
snd_soc_update_bits(codec, CS42L73_CPFCHC,
|
||||
CS42L73_CHARGEPUMP_MASK,
|
||||
cs42l73->pdata.chgfreq << 4);
|
||||
|
||||
/* MCLK1 as master clk */
|
||||
cs42l73->mclksel = CS42L73_CLKID_MCLK1;
|
||||
cs42l73->mclk = 0;
|
||||
|
||||
return ret;
|
||||
|
@ -1415,9 +1412,11 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct cs42l73_private *cs42l73;
|
||||
struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
|
||||
int ret;
|
||||
unsigned int devid = 0;
|
||||
unsigned int reg;
|
||||
u32 val32;
|
||||
|
||||
cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private),
|
||||
GFP_KERNEL);
|
||||
|
@ -1426,14 +1425,49 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c_client, cs42l73);
|
||||
|
||||
cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap);
|
||||
if (IS_ERR(cs42l73->regmap)) {
|
||||
ret = PTR_ERR(cs42l73->regmap);
|
||||
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
cs42l73->pdata = *pdata;
|
||||
} else {
|
||||
pdata = devm_kzalloc(&i2c_client->dev,
|
||||
sizeof(struct cs42l73_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
dev_err(&i2c_client->dev, "could not allocate pdata\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (i2c_client->dev.of_node) {
|
||||
if (of_property_read_u32(i2c_client->dev.of_node,
|
||||
"chgfreq", &val32) >= 0)
|
||||
pdata->chgfreq = val32;
|
||||
}
|
||||
pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node,
|
||||
"reset-gpio", 0);
|
||||
cs42l73->pdata = *pdata;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c_client, cs42l73);
|
||||
|
||||
if (cs42l73->pdata.reset_gpio) {
|
||||
ret = gpio_request_one(cs42l73->pdata.reset_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "CS42L73 /RST");
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
|
||||
cs42l73->pdata.reset_gpio, ret);
|
||||
return ret;
|
||||
}
|
||||
gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0);
|
||||
gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1);
|
||||
}
|
||||
|
||||
regcache_cache_bypass(cs42l73->regmap, true);
|
||||
|
||||
/* initialize codec */
|
||||
ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®);
|
||||
devid = (reg & 0xFF) << 12;
|
||||
|
@ -1444,7 +1478,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
|
|||
ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, ®);
|
||||
devid |= (reg & 0xF0) >> 4;
|
||||
|
||||
|
||||
if (devid != CS42L73_DEVID) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&i2c_client->dev,
|
||||
|
@ -1462,7 +1495,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
|
|||
dev_info(&i2c_client->dev,
|
||||
"Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF);
|
||||
|
||||
regcache_cache_only(cs42l73->regmap, true);
|
||||
regcache_cache_bypass(cs42l73->regmap, false);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c_client->dev,
|
||||
&soc_codec_dev_cs42l73, cs42l73_dai,
|
||||
|
@ -1478,6 +1511,12 @@ static int cs42l73_i2c_remove(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cs42l73_of_match[] = {
|
||||
{ .compatible = "cirrus,cs42l73", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs42l73_of_match);
|
||||
|
||||
static const struct i2c_device_id cs42l73_id[] = {
|
||||
{"cs42l73", 0},
|
||||
{}
|
||||
|
@ -1489,6 +1528,7 @@ static struct i2c_driver cs42l73_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "cs42l73",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = cs42l73_of_match,
|
||||
},
|
||||
.id_table = cs42l73_id,
|
||||
.probe = cs42l73_i2c_probe,
|
||||
|
|
|
@ -128,59 +128,60 @@
|
|||
/* Bitfield Definitions */
|
||||
|
||||
/* CS42L73_PWRCTL1 */
|
||||
#define PDN_ADCB (1 << 7)
|
||||
#define PDN_DMICB (1 << 6)
|
||||
#define PDN_ADCA (1 << 5)
|
||||
#define PDN_DMICA (1 << 4)
|
||||
#define PDN_LDO (1 << 2)
|
||||
#define DISCHG_FILT (1 << 1)
|
||||
#define PDN (1 << 0)
|
||||
#define CS42L73_PDN_ADCB (1 << 7)
|
||||
#define CS42L73_PDN_DMICB (1 << 6)
|
||||
#define CS42L73_PDN_ADCA (1 << 5)
|
||||
#define CS42L73_PDN_DMICA (1 << 4)
|
||||
#define CS42L73_PDN_LDO (1 << 2)
|
||||
#define CS42L73_DISCHG_FILT (1 << 1)
|
||||
#define CS42L73_PDN (1 << 0)
|
||||
|
||||
/* CS42L73_PWRCTL2 */
|
||||
#define PDN_MIC2_BIAS (1 << 7)
|
||||
#define PDN_MIC1_BIAS (1 << 6)
|
||||
#define PDN_VSP (1 << 4)
|
||||
#define PDN_ASP_SDOUT (1 << 3)
|
||||
#define PDN_ASP_SDIN (1 << 2)
|
||||
#define PDN_XSP_SDOUT (1 << 1)
|
||||
#define PDN_XSP_SDIN (1 << 0)
|
||||
#define CS42L73_PDN_MIC2_BIAS (1 << 7)
|
||||
#define CS42L73_PDN_MIC1_BIAS (1 << 6)
|
||||
#define CS42L73_PDN_VSP (1 << 4)
|
||||
#define CS42L73_PDN_ASP_SDOUT (1 << 3)
|
||||
#define CS42L73_PDN_ASP_SDIN (1 << 2)
|
||||
#define CS42L73_PDN_XSP_SDOUT (1 << 1)
|
||||
#define CS42L73_PDN_XSP_SDIN (1 << 0)
|
||||
|
||||
/* CS42L73_PWRCTL3 */
|
||||
#define PDN_THMS (1 << 5)
|
||||
#define PDN_SPKLO (1 << 4)
|
||||
#define PDN_EAR (1 << 3)
|
||||
#define PDN_SPK (1 << 2)
|
||||
#define PDN_LO (1 << 1)
|
||||
#define PDN_HP (1 << 0)
|
||||
#define CS42L73_PDN_THMS (1 << 5)
|
||||
#define CS42L73_PDN_SPKLO (1 << 4)
|
||||
#define CS42L73_PDN_EAR (1 << 3)
|
||||
#define CS42L73_PDN_SPK (1 << 2)
|
||||
#define CS42L73_PDN_LO (1 << 1)
|
||||
#define CS42L73_PDN_HP (1 << 0)
|
||||
|
||||
/* Thermal Overload Detect. Requires interrupt ... */
|
||||
#define THMOVLD_150C 0
|
||||
#define THMOVLD_132C 1
|
||||
#define THMOVLD_115C 2
|
||||
#define THMOVLD_098C 3
|
||||
#define CS42L73_THMOVLD_150C 0
|
||||
#define CS42L73_THMOVLD_132C 1
|
||||
#define CS42L73_THMOVLD_115C 2
|
||||
#define CS42L73_THMOVLD_098C 3
|
||||
|
||||
#define CS42L73_CHARGEPUMP_MASK (0xF0)
|
||||
|
||||
/* CS42L73_ASPC, CS42L73_XSPC, CS42L73_VSPC */
|
||||
#define SP_3ST (1 << 7)
|
||||
#define SPDIF_I2S (0 << 6)
|
||||
#define SPDIF_PCM (1 << 6)
|
||||
#define PCM_MODE0 (0 << 4)
|
||||
#define PCM_MODE1 (1 << 4)
|
||||
#define PCM_MODE2 (2 << 4)
|
||||
#define PCM_MODE_MASK (3 << 4)
|
||||
#define PCM_BIT_ORDER (1 << 3)
|
||||
#define MCK_SCLK_64FS (0 << 0)
|
||||
#define MCK_SCLK_MCLK (2 << 0)
|
||||
#define MCK_SCLK_PREMCLK (3 << 0)
|
||||
#define CS42L73_SP_3ST (1 << 7)
|
||||
#define CS42L73_SPDIF_I2S (0 << 6)
|
||||
#define CS42L73_SPDIF_PCM (1 << 6)
|
||||
#define CS42L73_PCM_MODE0 (0 << 4)
|
||||
#define CS42L73_PCM_MODE1 (1 << 4)
|
||||
#define CS42L73_PCM_MODE2 (2 << 4)
|
||||
#define CS42L73_PCM_MODE_MASK (3 << 4)
|
||||
#define CS42L73_PCM_BIT_ORDER (1 << 3)
|
||||
#define CS42L73_MCK_SCLK_64FS (0 << 0)
|
||||
#define CS42L73_MCK_SCLK_MCLK (2 << 0)
|
||||
#define CS42L73_MCK_SCLK_PREMCLK (3 << 0)
|
||||
|
||||
/* CS42L73_xSPMMCC */
|
||||
#define MS_MASTER (1 << 7)
|
||||
#define CS42L73_MS_MASTER (1 << 7)
|
||||
|
||||
|
||||
/* CS42L73_DMMCC */
|
||||
#define MCLKDIS (1 << 0)
|
||||
#define MCLKSEL_MCLK2 (1 << 4)
|
||||
#define MCLKSEL_MCLK1 (0 << 4)
|
||||
#define CS42L73_MCLKDIS (1 << 0)
|
||||
#define CS42L73_MCLKSEL_MCLK2 (1 << 4)
|
||||
#define CS42L73_MCLKSEL_MCLK1 (0 << 4)
|
||||
|
||||
/* CS42L73 MCLK derived from MCLK1 or MCLK2 */
|
||||
#define CS42L73_CLKID_MCLK1 0
|
||||
|
@ -194,28 +195,26 @@
|
|||
#define CS42L73_VSP 2
|
||||
|
||||
/* IS1, IM1 */
|
||||
#define MIC2_SDET (1 << 6)
|
||||
#define THMOVLD (1 << 4)
|
||||
#define DIGMIXOVFL (1 << 3)
|
||||
#define IPBOVFL (1 << 1)
|
||||
#define IPAOVFL (1 << 0)
|
||||
#define CS42L73_MIC2_SDET (1 << 6)
|
||||
#define CS42L73_THMOVLD (1 << 4)
|
||||
#define CS42L73_DIGMIXOVFL (1 << 3)
|
||||
#define CS42L73_IPBOVFL (1 << 1)
|
||||
#define CS42L73_IPAOVFL (1 << 0)
|
||||
|
||||
/* Analog Softramp */
|
||||
#define ANLGOSFT (1 << 0)
|
||||
#define CS42L73_ANLGOSFT (1 << 0)
|
||||
|
||||
/* HP A/B Analog Mute */
|
||||
#define HPA_MUTE (1 << 7)
|
||||
#define CS42L73_HPA_MUTE (1 << 7)
|
||||
/* LO A/B Analog Mute */
|
||||
#define LOA_MUTE (1 << 7)
|
||||
#define CS42L73_LOA_MUTE (1 << 7)
|
||||
/* Digital Mute */
|
||||
#define HLAD_MUTE (1 << 0)
|
||||
#define HLBD_MUTE (1 << 1)
|
||||
#define SPKD_MUTE (1 << 2)
|
||||
#define ESLD_MUTE (1 << 3)
|
||||
#define CS42L73_HLAD_MUTE (1 << 0)
|
||||
#define CS42L73_HLBD_MUTE (1 << 1)
|
||||
#define CS42L73_SPKD_MUTE (1 << 2)
|
||||
#define CS42L73_ESLD_MUTE (1 << 3)
|
||||
|
||||
/* Misc defines for codec */
|
||||
#define CS42L73_RESET_GPIO 143
|
||||
|
||||
#define CS42L73_DEVID 0x00042A73
|
||||
#define CS42L73_MCLKX_MIN 5644800
|
||||
#define CS42L73_MCLKX_MAX 38400000
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
@ -38,294 +39,223 @@ struct max98088_cdata {
|
|||
};
|
||||
|
||||
struct max98088_priv {
|
||||
enum max98088_type devtype;
|
||||
struct max98088_pdata *pdata;
|
||||
unsigned int sysclk;
|
||||
struct max98088_cdata dai[2];
|
||||
int eq_textcnt;
|
||||
const char **eq_texts;
|
||||
struct soc_enum eq_enum;
|
||||
u8 ina_state;
|
||||
u8 inb_state;
|
||||
unsigned int ex_mode;
|
||||
unsigned int digmic;
|
||||
unsigned int mic1pre;
|
||||
unsigned int mic2pre;
|
||||
unsigned int extmic_mode;
|
||||
struct regmap *regmap;
|
||||
enum max98088_type devtype;
|
||||
struct max98088_pdata *pdata;
|
||||
unsigned int sysclk;
|
||||
struct max98088_cdata dai[2];
|
||||
int eq_textcnt;
|
||||
const char **eq_texts;
|
||||
struct soc_enum eq_enum;
|
||||
u8 ina_state;
|
||||
u8 inb_state;
|
||||
unsigned int ex_mode;
|
||||
unsigned int digmic;
|
||||
unsigned int mic1pre;
|
||||
unsigned int mic2pre;
|
||||
unsigned int extmic_mode;
|
||||
};
|
||||
|
||||
static const u8 max98088_reg[M98088_REG_CNT] = {
|
||||
0x00, /* 00 IRQ status */
|
||||
0x00, /* 01 MIC status */
|
||||
0x00, /* 02 jack status */
|
||||
0x00, /* 03 battery voltage */
|
||||
0x00, /* 04 */
|
||||
0x00, /* 05 */
|
||||
0x00, /* 06 */
|
||||
0x00, /* 07 */
|
||||
0x00, /* 08 */
|
||||
0x00, /* 09 */
|
||||
0x00, /* 0A */
|
||||
0x00, /* 0B */
|
||||
0x00, /* 0C */
|
||||
0x00, /* 0D */
|
||||
0x00, /* 0E */
|
||||
0x00, /* 0F interrupt enable */
|
||||
static const struct reg_default max98088_reg[] = {
|
||||
{ 0xf, 0x00 }, /* 0F interrupt enable */
|
||||
|
||||
0x00, /* 10 master clock */
|
||||
0x00, /* 11 DAI1 clock mode */
|
||||
0x00, /* 12 DAI1 clock control */
|
||||
0x00, /* 13 DAI1 clock control */
|
||||
0x00, /* 14 DAI1 format */
|
||||
0x00, /* 15 DAI1 clock */
|
||||
0x00, /* 16 DAI1 config */
|
||||
0x00, /* 17 DAI1 TDM */
|
||||
0x00, /* 18 DAI1 filters */
|
||||
0x00, /* 19 DAI2 clock mode */
|
||||
0x00, /* 1A DAI2 clock control */
|
||||
0x00, /* 1B DAI2 clock control */
|
||||
0x00, /* 1C DAI2 format */
|
||||
0x00, /* 1D DAI2 clock */
|
||||
0x00, /* 1E DAI2 config */
|
||||
0x00, /* 1F DAI2 TDM */
|
||||
{ 0x10, 0x00 }, /* 10 master clock */
|
||||
{ 0x11, 0x00 }, /* 11 DAI1 clock mode */
|
||||
{ 0x12, 0x00 }, /* 12 DAI1 clock control */
|
||||
{ 0x13, 0x00 }, /* 13 DAI1 clock control */
|
||||
{ 0x14, 0x00 }, /* 14 DAI1 format */
|
||||
{ 0x15, 0x00 }, /* 15 DAI1 clock */
|
||||
{ 0x16, 0x00 }, /* 16 DAI1 config */
|
||||
{ 0x17, 0x00 }, /* 17 DAI1 TDM */
|
||||
{ 0x18, 0x00 }, /* 18 DAI1 filters */
|
||||
{ 0x19, 0x00 }, /* 19 DAI2 clock mode */
|
||||
{ 0x1a, 0x00 }, /* 1A DAI2 clock control */
|
||||
{ 0x1b, 0x00 }, /* 1B DAI2 clock control */
|
||||
{ 0x1c, 0x00 }, /* 1C DAI2 format */
|
||||
{ 0x1d, 0x00 }, /* 1D DAI2 clock */
|
||||
{ 0x1e, 0x00 }, /* 1E DAI2 config */
|
||||
{ 0x1f, 0x00 }, /* 1F DAI2 TDM */
|
||||
|
||||
0x00, /* 20 DAI2 filters */
|
||||
0x00, /* 21 data config */
|
||||
0x00, /* 22 DAC mixer */
|
||||
0x00, /* 23 left ADC mixer */
|
||||
0x00, /* 24 right ADC mixer */
|
||||
0x00, /* 25 left HP mixer */
|
||||
0x00, /* 26 right HP mixer */
|
||||
0x00, /* 27 HP control */
|
||||
0x00, /* 28 left REC mixer */
|
||||
0x00, /* 29 right REC mixer */
|
||||
0x00, /* 2A REC control */
|
||||
0x00, /* 2B left SPK mixer */
|
||||
0x00, /* 2C right SPK mixer */
|
||||
0x00, /* 2D SPK control */
|
||||
0x00, /* 2E sidetone */
|
||||
0x00, /* 2F DAI1 playback level */
|
||||
{ 0x20, 0x00 }, /* 20 DAI2 filters */
|
||||
{ 0x21, 0x00 }, /* 21 data config */
|
||||
{ 0x22, 0x00 }, /* 22 DAC mixer */
|
||||
{ 0x23, 0x00 }, /* 23 left ADC mixer */
|
||||
{ 0x24, 0x00 }, /* 24 right ADC mixer */
|
||||
{ 0x25, 0x00 }, /* 25 left HP mixer */
|
||||
{ 0x26, 0x00 }, /* 26 right HP mixer */
|
||||
{ 0x27, 0x00 }, /* 27 HP control */
|
||||
{ 0x28, 0x00 }, /* 28 left REC mixer */
|
||||
{ 0x29, 0x00 }, /* 29 right REC mixer */
|
||||
{ 0x2a, 0x00 }, /* 2A REC control */
|
||||
{ 0x2b, 0x00 }, /* 2B left SPK mixer */
|
||||
{ 0x2c, 0x00 }, /* 2C right SPK mixer */
|
||||
{ 0x2d, 0x00 }, /* 2D SPK control */
|
||||
{ 0x2e, 0x00 }, /* 2E sidetone */
|
||||
{ 0x2f, 0x00 }, /* 2F DAI1 playback level */
|
||||
|
||||
0x00, /* 30 DAI1 playback level */
|
||||
0x00, /* 31 DAI2 playback level */
|
||||
0x00, /* 32 DAI2 playbakc level */
|
||||
0x00, /* 33 left ADC level */
|
||||
0x00, /* 34 right ADC level */
|
||||
0x00, /* 35 MIC1 level */
|
||||
0x00, /* 36 MIC2 level */
|
||||
0x00, /* 37 INA level */
|
||||
0x00, /* 38 INB level */
|
||||
0x00, /* 39 left HP volume */
|
||||
0x00, /* 3A right HP volume */
|
||||
0x00, /* 3B left REC volume */
|
||||
0x00, /* 3C right REC volume */
|
||||
0x00, /* 3D left SPK volume */
|
||||
0x00, /* 3E right SPK volume */
|
||||
0x00, /* 3F MIC config */
|
||||
{ 0x30, 0x00 }, /* 30 DAI1 playback level */
|
||||
{ 0x31, 0x00 }, /* 31 DAI2 playback level */
|
||||
{ 0x32, 0x00 }, /* 32 DAI2 playbakc level */
|
||||
{ 0x33, 0x00 }, /* 33 left ADC level */
|
||||
{ 0x34, 0x00 }, /* 34 right ADC level */
|
||||
{ 0x35, 0x00 }, /* 35 MIC1 level */
|
||||
{ 0x36, 0x00 }, /* 36 MIC2 level */
|
||||
{ 0x37, 0x00 }, /* 37 INA level */
|
||||
{ 0x38, 0x00 }, /* 38 INB level */
|
||||
{ 0x39, 0x00 }, /* 39 left HP volume */
|
||||
{ 0x3a, 0x00 }, /* 3A right HP volume */
|
||||
{ 0x3b, 0x00 }, /* 3B left REC volume */
|
||||
{ 0x3c, 0x00 }, /* 3C right REC volume */
|
||||
{ 0x3d, 0x00 }, /* 3D left SPK volume */
|
||||
{ 0x3e, 0x00 }, /* 3E right SPK volume */
|
||||
{ 0x3f, 0x00 }, /* 3F MIC config */
|
||||
|
||||
0x00, /* 40 MIC threshold */
|
||||
0x00, /* 41 excursion limiter filter */
|
||||
0x00, /* 42 excursion limiter threshold */
|
||||
0x00, /* 43 ALC */
|
||||
0x00, /* 44 power limiter threshold */
|
||||
0x00, /* 45 power limiter config */
|
||||
0x00, /* 46 distortion limiter config */
|
||||
0x00, /* 47 audio input */
|
||||
0x00, /* 48 microphone */
|
||||
0x00, /* 49 level control */
|
||||
0x00, /* 4A bypass switches */
|
||||
0x00, /* 4B jack detect */
|
||||
0x00, /* 4C input enable */
|
||||
0x00, /* 4D output enable */
|
||||
0xF0, /* 4E bias control */
|
||||
0x00, /* 4F DAC power */
|
||||
{ 0x40, 0x00 }, /* 40 MIC threshold */
|
||||
{ 0x41, 0x00 }, /* 41 excursion limiter filter */
|
||||
{ 0x42, 0x00 }, /* 42 excursion limiter threshold */
|
||||
{ 0x43, 0x00 }, /* 43 ALC */
|
||||
{ 0x44, 0x00 }, /* 44 power limiter threshold */
|
||||
{ 0x45, 0x00 }, /* 45 power limiter config */
|
||||
{ 0x46, 0x00 }, /* 46 distortion limiter config */
|
||||
{ 0x47, 0x00 }, /* 47 audio input */
|
||||
{ 0x48, 0x00 }, /* 48 microphone */
|
||||
{ 0x49, 0x00 }, /* 49 level control */
|
||||
{ 0x4a, 0x00 }, /* 4A bypass switches */
|
||||
{ 0x4b, 0x00 }, /* 4B jack detect */
|
||||
{ 0x4c, 0x00 }, /* 4C input enable */
|
||||
{ 0x4d, 0x00 }, /* 4D output enable */
|
||||
{ 0x4e, 0xF0 }, /* 4E bias control */
|
||||
{ 0x4f, 0x00 }, /* 4F DAC power */
|
||||
|
||||
0x0F, /* 50 DAC power */
|
||||
0x00, /* 51 system */
|
||||
0x00, /* 52 DAI1 EQ1 */
|
||||
0x00, /* 53 DAI1 EQ1 */
|
||||
0x00, /* 54 DAI1 EQ1 */
|
||||
0x00, /* 55 DAI1 EQ1 */
|
||||
0x00, /* 56 DAI1 EQ1 */
|
||||
0x00, /* 57 DAI1 EQ1 */
|
||||
0x00, /* 58 DAI1 EQ1 */
|
||||
0x00, /* 59 DAI1 EQ1 */
|
||||
0x00, /* 5A DAI1 EQ1 */
|
||||
0x00, /* 5B DAI1 EQ1 */
|
||||
0x00, /* 5C DAI1 EQ2 */
|
||||
0x00, /* 5D DAI1 EQ2 */
|
||||
0x00, /* 5E DAI1 EQ2 */
|
||||
0x00, /* 5F DAI1 EQ2 */
|
||||
{ 0x50, 0x0F }, /* 50 DAC power */
|
||||
{ 0x51, 0x00 }, /* 51 system */
|
||||
{ 0x52, 0x00 }, /* 52 DAI1 EQ1 */
|
||||
{ 0x53, 0x00 }, /* 53 DAI1 EQ1 */
|
||||
{ 0x54, 0x00 }, /* 54 DAI1 EQ1 */
|
||||
{ 0x55, 0x00 }, /* 55 DAI1 EQ1 */
|
||||
{ 0x56, 0x00 }, /* 56 DAI1 EQ1 */
|
||||
{ 0x57, 0x00 }, /* 57 DAI1 EQ1 */
|
||||
{ 0x58, 0x00 }, /* 58 DAI1 EQ1 */
|
||||
{ 0x59, 0x00 }, /* 59 DAI1 EQ1 */
|
||||
{ 0x5a, 0x00 }, /* 5A DAI1 EQ1 */
|
||||
{ 0x5b, 0x00 }, /* 5B DAI1 EQ1 */
|
||||
{ 0x5c, 0x00 }, /* 5C DAI1 EQ2 */
|
||||
{ 0x5d, 0x00 }, /* 5D DAI1 EQ2 */
|
||||
{ 0x5e, 0x00 }, /* 5E DAI1 EQ2 */
|
||||
{ 0x5f, 0x00 }, /* 5F DAI1 EQ2 */
|
||||
|
||||
0x00, /* 60 DAI1 EQ2 */
|
||||
0x00, /* 61 DAI1 EQ2 */
|
||||
0x00, /* 62 DAI1 EQ2 */
|
||||
0x00, /* 63 DAI1 EQ2 */
|
||||
0x00, /* 64 DAI1 EQ2 */
|
||||
0x00, /* 65 DAI1 EQ2 */
|
||||
0x00, /* 66 DAI1 EQ3 */
|
||||
0x00, /* 67 DAI1 EQ3 */
|
||||
0x00, /* 68 DAI1 EQ3 */
|
||||
0x00, /* 69 DAI1 EQ3 */
|
||||
0x00, /* 6A DAI1 EQ3 */
|
||||
0x00, /* 6B DAI1 EQ3 */
|
||||
0x00, /* 6C DAI1 EQ3 */
|
||||
0x00, /* 6D DAI1 EQ3 */
|
||||
0x00, /* 6E DAI1 EQ3 */
|
||||
0x00, /* 6F DAI1 EQ3 */
|
||||
{ 0x60, 0x00 }, /* 60 DAI1 EQ2 */
|
||||
{ 0x61, 0x00 }, /* 61 DAI1 EQ2 */
|
||||
{ 0x62, 0x00 }, /* 62 DAI1 EQ2 */
|
||||
{ 0x63, 0x00 }, /* 63 DAI1 EQ2 */
|
||||
{ 0x64, 0x00 }, /* 64 DAI1 EQ2 */
|
||||
{ 0x65, 0x00 }, /* 65 DAI1 EQ2 */
|
||||
{ 0x66, 0x00 }, /* 66 DAI1 EQ3 */
|
||||
{ 0x67, 0x00 }, /* 67 DAI1 EQ3 */
|
||||
{ 0x68, 0x00 }, /* 68 DAI1 EQ3 */
|
||||
{ 0x69, 0x00 }, /* 69 DAI1 EQ3 */
|
||||
{ 0x6a, 0x00 }, /* 6A DAI1 EQ3 */
|
||||
{ 0x6b, 0x00 }, /* 6B DAI1 EQ3 */
|
||||
{ 0x6c, 0x00 }, /* 6C DAI1 EQ3 */
|
||||
{ 0x6d, 0x00 }, /* 6D DAI1 EQ3 */
|
||||
{ 0x6e, 0x00 }, /* 6E DAI1 EQ3 */
|
||||
{ 0x6f, 0x00 }, /* 6F DAI1 EQ3 */
|
||||
|
||||
0x00, /* 70 DAI1 EQ4 */
|
||||
0x00, /* 71 DAI1 EQ4 */
|
||||
0x00, /* 72 DAI1 EQ4 */
|
||||
0x00, /* 73 DAI1 EQ4 */
|
||||
0x00, /* 74 DAI1 EQ4 */
|
||||
0x00, /* 75 DAI1 EQ4 */
|
||||
0x00, /* 76 DAI1 EQ4 */
|
||||
0x00, /* 77 DAI1 EQ4 */
|
||||
0x00, /* 78 DAI1 EQ4 */
|
||||
0x00, /* 79 DAI1 EQ4 */
|
||||
0x00, /* 7A DAI1 EQ5 */
|
||||
0x00, /* 7B DAI1 EQ5 */
|
||||
0x00, /* 7C DAI1 EQ5 */
|
||||
0x00, /* 7D DAI1 EQ5 */
|
||||
0x00, /* 7E DAI1 EQ5 */
|
||||
0x00, /* 7F DAI1 EQ5 */
|
||||
{ 0x70, 0x00 }, /* 70 DAI1 EQ4 */
|
||||
{ 0x71, 0x00 }, /* 71 DAI1 EQ4 */
|
||||
{ 0x72, 0x00 }, /* 72 DAI1 EQ4 */
|
||||
{ 0x73, 0x00 }, /* 73 DAI1 EQ4 */
|
||||
{ 0x74, 0x00 }, /* 74 DAI1 EQ4 */
|
||||
{ 0x75, 0x00 }, /* 75 DAI1 EQ4 */
|
||||
{ 0x76, 0x00 }, /* 76 DAI1 EQ4 */
|
||||
{ 0x77, 0x00 }, /* 77 DAI1 EQ4 */
|
||||
{ 0x78, 0x00 }, /* 78 DAI1 EQ4 */
|
||||
{ 0x79, 0x00 }, /* 79 DAI1 EQ4 */
|
||||
{ 0x7a, 0x00 }, /* 7A DAI1 EQ5 */
|
||||
{ 0x7b, 0x00 }, /* 7B DAI1 EQ5 */
|
||||
{ 0x7c, 0x00 }, /* 7C DAI1 EQ5 */
|
||||
{ 0x7d, 0x00 }, /* 7D DAI1 EQ5 */
|
||||
{ 0x7e, 0x00 }, /* 7E DAI1 EQ5 */
|
||||
{ 0x7f, 0x00 }, /* 7F DAI1 EQ5 */
|
||||
|
||||
0x00, /* 80 DAI1 EQ5 */
|
||||
0x00, /* 81 DAI1 EQ5 */
|
||||
0x00, /* 82 DAI1 EQ5 */
|
||||
0x00, /* 83 DAI1 EQ5 */
|
||||
0x00, /* 84 DAI2 EQ1 */
|
||||
0x00, /* 85 DAI2 EQ1 */
|
||||
0x00, /* 86 DAI2 EQ1 */
|
||||
0x00, /* 87 DAI2 EQ1 */
|
||||
0x00, /* 88 DAI2 EQ1 */
|
||||
0x00, /* 89 DAI2 EQ1 */
|
||||
0x00, /* 8A DAI2 EQ1 */
|
||||
0x00, /* 8B DAI2 EQ1 */
|
||||
0x00, /* 8C DAI2 EQ1 */
|
||||
0x00, /* 8D DAI2 EQ1 */
|
||||
0x00, /* 8E DAI2 EQ2 */
|
||||
0x00, /* 8F DAI2 EQ2 */
|
||||
{ 0x80, 0x00 }, /* 80 DAI1 EQ5 */
|
||||
{ 0x81, 0x00 }, /* 81 DAI1 EQ5 */
|
||||
{ 0x82, 0x00 }, /* 82 DAI1 EQ5 */
|
||||
{ 0x83, 0x00 }, /* 83 DAI1 EQ5 */
|
||||
{ 0x84, 0x00 }, /* 84 DAI2 EQ1 */
|
||||
{ 0x85, 0x00 }, /* 85 DAI2 EQ1 */
|
||||
{ 0x86, 0x00 }, /* 86 DAI2 EQ1 */
|
||||
{ 0x87, 0x00 }, /* 87 DAI2 EQ1 */
|
||||
{ 0x88, 0x00 }, /* 88 DAI2 EQ1 */
|
||||
{ 0x89, 0x00 }, /* 89 DAI2 EQ1 */
|
||||
{ 0x8a, 0x00 }, /* 8A DAI2 EQ1 */
|
||||
{ 0x8b, 0x00 }, /* 8B DAI2 EQ1 */
|
||||
{ 0x8c, 0x00 }, /* 8C DAI2 EQ1 */
|
||||
{ 0x8d, 0x00 }, /* 8D DAI2 EQ1 */
|
||||
{ 0x8e, 0x00 }, /* 8E DAI2 EQ2 */
|
||||
{ 0x8f, 0x00 }, /* 8F DAI2 EQ2 */
|
||||
|
||||
0x00, /* 90 DAI2 EQ2 */
|
||||
0x00, /* 91 DAI2 EQ2 */
|
||||
0x00, /* 92 DAI2 EQ2 */
|
||||
0x00, /* 93 DAI2 EQ2 */
|
||||
0x00, /* 94 DAI2 EQ2 */
|
||||
0x00, /* 95 DAI2 EQ2 */
|
||||
0x00, /* 96 DAI2 EQ2 */
|
||||
0x00, /* 97 DAI2 EQ2 */
|
||||
0x00, /* 98 DAI2 EQ3 */
|
||||
0x00, /* 99 DAI2 EQ3 */
|
||||
0x00, /* 9A DAI2 EQ3 */
|
||||
0x00, /* 9B DAI2 EQ3 */
|
||||
0x00, /* 9C DAI2 EQ3 */
|
||||
0x00, /* 9D DAI2 EQ3 */
|
||||
0x00, /* 9E DAI2 EQ3 */
|
||||
0x00, /* 9F DAI2 EQ3 */
|
||||
{ 0x90, 0x00 }, /* 90 DAI2 EQ2 */
|
||||
{ 0x91, 0x00 }, /* 91 DAI2 EQ2 */
|
||||
{ 0x92, 0x00 }, /* 92 DAI2 EQ2 */
|
||||
{ 0x93, 0x00 }, /* 93 DAI2 EQ2 */
|
||||
{ 0x94, 0x00 }, /* 94 DAI2 EQ2 */
|
||||
{ 0x95, 0x00 }, /* 95 DAI2 EQ2 */
|
||||
{ 0x96, 0x00 }, /* 96 DAI2 EQ2 */
|
||||
{ 0x97, 0x00 }, /* 97 DAI2 EQ2 */
|
||||
{ 0x98, 0x00 }, /* 98 DAI2 EQ3 */
|
||||
{ 0x99, 0x00 }, /* 99 DAI2 EQ3 */
|
||||
{ 0x9a, 0x00 }, /* 9A DAI2 EQ3 */
|
||||
{ 0x9b, 0x00 }, /* 9B DAI2 EQ3 */
|
||||
{ 0x9c, 0x00 }, /* 9C DAI2 EQ3 */
|
||||
{ 0x9d, 0x00 }, /* 9D DAI2 EQ3 */
|
||||
{ 0x9e, 0x00 }, /* 9E DAI2 EQ3 */
|
||||
{ 0x9f, 0x00 }, /* 9F DAI2 EQ3 */
|
||||
|
||||
0x00, /* A0 DAI2 EQ3 */
|
||||
0x00, /* A1 DAI2 EQ3 */
|
||||
0x00, /* A2 DAI2 EQ4 */
|
||||
0x00, /* A3 DAI2 EQ4 */
|
||||
0x00, /* A4 DAI2 EQ4 */
|
||||
0x00, /* A5 DAI2 EQ4 */
|
||||
0x00, /* A6 DAI2 EQ4 */
|
||||
0x00, /* A7 DAI2 EQ4 */
|
||||
0x00, /* A8 DAI2 EQ4 */
|
||||
0x00, /* A9 DAI2 EQ4 */
|
||||
0x00, /* AA DAI2 EQ4 */
|
||||
0x00, /* AB DAI2 EQ4 */
|
||||
0x00, /* AC DAI2 EQ5 */
|
||||
0x00, /* AD DAI2 EQ5 */
|
||||
0x00, /* AE DAI2 EQ5 */
|
||||
0x00, /* AF DAI2 EQ5 */
|
||||
{ 0xa0, 0x00 }, /* A0 DAI2 EQ3 */
|
||||
{ 0xa1, 0x00 }, /* A1 DAI2 EQ3 */
|
||||
{ 0xa2, 0x00 }, /* A2 DAI2 EQ4 */
|
||||
{ 0xa3, 0x00 }, /* A3 DAI2 EQ4 */
|
||||
{ 0xa4, 0x00 }, /* A4 DAI2 EQ4 */
|
||||
{ 0xa5, 0x00 }, /* A5 DAI2 EQ4 */
|
||||
{ 0xa6, 0x00 }, /* A6 DAI2 EQ4 */
|
||||
{ 0xa7, 0x00 }, /* A7 DAI2 EQ4 */
|
||||
{ 0xa8, 0x00 }, /* A8 DAI2 EQ4 */
|
||||
{ 0xa9, 0x00 }, /* A9 DAI2 EQ4 */
|
||||
{ 0xaa, 0x00 }, /* AA DAI2 EQ4 */
|
||||
{ 0xab, 0x00 }, /* AB DAI2 EQ4 */
|
||||
{ 0xac, 0x00 }, /* AC DAI2 EQ5 */
|
||||
{ 0xad, 0x00 }, /* AD DAI2 EQ5 */
|
||||
{ 0xae, 0x00 }, /* AE DAI2 EQ5 */
|
||||
{ 0xaf, 0x00 }, /* AF DAI2 EQ5 */
|
||||
|
||||
0x00, /* B0 DAI2 EQ5 */
|
||||
0x00, /* B1 DAI2 EQ5 */
|
||||
0x00, /* B2 DAI2 EQ5 */
|
||||
0x00, /* B3 DAI2 EQ5 */
|
||||
0x00, /* B4 DAI2 EQ5 */
|
||||
0x00, /* B5 DAI2 EQ5 */
|
||||
0x00, /* B6 DAI1 biquad */
|
||||
0x00, /* B7 DAI1 biquad */
|
||||
0x00, /* B8 DAI1 biquad */
|
||||
0x00, /* B9 DAI1 biquad */
|
||||
0x00, /* BA DAI1 biquad */
|
||||
0x00, /* BB DAI1 biquad */
|
||||
0x00, /* BC DAI1 biquad */
|
||||
0x00, /* BD DAI1 biquad */
|
||||
0x00, /* BE DAI1 biquad */
|
||||
0x00, /* BF DAI1 biquad */
|
||||
{ 0xb0, 0x00 }, /* B0 DAI2 EQ5 */
|
||||
{ 0xb1, 0x00 }, /* B1 DAI2 EQ5 */
|
||||
{ 0xb2, 0x00 }, /* B2 DAI2 EQ5 */
|
||||
{ 0xb3, 0x00 }, /* B3 DAI2 EQ5 */
|
||||
{ 0xb4, 0x00 }, /* B4 DAI2 EQ5 */
|
||||
{ 0xb5, 0x00 }, /* B5 DAI2 EQ5 */
|
||||
{ 0xb6, 0x00 }, /* B6 DAI1 biquad */
|
||||
{ 0xb7, 0x00 }, /* B7 DAI1 biquad */
|
||||
{ 0xb8 ,0x00 }, /* B8 DAI1 biquad */
|
||||
{ 0xb9, 0x00 }, /* B9 DAI1 biquad */
|
||||
{ 0xba, 0x00 }, /* BA DAI1 biquad */
|
||||
{ 0xbb, 0x00 }, /* BB DAI1 biquad */
|
||||
{ 0xbc, 0x00 }, /* BC DAI1 biquad */
|
||||
{ 0xbd, 0x00 }, /* BD DAI1 biquad */
|
||||
{ 0xbe, 0x00 }, /* BE DAI1 biquad */
|
||||
{ 0xbf, 0x00 }, /* BF DAI1 biquad */
|
||||
|
||||
0x00, /* C0 DAI2 biquad */
|
||||
0x00, /* C1 DAI2 biquad */
|
||||
0x00, /* C2 DAI2 biquad */
|
||||
0x00, /* C3 DAI2 biquad */
|
||||
0x00, /* C4 DAI2 biquad */
|
||||
0x00, /* C5 DAI2 biquad */
|
||||
0x00, /* C6 DAI2 biquad */
|
||||
0x00, /* C7 DAI2 biquad */
|
||||
0x00, /* C8 DAI2 biquad */
|
||||
0x00, /* C9 DAI2 biquad */
|
||||
0x00, /* CA */
|
||||
0x00, /* CB */
|
||||
0x00, /* CC */
|
||||
0x00, /* CD */
|
||||
0x00, /* CE */
|
||||
0x00, /* CF */
|
||||
|
||||
0x00, /* D0 */
|
||||
0x00, /* D1 */
|
||||
0x00, /* D2 */
|
||||
0x00, /* D3 */
|
||||
0x00, /* D4 */
|
||||
0x00, /* D5 */
|
||||
0x00, /* D6 */
|
||||
0x00, /* D7 */
|
||||
0x00, /* D8 */
|
||||
0x00, /* D9 */
|
||||
0x00, /* DA */
|
||||
0x70, /* DB */
|
||||
0x00, /* DC */
|
||||
0x00, /* DD */
|
||||
0x00, /* DE */
|
||||
0x00, /* DF */
|
||||
|
||||
0x00, /* E0 */
|
||||
0x00, /* E1 */
|
||||
0x00, /* E2 */
|
||||
0x00, /* E3 */
|
||||
0x00, /* E4 */
|
||||
0x00, /* E5 */
|
||||
0x00, /* E6 */
|
||||
0x00, /* E7 */
|
||||
0x00, /* E8 */
|
||||
0x00, /* E9 */
|
||||
0x00, /* EA */
|
||||
0x00, /* EB */
|
||||
0x00, /* EC */
|
||||
0x00, /* ED */
|
||||
0x00, /* EE */
|
||||
0x00, /* EF */
|
||||
|
||||
0x00, /* F0 */
|
||||
0x00, /* F1 */
|
||||
0x00, /* F2 */
|
||||
0x00, /* F3 */
|
||||
0x00, /* F4 */
|
||||
0x00, /* F5 */
|
||||
0x00, /* F6 */
|
||||
0x00, /* F7 */
|
||||
0x00, /* F8 */
|
||||
0x00, /* F9 */
|
||||
0x00, /* FA */
|
||||
0x00, /* FB */
|
||||
0x00, /* FC */
|
||||
0x00, /* FD */
|
||||
0x00, /* FE */
|
||||
0x00, /* FF */
|
||||
{ 0xc0, 0x00 }, /* C0 DAI2 biquad */
|
||||
{ 0xc1, 0x00 }, /* C1 DAI2 biquad */
|
||||
{ 0xc2, 0x00 }, /* C2 DAI2 biquad */
|
||||
{ 0xc3, 0x00 }, /* C3 DAI2 biquad */
|
||||
{ 0xc4, 0x00 }, /* C4 DAI2 biquad */
|
||||
{ 0xc5, 0x00 }, /* C5 DAI2 biquad */
|
||||
{ 0xc6, 0x00 }, /* C6 DAI2 biquad */
|
||||
{ 0xc7, 0x00 }, /* C7 DAI2 biquad */
|
||||
{ 0xc8, 0x00 }, /* C8 DAI2 biquad */
|
||||
{ 0xc9, 0x00 }, /* C9 DAI2 biquad */
|
||||
};
|
||||
|
||||
static struct {
|
||||
|
@ -606,11 +536,28 @@ static struct {
|
|||
{ 0xFF, 0x00, 1 }, /* FF */
|
||||
};
|
||||
|
||||
static int max98088_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
|
||||
static bool max98088_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return max98088_access[reg].readable;
|
||||
}
|
||||
|
||||
static bool max98088_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return max98088_access[reg].vol;
|
||||
}
|
||||
|
||||
static const struct regmap_config max98088_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.readable_reg = max98088_readable_register,
|
||||
.volatile_reg = max98088_volatile_register,
|
||||
.max_register = 0xff,
|
||||
|
||||
.reg_defaults = max98088_reg,
|
||||
.num_reg_defaults = ARRAY_SIZE(max98088_reg),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Load equalizer DSP coefficient configurations registers
|
||||
|
@ -1610,58 +1557,34 @@ static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void max98088_sync_cache(struct snd_soc_codec *codec)
|
||||
{
|
||||
u8 *reg_cache = codec->reg_cache;
|
||||
int i;
|
||||
|
||||
if (!codec->cache_sync)
|
||||
return;
|
||||
|
||||
codec->cache_only = 0;
|
||||
|
||||
/* write back cached values if they're writeable and
|
||||
* different from the hardware default.
|
||||
*/
|
||||
for (i = 1; i < codec->driver->reg_cache_size; i++) {
|
||||
if (!max98088_access[i].writable)
|
||||
continue;
|
||||
|
||||
if (reg_cache[i] == max98088_reg[i])
|
||||
continue;
|
||||
|
||||
snd_soc_write(codec, i, reg_cache[i]);
|
||||
}
|
||||
|
||||
codec->cache_sync = 0;
|
||||
}
|
||||
|
||||
static int max98088_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
|
||||
max98088_sync_cache(codec);
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
|
||||
snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
|
||||
M98088_MBEN, M98088_MBEN);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
|
||||
regcache_sync(max98088->regmap);
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
|
||||
M98088_MBEN, 0);
|
||||
codec->cache_sync = 1;
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
|
||||
M98088_MBEN, M98088_MBEN);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
|
||||
M98088_MBEN, 0);
|
||||
regcache_mark_dirty(max98088->regmap);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
|
||||
|
@ -1988,9 +1911,9 @@ static int max98088_probe(struct snd_soc_codec *codec)
|
|||
struct max98088_cdata *cdata;
|
||||
int ret = 0;
|
||||
|
||||
codec->cache_sync = 1;
|
||||
regcache_mark_dirty(max98088->regmap);
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -2048,9 +1971,6 @@ static int max98088_probe(struct snd_soc_codec *codec)
|
|||
|
||||
max98088_handle_pdata(codec);
|
||||
|
||||
snd_soc_add_codec_controls(codec, max98088_snd_controls,
|
||||
ARRAY_SIZE(max98088_snd_controls));
|
||||
|
||||
err_access:
|
||||
return ret;
|
||||
}
|
||||
|
@ -2066,15 +1986,13 @@ 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,
|
||||
.reg_cache_size = ARRAY_SIZE(max98088_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = max98088_reg,
|
||||
.volatile_register = max98088_volatile_register,
|
||||
.probe = max98088_probe,
|
||||
.remove = max98088_remove,
|
||||
.suspend = max98088_suspend,
|
||||
.resume = max98088_resume,
|
||||
.set_bias_level = max98088_set_bias_level,
|
||||
.controls = max98088_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(max98088_snd_controls),
|
||||
.dapm_widgets = max98088_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets),
|
||||
.dapm_routes = max98088_audio_map,
|
||||
|
@ -2082,7 +2000,7 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
|
|||
};
|
||||
|
||||
static int max98088_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct max98088_priv *max98088;
|
||||
int ret;
|
||||
|
@ -2092,6 +2010,10 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
|
|||
if (max98088 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap);
|
||||
if (IS_ERR(max98088->regmap))
|
||||
return PTR_ERR(max98088->regmap);
|
||||
|
||||
max98088->devtype = id->driver_data;
|
||||
|
||||
i2c_set_clientdata(i2c, max98088);
|
||||
|
|
|
@ -39,6 +39,7 @@ struct max98095_cdata {
|
|||
};
|
||||
|
||||
struct max98095_priv {
|
||||
struct regmap *regmap;
|
||||
enum max98095_type devtype;
|
||||
struct max98095_pdata *pdata;
|
||||
unsigned int sysclk;
|
||||
|
@ -56,263 +57,145 @@ struct max98095_priv {
|
|||
struct snd_soc_jack *mic_jack;
|
||||
};
|
||||
|
||||
static const u8 max98095_reg_def[M98095_REG_CNT] = {
|
||||
0x00, /* 00 */
|
||||
0x00, /* 01 */
|
||||
0x00, /* 02 */
|
||||
0x00, /* 03 */
|
||||
0x00, /* 04 */
|
||||
0x00, /* 05 */
|
||||
0x00, /* 06 */
|
||||
0x00, /* 07 */
|
||||
0x00, /* 08 */
|
||||
0x00, /* 09 */
|
||||
0x00, /* 0A */
|
||||
0x00, /* 0B */
|
||||
0x00, /* 0C */
|
||||
0x00, /* 0D */
|
||||
0x00, /* 0E */
|
||||
0x00, /* 0F */
|
||||
0x00, /* 10 */
|
||||
0x00, /* 11 */
|
||||
0x00, /* 12 */
|
||||
0x00, /* 13 */
|
||||
0x00, /* 14 */
|
||||
0x00, /* 15 */
|
||||
0x00, /* 16 */
|
||||
0x00, /* 17 */
|
||||
0x00, /* 18 */
|
||||
0x00, /* 19 */
|
||||
0x00, /* 1A */
|
||||
0x00, /* 1B */
|
||||
0x00, /* 1C */
|
||||
0x00, /* 1D */
|
||||
0x00, /* 1E */
|
||||
0x00, /* 1F */
|
||||
0x00, /* 20 */
|
||||
0x00, /* 21 */
|
||||
0x00, /* 22 */
|
||||
0x00, /* 23 */
|
||||
0x00, /* 24 */
|
||||
0x00, /* 25 */
|
||||
0x00, /* 26 */
|
||||
0x00, /* 27 */
|
||||
0x00, /* 28 */
|
||||
0x00, /* 29 */
|
||||
0x00, /* 2A */
|
||||
0x00, /* 2B */
|
||||
0x00, /* 2C */
|
||||
0x00, /* 2D */
|
||||
0x00, /* 2E */
|
||||
0x00, /* 2F */
|
||||
0x00, /* 30 */
|
||||
0x00, /* 31 */
|
||||
0x00, /* 32 */
|
||||
0x00, /* 33 */
|
||||
0x00, /* 34 */
|
||||
0x00, /* 35 */
|
||||
0x00, /* 36 */
|
||||
0x00, /* 37 */
|
||||
0x00, /* 38 */
|
||||
0x00, /* 39 */
|
||||
0x00, /* 3A */
|
||||
0x00, /* 3B */
|
||||
0x00, /* 3C */
|
||||
0x00, /* 3D */
|
||||
0x00, /* 3E */
|
||||
0x00, /* 3F */
|
||||
0x00, /* 40 */
|
||||
0x00, /* 41 */
|
||||
0x00, /* 42 */
|
||||
0x00, /* 43 */
|
||||
0x00, /* 44 */
|
||||
0x00, /* 45 */
|
||||
0x00, /* 46 */
|
||||
0x00, /* 47 */
|
||||
0x00, /* 48 */
|
||||
0x00, /* 49 */
|
||||
0x00, /* 4A */
|
||||
0x00, /* 4B */
|
||||
0x00, /* 4C */
|
||||
0x00, /* 4D */
|
||||
0x00, /* 4E */
|
||||
0x00, /* 4F */
|
||||
0x00, /* 50 */
|
||||
0x00, /* 51 */
|
||||
0x00, /* 52 */
|
||||
0x00, /* 53 */
|
||||
0x00, /* 54 */
|
||||
0x00, /* 55 */
|
||||
0x00, /* 56 */
|
||||
0x00, /* 57 */
|
||||
0x00, /* 58 */
|
||||
0x00, /* 59 */
|
||||
0x00, /* 5A */
|
||||
0x00, /* 5B */
|
||||
0x00, /* 5C */
|
||||
0x00, /* 5D */
|
||||
0x00, /* 5E */
|
||||
0x00, /* 5F */
|
||||
0x00, /* 60 */
|
||||
0x00, /* 61 */
|
||||
0x00, /* 62 */
|
||||
0x00, /* 63 */
|
||||
0x00, /* 64 */
|
||||
0x00, /* 65 */
|
||||
0x00, /* 66 */
|
||||
0x00, /* 67 */
|
||||
0x00, /* 68 */
|
||||
0x00, /* 69 */
|
||||
0x00, /* 6A */
|
||||
0x00, /* 6B */
|
||||
0x00, /* 6C */
|
||||
0x00, /* 6D */
|
||||
0x00, /* 6E */
|
||||
0x00, /* 6F */
|
||||
0x00, /* 70 */
|
||||
0x00, /* 71 */
|
||||
0x00, /* 72 */
|
||||
0x00, /* 73 */
|
||||
0x00, /* 74 */
|
||||
0x00, /* 75 */
|
||||
0x00, /* 76 */
|
||||
0x00, /* 77 */
|
||||
0x00, /* 78 */
|
||||
0x00, /* 79 */
|
||||
0x00, /* 7A */
|
||||
0x00, /* 7B */
|
||||
0x00, /* 7C */
|
||||
0x00, /* 7D */
|
||||
0x00, /* 7E */
|
||||
0x00, /* 7F */
|
||||
0x00, /* 80 */
|
||||
0x00, /* 81 */
|
||||
0x00, /* 82 */
|
||||
0x00, /* 83 */
|
||||
0x00, /* 84 */
|
||||
0x00, /* 85 */
|
||||
0x00, /* 86 */
|
||||
0x00, /* 87 */
|
||||
0x00, /* 88 */
|
||||
0x00, /* 89 */
|
||||
0x00, /* 8A */
|
||||
0x00, /* 8B */
|
||||
0x00, /* 8C */
|
||||
0x00, /* 8D */
|
||||
0x00, /* 8E */
|
||||
0x00, /* 8F */
|
||||
0x00, /* 90 */
|
||||
0x00, /* 91 */
|
||||
0x30, /* 92 */
|
||||
0xF0, /* 93 */
|
||||
0x00, /* 94 */
|
||||
0x00, /* 95 */
|
||||
0x3F, /* 96 */
|
||||
0x00, /* 97 */
|
||||
0x00, /* 98 */
|
||||
0x00, /* 99 */
|
||||
0x00, /* 9A */
|
||||
0x00, /* 9B */
|
||||
0x00, /* 9C */
|
||||
0x00, /* 9D */
|
||||
0x00, /* 9E */
|
||||
0x00, /* 9F */
|
||||
0x00, /* A0 */
|
||||
0x00, /* A1 */
|
||||
0x00, /* A2 */
|
||||
0x00, /* A3 */
|
||||
0x00, /* A4 */
|
||||
0x00, /* A5 */
|
||||
0x00, /* A6 */
|
||||
0x00, /* A7 */
|
||||
0x00, /* A8 */
|
||||
0x00, /* A9 */
|
||||
0x00, /* AA */
|
||||
0x00, /* AB */
|
||||
0x00, /* AC */
|
||||
0x00, /* AD */
|
||||
0x00, /* AE */
|
||||
0x00, /* AF */
|
||||
0x00, /* B0 */
|
||||
0x00, /* B1 */
|
||||
0x00, /* B2 */
|
||||
0x00, /* B3 */
|
||||
0x00, /* B4 */
|
||||
0x00, /* B5 */
|
||||
0x00, /* B6 */
|
||||
0x00, /* B7 */
|
||||
0x00, /* B8 */
|
||||
0x00, /* B9 */
|
||||
0x00, /* BA */
|
||||
0x00, /* BB */
|
||||
0x00, /* BC */
|
||||
0x00, /* BD */
|
||||
0x00, /* BE */
|
||||
0x00, /* BF */
|
||||
0x00, /* C0 */
|
||||
0x00, /* C1 */
|
||||
0x00, /* C2 */
|
||||
0x00, /* C3 */
|
||||
0x00, /* C4 */
|
||||
0x00, /* C5 */
|
||||
0x00, /* C6 */
|
||||
0x00, /* C7 */
|
||||
0x00, /* C8 */
|
||||
0x00, /* C9 */
|
||||
0x00, /* CA */
|
||||
0x00, /* CB */
|
||||
0x00, /* CC */
|
||||
0x00, /* CD */
|
||||
0x00, /* CE */
|
||||
0x00, /* CF */
|
||||
0x00, /* D0 */
|
||||
0x00, /* D1 */
|
||||
0x00, /* D2 */
|
||||
0x00, /* D3 */
|
||||
0x00, /* D4 */
|
||||
0x00, /* D5 */
|
||||
0x00, /* D6 */
|
||||
0x00, /* D7 */
|
||||
0x00, /* D8 */
|
||||
0x00, /* D9 */
|
||||
0x00, /* DA */
|
||||
0x00, /* DB */
|
||||
0x00, /* DC */
|
||||
0x00, /* DD */
|
||||
0x00, /* DE */
|
||||
0x00, /* DF */
|
||||
0x00, /* E0 */
|
||||
0x00, /* E1 */
|
||||
0x00, /* E2 */
|
||||
0x00, /* E3 */
|
||||
0x00, /* E4 */
|
||||
0x00, /* E5 */
|
||||
0x00, /* E6 */
|
||||
0x00, /* E7 */
|
||||
0x00, /* E8 */
|
||||
0x00, /* E9 */
|
||||
0x00, /* EA */
|
||||
0x00, /* EB */
|
||||
0x00, /* EC */
|
||||
0x00, /* ED */
|
||||
0x00, /* EE */
|
||||
0x00, /* EF */
|
||||
0x00, /* F0 */
|
||||
0x00, /* F1 */
|
||||
0x00, /* F2 */
|
||||
0x00, /* F3 */
|
||||
0x00, /* F4 */
|
||||
0x00, /* F5 */
|
||||
0x00, /* F6 */
|
||||
0x00, /* F7 */
|
||||
0x00, /* F8 */
|
||||
0x00, /* F9 */
|
||||
0x00, /* FA */
|
||||
0x00, /* FB */
|
||||
0x00, /* FC */
|
||||
0x00, /* FD */
|
||||
0x00, /* FE */
|
||||
0x00, /* FF */
|
||||
static const struct reg_default max98095_reg_def[] = {
|
||||
{ 0xf, 0x00 }, /* 0F */
|
||||
{ 0x10, 0x00 }, /* 10 */
|
||||
{ 0x11, 0x00 }, /* 11 */
|
||||
{ 0x12, 0x00 }, /* 12 */
|
||||
{ 0x13, 0x00 }, /* 13 */
|
||||
{ 0x14, 0x00 }, /* 14 */
|
||||
{ 0x15, 0x00 }, /* 15 */
|
||||
{ 0x16, 0x00 }, /* 16 */
|
||||
{ 0x17, 0x00 }, /* 17 */
|
||||
{ 0x18, 0x00 }, /* 18 */
|
||||
{ 0x19, 0x00 }, /* 19 */
|
||||
{ 0x1a, 0x00 }, /* 1A */
|
||||
{ 0x1b, 0x00 }, /* 1B */
|
||||
{ 0x1c, 0x00 }, /* 1C */
|
||||
{ 0x1d, 0x00 }, /* 1D */
|
||||
{ 0x1e, 0x00 }, /* 1E */
|
||||
{ 0x1f, 0x00 }, /* 1F */
|
||||
{ 0x20, 0x00 }, /* 20 */
|
||||
{ 0x21, 0x00 }, /* 21 */
|
||||
{ 0x22, 0x00 }, /* 22 */
|
||||
{ 0x23, 0x00 }, /* 23 */
|
||||
{ 0x24, 0x00 }, /* 24 */
|
||||
{ 0x25, 0x00 }, /* 25 */
|
||||
{ 0x26, 0x00 }, /* 26 */
|
||||
{ 0x27, 0x00 }, /* 27 */
|
||||
{ 0x28, 0x00 }, /* 28 */
|
||||
{ 0x29, 0x00 }, /* 29 */
|
||||
{ 0x2a, 0x00 }, /* 2A */
|
||||
{ 0x2b, 0x00 }, /* 2B */
|
||||
{ 0x2c, 0x00 }, /* 2C */
|
||||
{ 0x2d, 0x00 }, /* 2D */
|
||||
{ 0x2e, 0x00 }, /* 2E */
|
||||
{ 0x2f, 0x00 }, /* 2F */
|
||||
{ 0x30, 0x00 }, /* 30 */
|
||||
{ 0x31, 0x00 }, /* 31 */
|
||||
{ 0x32, 0x00 }, /* 32 */
|
||||
{ 0x33, 0x00 }, /* 33 */
|
||||
{ 0x34, 0x00 }, /* 34 */
|
||||
{ 0x35, 0x00 }, /* 35 */
|
||||
{ 0x36, 0x00 }, /* 36 */
|
||||
{ 0x37, 0x00 }, /* 37 */
|
||||
{ 0x38, 0x00 }, /* 38 */
|
||||
{ 0x39, 0x00 }, /* 39 */
|
||||
{ 0x3a, 0x00 }, /* 3A */
|
||||
{ 0x3b, 0x00 }, /* 3B */
|
||||
{ 0x3c, 0x00 }, /* 3C */
|
||||
{ 0x3d, 0x00 }, /* 3D */
|
||||
{ 0x3e, 0x00 }, /* 3E */
|
||||
{ 0x3f, 0x00 }, /* 3F */
|
||||
{ 0x40, 0x00 }, /* 40 */
|
||||
{ 0x41, 0x00 }, /* 41 */
|
||||
{ 0x42, 0x00 }, /* 42 */
|
||||
{ 0x43, 0x00 }, /* 43 */
|
||||
{ 0x44, 0x00 }, /* 44 */
|
||||
{ 0x45, 0x00 }, /* 45 */
|
||||
{ 0x46, 0x00 }, /* 46 */
|
||||
{ 0x47, 0x00 }, /* 47 */
|
||||
{ 0x48, 0x00 }, /* 48 */
|
||||
{ 0x49, 0x00 }, /* 49 */
|
||||
{ 0x4a, 0x00 }, /* 4A */
|
||||
{ 0x4b, 0x00 }, /* 4B */
|
||||
{ 0x4c, 0x00 }, /* 4C */
|
||||
{ 0x4d, 0x00 }, /* 4D */
|
||||
{ 0x4e, 0x00 }, /* 4E */
|
||||
{ 0x4f, 0x00 }, /* 4F */
|
||||
{ 0x50, 0x00 }, /* 50 */
|
||||
{ 0x51, 0x00 }, /* 51 */
|
||||
{ 0x52, 0x00 }, /* 52 */
|
||||
{ 0x53, 0x00 }, /* 53 */
|
||||
{ 0x54, 0x00 }, /* 54 */
|
||||
{ 0x55, 0x00 }, /* 55 */
|
||||
{ 0x56, 0x00 }, /* 56 */
|
||||
{ 0x57, 0x00 }, /* 57 */
|
||||
{ 0x58, 0x00 }, /* 58 */
|
||||
{ 0x59, 0x00 }, /* 59 */
|
||||
{ 0x5a, 0x00 }, /* 5A */
|
||||
{ 0x5b, 0x00 }, /* 5B */
|
||||
{ 0x5c, 0x00 }, /* 5C */
|
||||
{ 0x5d, 0x00 }, /* 5D */
|
||||
{ 0x5e, 0x00 }, /* 5E */
|
||||
{ 0x5f, 0x00 }, /* 5F */
|
||||
{ 0x60, 0x00 }, /* 60 */
|
||||
{ 0x61, 0x00 }, /* 61 */
|
||||
{ 0x62, 0x00 }, /* 62 */
|
||||
{ 0x63, 0x00 }, /* 63 */
|
||||
{ 0x64, 0x00 }, /* 64 */
|
||||
{ 0x65, 0x00 }, /* 65 */
|
||||
{ 0x66, 0x00 }, /* 66 */
|
||||
{ 0x67, 0x00 }, /* 67 */
|
||||
{ 0x68, 0x00 }, /* 68 */
|
||||
{ 0x69, 0x00 }, /* 69 */
|
||||
{ 0x6a, 0x00 }, /* 6A */
|
||||
{ 0x6b, 0x00 }, /* 6B */
|
||||
{ 0x6c, 0x00 }, /* 6C */
|
||||
{ 0x6d, 0x00 }, /* 6D */
|
||||
{ 0x6e, 0x00 }, /* 6E */
|
||||
{ 0x6f, 0x00 }, /* 6F */
|
||||
{ 0x70, 0x00 }, /* 70 */
|
||||
{ 0x71, 0x00 }, /* 71 */
|
||||
{ 0x72, 0x00 }, /* 72 */
|
||||
{ 0x73, 0x00 }, /* 73 */
|
||||
{ 0x74, 0x00 }, /* 74 */
|
||||
{ 0x75, 0x00 }, /* 75 */
|
||||
{ 0x76, 0x00 }, /* 76 */
|
||||
{ 0x77, 0x00 }, /* 77 */
|
||||
{ 0x78, 0x00 }, /* 78 */
|
||||
{ 0x79, 0x00 }, /* 79 */
|
||||
{ 0x7a, 0x00 }, /* 7A */
|
||||
{ 0x7b, 0x00 }, /* 7B */
|
||||
{ 0x7c, 0x00 }, /* 7C */
|
||||
{ 0x7d, 0x00 }, /* 7D */
|
||||
{ 0x7e, 0x00 }, /* 7E */
|
||||
{ 0x7f, 0x00 }, /* 7F */
|
||||
{ 0x80, 0x00 }, /* 80 */
|
||||
{ 0x81, 0x00 }, /* 81 */
|
||||
{ 0x82, 0x00 }, /* 82 */
|
||||
{ 0x83, 0x00 }, /* 83 */
|
||||
{ 0x84, 0x00 }, /* 84 */
|
||||
{ 0x85, 0x00 }, /* 85 */
|
||||
{ 0x86, 0x00 }, /* 86 */
|
||||
{ 0x87, 0x00 }, /* 87 */
|
||||
{ 0x88, 0x00 }, /* 88 */
|
||||
{ 0x89, 0x00 }, /* 89 */
|
||||
{ 0x8a, 0x00 }, /* 8A */
|
||||
{ 0x8b, 0x00 }, /* 8B */
|
||||
{ 0x8c, 0x00 }, /* 8C */
|
||||
{ 0x8d, 0x00 }, /* 8D */
|
||||
{ 0x8e, 0x00 }, /* 8E */
|
||||
{ 0x8f, 0x00 }, /* 8F */
|
||||
{ 0x90, 0x00 }, /* 90 */
|
||||
{ 0x91, 0x00 }, /* 91 */
|
||||
{ 0x92, 0x30 }, /* 92 */
|
||||
{ 0x93, 0xF0 }, /* 93 */
|
||||
{ 0x94, 0x00 }, /* 94 */
|
||||
{ 0x95, 0x00 }, /* 95 */
|
||||
{ 0x96, 0x3F }, /* 96 */
|
||||
{ 0x97, 0x00 }, /* 97 */
|
||||
{ 0xff, 0x00 }, /* FF */
|
||||
};
|
||||
|
||||
static struct {
|
||||
|
@ -577,14 +460,14 @@ static struct {
|
|||
{ 0xFF, 0x00 }, /* FF */
|
||||
};
|
||||
|
||||
static int max98095_readable(struct snd_soc_codec *codec, unsigned int reg)
|
||||
static bool max98095_readable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
if (reg >= M98095_REG_CNT)
|
||||
return 0;
|
||||
return max98095_access[reg].readable != 0;
|
||||
}
|
||||
|
||||
static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)
|
||||
static bool max98095_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
if (reg > M98095_REG_MAX_CACHED)
|
||||
return 1;
|
||||
|
@ -611,22 +494,18 @@ static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Filter coefficients are in a separate register segment
|
||||
* and they share the address space of the normal registers.
|
||||
* The coefficient registers do not need or share the cache.
|
||||
*/
|
||||
static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
int ret;
|
||||
static const struct regmap_config max98095_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
codec->cache_bypass = 1;
|
||||
ret = snd_soc_write(codec, reg, value);
|
||||
codec->cache_bypass = 0;
|
||||
.reg_defaults = max98095_reg_def,
|
||||
.num_reg_defaults = ARRAY_SIZE(max98095_reg_def),
|
||||
.max_register = M98095_0FF_REV_ID,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
return ret ? -EIO : 0;
|
||||
}
|
||||
.readable_reg = max98095_readable,
|
||||
.volatile_reg = max98095_volatile,
|
||||
};
|
||||
|
||||
/*
|
||||
* Load equalizer DSP coefficient configurations registers
|
||||
|
@ -648,8 +527,8 @@ static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,
|
|||
|
||||
/* Step through the registers and coefs */
|
||||
for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
|
||||
max98095_hw_write(codec, eq_reg++, M98095_BYTE1(coefs[i]));
|
||||
max98095_hw_write(codec, eq_reg++, M98095_BYTE0(coefs[i]));
|
||||
snd_soc_write(codec, eq_reg++, M98095_BYTE1(coefs[i]));
|
||||
snd_soc_write(codec, eq_reg++, M98095_BYTE0(coefs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -673,8 +552,8 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
|
|||
|
||||
/* Step through the registers and coefs */
|
||||
for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
|
||||
max98095_hw_write(codec, bq_reg++, M98095_BYTE1(coefs[i]));
|
||||
max98095_hw_write(codec, bq_reg++, M98095_BYTE0(coefs[i]));
|
||||
snd_soc_write(codec, bq_reg++, M98095_BYTE1(coefs[i]));
|
||||
snd_soc_write(codec, bq_reg++, M98095_BYTE0(coefs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1285,14 +1164,6 @@ static const struct snd_soc_dapm_route max98095_audio_map[] = {
|
|||
{"MIC2 Input", NULL, "MIC2"},
|
||||
};
|
||||
|
||||
static int max98095_add_widgets(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_soc_add_codec_controls(codec, max98095_snd_controls,
|
||||
ARRAY_SIZE(max98095_snd_controls));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* codec mclk clock divider coefficients */
|
||||
static const struct {
|
||||
u32 rate;
|
||||
|
@ -1748,6 +1619,7 @@ static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
|
|||
static int max98095_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
switch (level) {
|
||||
|
@ -1759,7 +1631,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
|
|||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
|
||||
ret = snd_soc_cache_sync(codec);
|
||||
ret = regcache_sync(max98095->regmap);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
|
||||
|
@ -1774,7 +1646,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
|
|||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
|
||||
M98095_MBEN, 0);
|
||||
codec->cache_sync = 1;
|
||||
regcache_mark_dirty(max98095->regmap);
|
||||
break;
|
||||
}
|
||||
codec->dapm.bias_level = level;
|
||||
|
@ -2341,7 +2213,7 @@ static int max98095_reset(struct snd_soc_codec *codec)
|
|||
/* Reset to hardware default for registers, as there is not
|
||||
* a soft reset hardware control register */
|
||||
for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
|
||||
ret = snd_soc_write(codec, i, max98095_reg_def[i]);
|
||||
ret = snd_soc_write(codec, i, snd_soc_read(codec, i));
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to reset: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -2358,7 +2230,7 @@ static int max98095_probe(struct snd_soc_codec *codec)
|
|||
struct i2c_client *client;
|
||||
int ret = 0;
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -2447,8 +2319,6 @@ static int max98095_probe(struct snd_soc_codec *codec)
|
|||
snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN,
|
||||
M98095_SHDNRUN);
|
||||
|
||||
max98095_add_widgets(codec);
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq:
|
||||
|
@ -2480,11 +2350,8 @@ static struct snd_soc_codec_driver soc_codec_dev_max98095 = {
|
|||
.suspend = max98095_suspend,
|
||||
.resume = max98095_resume,
|
||||
.set_bias_level = max98095_set_bias_level,
|
||||
.reg_cache_size = ARRAY_SIZE(max98095_reg_def),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = max98095_reg_def,
|
||||
.readable_register = max98095_readable,
|
||||
.volatile_register = max98095_volatile,
|
||||
.controls = max98095_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(max98095_snd_controls),
|
||||
.dapm_widgets = max98095_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets),
|
||||
.dapm_routes = max98095_audio_map,
|
||||
|
@ -2502,6 +2369,13 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
|
|||
if (max98095 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap);
|
||||
if (IS_ERR(max98095->regmap)) {
|
||||
ret = PTR_ERR(max98095->regmap);
|
||||
dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
max98095->devtype = id->driver_data;
|
||||
i2c_set_clientdata(i2c, max98095);
|
||||
max98095->pdata = i2c->dev.platform_data;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
@ -27,18 +28,26 @@
|
|||
#include "max9850.h"
|
||||
|
||||
struct max9850_priv {
|
||||
struct regmap *regmap;
|
||||
unsigned int sysclk;
|
||||
};
|
||||
|
||||
/* max9850 register cache */
|
||||
static const u8 max9850_reg[MAX9850_CACHEREGNUM] = {
|
||||
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
static const struct reg_default max9850_reg[] = {
|
||||
{ 2, 0x0c },
|
||||
{ 3, 0x00 },
|
||||
{ 4, 0x00 },
|
||||
{ 5, 0x00 },
|
||||
{ 6, 0x00 },
|
||||
{ 7, 0x00 },
|
||||
{ 8, 0x00 },
|
||||
{ 9, 0x00 },
|
||||
{ 10, 0x00 },
|
||||
};
|
||||
|
||||
/* these registers are not used at the moment but provided for the sake of
|
||||
* completeness */
|
||||
static int max9850_volatile_register(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
static bool max9850_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MAX9850_STATUSA:
|
||||
|
@ -49,6 +58,15 @@ static int max9850_volatile_register(struct snd_soc_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config max9850_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = MAX9850_DIGITAL_AUDIO,
|
||||
.volatile_reg = max9850_volatile_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static const unsigned int max9850_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(4),
|
||||
0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0),
|
||||
|
@ -225,6 +243,7 @@ static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
|||
static int max9850_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
switch (level) {
|
||||
|
@ -234,7 +253,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
|
|||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
|
||||
ret = snd_soc_cache_sync(codec);
|
||||
ret = regcache_sync(max9850->regmap);
|
||||
if (ret) {
|
||||
dev_err(codec->dev,
|
||||
"Failed to sync cache: %d\n", ret);
|
||||
|
@ -295,7 +314,7 @@ static int max9850_probe(struct snd_soc_codec *codec)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -316,10 +335,6 @@ static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
|
|||
.suspend = max9850_suspend,
|
||||
.resume = max9850_resume,
|
||||
.set_bias_level = max9850_set_bias_level,
|
||||
.reg_cache_size = ARRAY_SIZE(max9850_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = max9850_reg,
|
||||
.volatile_register = max9850_volatile_register,
|
||||
|
||||
.controls = max9850_controls,
|
||||
.num_controls = ARRAY_SIZE(max9850_controls),
|
||||
|
@ -340,6 +355,10 @@ static int max9850_i2c_probe(struct i2c_client *i2c,
|
|||
if (max9850 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
max9850->regmap = devm_regmap_init_i2c(i2c, &max9850_regmap);
|
||||
if (IS_ERR(max9850->regmap))
|
||||
return PTR_ERR(max9850->regmap);
|
||||
|
||||
i2c_set_clientdata(i2c, max9850);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
|
|
|
@ -30,16 +30,10 @@
|
|||
#include <sound/soc.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "mc13783.h"
|
||||
|
||||
#define MC13783_AUDIO_RX0 36
|
||||
#define MC13783_AUDIO_RX1 37
|
||||
#define MC13783_AUDIO_TX 38
|
||||
#define MC13783_SSI_NETWORK 39
|
||||
#define MC13783_AUDIO_CODEC 40
|
||||
#define MC13783_AUDIO_DAC 41
|
||||
|
||||
#define AUDIO_RX0_ALSPEN (1 << 5)
|
||||
#define AUDIO_RX0_ALSPSEL (1 << 7)
|
||||
#define AUDIO_RX0_ADDCDC (1 << 21)
|
||||
|
@ -95,45 +89,12 @@
|
|||
|
||||
struct mc13783_priv {
|
||||
struct mc13xxx *mc13xxx;
|
||||
struct regmap *regmap;
|
||||
|
||||
enum mc13783_ssi_port adc_ssi_port;
|
||||
enum mc13783_ssi_port dac_ssi_port;
|
||||
};
|
||||
|
||||
static unsigned int mc13783_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int value = 0;
|
||||
|
||||
mc13xxx_lock(priv->mc13xxx);
|
||||
|
||||
mc13xxx_reg_read(priv->mc13xxx, reg, &value);
|
||||
|
||||
mc13xxx_unlock(priv->mc13xxx);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int mc13783_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
mc13xxx_lock(priv->mc13xxx);
|
||||
|
||||
ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
|
||||
|
||||
/* include errata fix for spi audio problems */
|
||||
if (reg == MC13783_AUDIO_CODEC || reg == MC13783_AUDIO_DAC)
|
||||
ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
|
||||
|
||||
mc13xxx_unlock(priv->mc13xxx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Mapping between sample rates and register value */
|
||||
static unsigned int mc13783_rates[] = {
|
||||
8000, 11025, 12000, 16000,
|
||||
|
@ -466,6 +427,29 @@ static const struct snd_kcontrol_new right_input_mux =
|
|||
static const struct snd_kcontrol_new samp_ctl =
|
||||
SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0);
|
||||
|
||||
static const char * const speaker_amp_source_text[] = {
|
||||
"CODEC", "Right"
|
||||
};
|
||||
static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4,
|
||||
speaker_amp_source_text);
|
||||
static const struct snd_kcontrol_new speaker_amp_source_mux =
|
||||
SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source);
|
||||
|
||||
static const char * const headset_amp_source_text[] = {
|
||||
"CODEC", "Mixer"
|
||||
};
|
||||
|
||||
static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11,
|
||||
headset_amp_source_text);
|
||||
static const struct snd_kcontrol_new headset_amp_source_mux =
|
||||
SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source);
|
||||
|
||||
static const struct snd_kcontrol_new cdcout_ctl =
|
||||
SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 18, 1, 0);
|
||||
|
||||
static const struct snd_kcontrol_new adc_bypass_ctl =
|
||||
SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_CODEC, 16, 1, 0);
|
||||
|
||||
static const struct snd_kcontrol_new lamp_ctl =
|
||||
SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0);
|
||||
|
||||
|
@ -503,12 +487,22 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
|
||||
&right_input_mux),
|
||||
|
||||
SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0,
|
||||
&speaker_amp_source_mux),
|
||||
|
||||
SND_SOC_DAPM_MUX("Headset Amp Source MUX", SND_SOC_NOPM, 0, 0,
|
||||
&headset_amp_source_mux),
|
||||
|
||||
SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("Voice CODEC PGA", MC13783_AUDIO_RX1, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SWITCH("Voice CODEC Bypass", MC13783_AUDIO_CODEC, 16, 0,
|
||||
&adc_bypass_ctl),
|
||||
|
||||
/* Output */
|
||||
SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0),
|
||||
|
@ -516,10 +510,15 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_OUTPUT("RXOUTR"),
|
||||
SND_SOC_DAPM_OUTPUT("HSL"),
|
||||
SND_SOC_DAPM_OUTPUT("HSR"),
|
||||
SND_SOC_DAPM_OUTPUT("LSPL"),
|
||||
SND_SOC_DAPM_OUTPUT("LSP"),
|
||||
SND_SOC_DAPM_OUTPUT("SP"),
|
||||
SND_SOC_DAPM_OUTPUT("CDCOUT"),
|
||||
|
||||
SND_SOC_DAPM_SWITCH("Speaker Amp", MC13783_AUDIO_RX0, 3, 0, &samp_ctl),
|
||||
SND_SOC_DAPM_SWITCH("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 0,
|
||||
&cdcout_ctl),
|
||||
SND_SOC_DAPM_SWITCH("Speaker Amp Switch", MC13783_AUDIO_RX0, 3, 0,
|
||||
&samp_ctl),
|
||||
SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),
|
||||
SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0,
|
||||
&hlamp_ctl),
|
||||
|
@ -554,20 +553,28 @@ static struct snd_soc_dapm_route mc13783_routes[] = {
|
|||
{ "ADC", NULL, "PGA Right Input"},
|
||||
{ "ADC", NULL, "ADC_Reset"},
|
||||
|
||||
{ "Voice CODEC PGA", "Voice CODEC Bypass", "ADC" },
|
||||
|
||||
{ "Speaker Amp Source MUX", "CODEC", "Voice CODEC PGA"},
|
||||
{ "Speaker Amp Source MUX", "Right", "DAC PGA"},
|
||||
|
||||
{ "Headset Amp Source MUX", "CODEC", "Voice CODEC PGA"},
|
||||
{ "Headset Amp Source MUX", "Mixer", "DAC PGA"},
|
||||
|
||||
/* Output */
|
||||
{ "HSL", NULL, "Headset Amp Left" },
|
||||
{ "HSR", NULL, "Headset Amp Right"},
|
||||
{ "RXOUTL", NULL, "Line out Amp Left"},
|
||||
{ "RXOUTR", NULL, "Line out Amp Right"},
|
||||
{ "SP", NULL, "Speaker Amp"},
|
||||
{ "Speaker Amp", NULL, "DAC PGA"},
|
||||
{ "LSP", NULL, "DAC PGA"},
|
||||
{ "Headset Amp Left", NULL, "DAC PGA"},
|
||||
{ "Headset Amp Right", NULL, "DAC PGA"},
|
||||
{ "SP", "Speaker Amp Switch", "Speaker Amp Source MUX"},
|
||||
{ "LSP", "Loudspeaker Amp", "Speaker Amp Source MUX"},
|
||||
{ "HSL", "Headset Amp Left", "Headset Amp Source MUX"},
|
||||
{ "HSR", "Headset Amp Right", "Headset Amp Source MUX"},
|
||||
{ "Line out Amp Left", NULL, "DAC PGA"},
|
||||
{ "Line out Amp Right", NULL, "DAC PGA"},
|
||||
{ "DAC PGA", NULL, "DAC"},
|
||||
{ "DAC", NULL, "DAC_E"},
|
||||
{ "CDCOUT", "CDCOUT Switch", "Voice CODEC PGA"},
|
||||
};
|
||||
|
||||
static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
|
||||
|
@ -580,15 +587,39 @@ static const struct soc_enum mc13783_enum_3d_mixer =
|
|||
static struct snd_kcontrol_new mc13783_control_list[] = {
|
||||
SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
|
||||
SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0),
|
||||
SOC_SINGLE("PCM Playback Switch", MC13783_AUDIO_RX1, 5, 1, 0),
|
||||
SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),
|
||||
SOC_ENUM("3D Control", mc13783_enum_3d_mixer),
|
||||
|
||||
SOC_SINGLE("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 1, 0),
|
||||
SOC_SINGLE("Earpiece Amp Switch", MC13783_AUDIO_RX0, 3, 1, 0),
|
||||
SOC_DOUBLE("Headset Amp Switch", MC13783_AUDIO_RX0, 10, 9, 1, 0),
|
||||
SOC_DOUBLE("Line out Amp Switch", MC13783_AUDIO_RX0, 16, 15, 1, 0),
|
||||
|
||||
SOC_SINGLE("PCM Capture Mixin Switch", MC13783_AUDIO_RX0, 22, 1, 0),
|
||||
SOC_SINGLE("Line in Capture Mixin Switch", MC13783_AUDIO_RX0, 23, 1, 0),
|
||||
|
||||
SOC_SINGLE("CODEC Capture Volume", MC13783_AUDIO_RX1, 1, 15, 0),
|
||||
SOC_SINGLE("CODEC Capture Mixin Switch", MC13783_AUDIO_RX0, 21, 1, 0),
|
||||
|
||||
SOC_SINGLE("Line in Capture Volume", MC13783_AUDIO_RX1, 12, 15, 0),
|
||||
SOC_SINGLE("Line in Capture Switch", MC13783_AUDIO_RX1, 10, 1, 0),
|
||||
|
||||
SOC_SINGLE("MC1 Capture Bias Switch", MC13783_AUDIO_TX, 0, 1, 0),
|
||||
SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0),
|
||||
};
|
||||
|
||||
static int mc13783_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
mc13xxx_lock(priv->mc13xxx);
|
||||
codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 24, SND_SOC_REGMAP);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* these are the reset values */
|
||||
mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
|
||||
|
@ -612,8 +643,6 @@ static int mc13783_probe(struct snd_soc_codec *codec)
|
|||
mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
|
||||
0, AUDIO_SSI_SEL);
|
||||
|
||||
mc13xxx_unlock(priv->mc13xxx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -621,13 +650,9 @@ static int mc13783_remove(struct snd_soc_codec *codec)
|
|||
{
|
||||
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
mc13xxx_lock(priv->mc13xxx);
|
||||
|
||||
/* Make sure VAUDIOON is off */
|
||||
mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0);
|
||||
|
||||
mc13xxx_unlock(priv->mc13xxx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -717,8 +742,6 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {
|
|||
static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
|
||||
.probe = mc13783_probe,
|
||||
.remove = mc13783_remove,
|
||||
.read = mc13783_read,
|
||||
.write = mc13783_write,
|
||||
.controls = mc13783_control_list,
|
||||
.num_controls = ARRAY_SIZE(mc13783_control_list),
|
||||
.dapm_widgets = mc13783_dapm_widgets,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <sound/pcm.h>
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include "pcm1792a.h"
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
@ -926,7 +927,7 @@ static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void hp_amp_power_on(struct snd_soc_codec *codec)
|
||||
static void hp_amp_power_on(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
|
@ -1609,7 +1610,8 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
|
|||
rt5640->lrck[dai->id] = params_rate(params);
|
||||
pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);
|
||||
if (pre_div < 0) {
|
||||
dev_err(codec->dev, "Unsupported clock setting\n");
|
||||
dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
|
||||
rt5640->lrck[dai->id], dai->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
frame_size = snd_soc_params_to_frame_size(params);
|
||||
|
@ -1977,13 +1979,20 @@ static int rt5640_suspend(struct snd_soc_codec *codec)
|
|||
rt5640_reset(codec);
|
||||
regcache_cache_only(rt5640->regmap, true);
|
||||
regcache_mark_dirty(rt5640->regmap);
|
||||
if (gpio_is_valid(rt5640->pdata.ldo1_en))
|
||||
gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5640_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
|
||||
gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1);
|
||||
msleep(400);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2080,6 +2089,14 @@ static const struct i2c_device_id rt5640_i2c_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static struct acpi_device_id rt5640_acpi_match[] = {
|
||||
{ "INT33CA", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
|
||||
#endif
|
||||
|
||||
static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
|
||||
{
|
||||
rt5640->pdata.in1_diff = of_property_read_bool(np,
|
||||
|
@ -2199,6 +2216,7 @@ static struct i2c_driver rt5640_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "rt5640",
|
||||
.owner = THIS_MODULE,
|
||||
.acpi_match_table = ACPI_PTR(rt5640_acpi_match),
|
||||
},
|
||||
.probe = rt5640_i2c_probe,
|
||||
.remove = rt5640_i2c_remove,
|
||||
|
|
|
@ -60,48 +60,6 @@ enum si476x_pcm_format {
|
|||
SI476X_PCM_FORMAT_S24_LE = 6,
|
||||
};
|
||||
|
||||
static unsigned int si476x_codec_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
int err;
|
||||
unsigned int val;
|
||||
struct si476x_core *core = codec->control_data;
|
||||
|
||||
si476x_core_lock(core);
|
||||
if (!si476x_core_is_powered_up(core))
|
||||
regcache_cache_only(core->regmap, true);
|
||||
|
||||
err = regmap_read(core->regmap, reg, &val);
|
||||
|
||||
if (!si476x_core_is_powered_up(core))
|
||||
regcache_cache_only(core->regmap, false);
|
||||
si476x_core_unlock(core);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int si476x_codec_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int val)
|
||||
{
|
||||
int err;
|
||||
struct si476x_core *core = codec->control_data;
|
||||
|
||||
si476x_core_lock(core);
|
||||
if (!si476x_core_is_powered_up(core))
|
||||
regcache_cache_only(core->regmap, true);
|
||||
|
||||
err = regmap_write(core->regmap, reg, val);
|
||||
|
||||
if (!si476x_core_is_powered_up(core))
|
||||
regcache_cache_only(core->regmap, false);
|
||||
si476x_core_unlock(core);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget si476x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_OUTPUT("LOUT"),
|
||||
SND_SOC_DAPM_OUTPUT("ROUT"),
|
||||
|
@ -115,6 +73,7 @@ static const struct snd_soc_dapm_route si476x_dapm_routes[] = {
|
|||
static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct si476x_core *core = i2c_mfd_cell_to_core(codec_dai->dev);
|
||||
int err;
|
||||
u16 format = 0;
|
||||
|
||||
|
@ -178,9 +137,14 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
si476x_core_lock(core);
|
||||
|
||||
err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
|
||||
SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK,
|
||||
format);
|
||||
|
||||
si476x_core_unlock(core);
|
||||
|
||||
if (err < 0) {
|
||||
dev_err(codec_dai->codec->dev, "Failed to set output format\n");
|
||||
return err;
|
||||
|
@ -193,6 +157,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct si476x_core *core = i2c_mfd_cell_to_core(dai->dev);
|
||||
int rate, width, err;
|
||||
|
||||
rate = params_rate(params);
|
||||
|
@ -218,11 +183,13 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
si476x_core_lock(core);
|
||||
|
||||
err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE,
|
||||
rate);
|
||||
if (err < 0) {
|
||||
dev_err(dai->codec->dev, "Failed to set sample rate\n");
|
||||
return err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
|
||||
|
@ -231,15 +198,18 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
|
|||
(width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));
|
||||
if (err < 0) {
|
||||
dev_err(dai->codec->dev, "Failed to set output width\n");
|
||||
return err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
si476x_core_unlock(core);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int si476x_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
codec->control_data = i2c_mfd_cell_to_core(codec->dev);
|
||||
codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -268,8 +238,6 @@ static struct snd_soc_dai_driver si476x_dai = {
|
|||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_si476x = {
|
||||
.probe = si476x_codec_probe,
|
||||
.read = si476x_codec_read,
|
||||
.write = si476x_codec_write,
|
||||
.dapm_widgets = si476x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets),
|
||||
.dapm_routes = si476x_dapm_routes,
|
||||
|
|
|
@ -164,30 +164,28 @@ static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec)
|
|||
}
|
||||
/*end - adc helper functions */
|
||||
|
||||
static inline unsigned int sn95031_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
static int sn95031_read(void *ctx, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
u8 value = 0;
|
||||
int ret;
|
||||
|
||||
ret = intel_scu_ipc_ioread8(reg, &value);
|
||||
if (ret)
|
||||
pr_err("read of %x failed, err %d\n", reg, ret);
|
||||
return value;
|
||||
if (ret == 0)
|
||||
*val = value;
|
||||
|
||||
}
|
||||
|
||||
static inline int sn95031_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = intel_scu_ipc_iowrite8(reg, value);
|
||||
if (ret)
|
||||
pr_err("write of %x failed, err %d\n", reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sn95031_write(void *ctx, unsigned int reg, unsigned int value)
|
||||
{
|
||||
return intel_scu_ipc_iowrite8(reg, value);
|
||||
}
|
||||
|
||||
static const struct regmap_config sn95031_regmap = {
|
||||
.reg_read = sn95031_read,
|
||||
.reg_write = sn95031_write,
|
||||
};
|
||||
|
||||
static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
|
@ -827,6 +825,8 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
|
|||
{
|
||||
pr_debug("codec_probe called\n");
|
||||
|
||||
snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
|
||||
|
||||
/* PCM interface config
|
||||
* This sets the pcm rx slot conguration to max 6 slots
|
||||
* for max 4 dais (2 stereo and 2 mono)
|
||||
|
@ -886,8 +886,6 @@ static int sn95031_codec_remove(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_codec_driver sn95031_codec = {
|
||||
.probe = sn95031_codec_probe,
|
||||
.remove = sn95031_codec_remove,
|
||||
.read = sn95031_read,
|
||||
.write = sn95031_write,
|
||||
.set_bias_level = sn95031_set_vaud_bias,
|
||||
.idle_bias_off = true,
|
||||
.dapm_widgets = sn95031_dapm_widgets,
|
||||
|
@ -898,7 +896,14 @@ static struct snd_soc_codec_driver sn95031_codec = {
|
|||
|
||||
static int sn95031_device_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev));
|
||||
|
||||
regmap = devm_regmap_init(&pdev->dev, NULL, NULL, &sn95031_regmap);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
return snd_soc_register_codec(&pdev->dev, &sn95031_codec,
|
||||
sn95031_dais, ARRAY_SIZE(sn95031_dais));
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <sound/pcm.h>
|
||||
|
@ -244,6 +245,8 @@ struct tas5086_private {
|
|||
unsigned int mclk, sclk;
|
||||
unsigned int format;
|
||||
bool deemph;
|
||||
unsigned int charge_period;
|
||||
unsigned int pwm_start_mid_z;
|
||||
/* Current sample rate for de-emphasis control */
|
||||
int rate;
|
||||
/* GPIO driving Reset pin, if any */
|
||||
|
@ -456,6 +459,75 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
|
|||
return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);
|
||||
}
|
||||
|
||||
static void tas5086_reset(struct tas5086_private *priv)
|
||||
{
|
||||
if (gpio_is_valid(priv->gpio_nreset)) {
|
||||
/* Reset codec - minimum assertion time is 400ns */
|
||||
gpio_direction_output(priv->gpio_nreset, 0);
|
||||
udelay(1);
|
||||
gpio_set_value(priv->gpio_nreset, 1);
|
||||
|
||||
/* Codec needs ~15ms to wake up */
|
||||
msleep(15);
|
||||
}
|
||||
}
|
||||
|
||||
/* charge period values in microseconds */
|
||||
static const int tas5086_charge_period[] = {
|
||||
13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200,
|
||||
130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000,
|
||||
1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
|
||||
};
|
||||
|
||||
static int tas5086_init(struct device *dev, struct tas5086_private *priv)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
/*
|
||||
* If any of the channels is configured to start in Mid-Z mode,
|
||||
* configure 'part 1' of the PWM starts to use Mid-Z, and tell
|
||||
* all configured mid-z channels to start start under 'part 1'.
|
||||
*/
|
||||
if (priv->pwm_start_mid_z)
|
||||
regmap_write(priv->regmap, TAS5086_PWM_START,
|
||||
TAS5086_PWM_START_MIDZ_FOR_START_1 |
|
||||
priv->pwm_start_mid_z);
|
||||
|
||||
/* lookup and set split-capacitor charge period */
|
||||
if (priv->charge_period == 0) {
|
||||
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
|
||||
} else {
|
||||
i = index_in_array(tas5086_charge_period,
|
||||
ARRAY_SIZE(tas5086_charge_period),
|
||||
priv->charge_period);
|
||||
if (i >= 0)
|
||||
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
|
||||
i + 0x08);
|
||||
else
|
||||
dev_warn(dev,
|
||||
"Invalid split-cap charge period of %d ns.\n",
|
||||
priv->charge_period);
|
||||
}
|
||||
|
||||
/* enable factory trim */
|
||||
ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* start all channels */
|
||||
ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* mute all channels for now */
|
||||
ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
|
||||
TAS5086_SOFT_MUTE_ALL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TAS5086 controls */
|
||||
static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);
|
||||
|
||||
|
@ -691,14 +763,39 @@ static struct snd_soc_dai_driver tas5086_dai = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tas5086_soc_suspend(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
/* Shut down all channels */
|
||||
ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x60);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas5086_soc_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
/* Restore codec state */
|
||||
return regcache_sync(priv->regmap);
|
||||
tas5086_reset(priv);
|
||||
regcache_mark_dirty(priv->regmap);
|
||||
|
||||
ret = tas5086_init(codec->dev, priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regcache_sync(priv->regmap);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define tas5086_soc_suspend NULL
|
||||
#define tas5086_soc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
@ -710,23 +807,19 @@ static const struct of_device_id tas5086_dt_ids[] = {
|
|||
MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
|
||||
#endif
|
||||
|
||||
/* charge period values in microseconds */
|
||||
static const int tas5086_charge_period[] = {
|
||||
13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200,
|
||||
130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000,
|
||||
1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
|
||||
};
|
||||
|
||||
static int tas5086_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int charge_period = 1300000; /* hardware default is 1300 ms */
|
||||
u8 pwm_start_mid_z = 0;
|
||||
int i, ret;
|
||||
|
||||
priv->pwm_start_mid_z = 0;
|
||||
priv->charge_period = 1300000; /* hardware default is 1300 ms */
|
||||
|
||||
if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
|
||||
struct device_node *of_node = codec->dev->of_node;
|
||||
of_property_read_u32(of_node, "ti,charge-period", &charge_period);
|
||||
|
||||
of_property_read_u32(of_node, "ti,charge-period",
|
||||
&priv->charge_period);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
char name[25];
|
||||
|
@ -735,43 +828,11 @@ static int tas5086_probe(struct snd_soc_codec *codec)
|
|||
"ti,mid-z-channel-%d", i + 1);
|
||||
|
||||
if (of_get_property(of_node, name, NULL) != NULL)
|
||||
pwm_start_mid_z |= 1 << i;
|
||||
priv->pwm_start_mid_z |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If any of the channels is configured to start in Mid-Z mode,
|
||||
* configure 'part 1' of the PWM starts to use Mid-Z, and tell
|
||||
* all configured mid-z channels to start start under 'part 1'.
|
||||
*/
|
||||
if (pwm_start_mid_z)
|
||||
regmap_write(priv->regmap, TAS5086_PWM_START,
|
||||
TAS5086_PWM_START_MIDZ_FOR_START_1 |
|
||||
pwm_start_mid_z);
|
||||
|
||||
/* lookup and set split-capacitor charge period */
|
||||
if (charge_period == 0) {
|
||||
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
|
||||
} else {
|
||||
i = index_in_array(tas5086_charge_period,
|
||||
ARRAY_SIZE(tas5086_charge_period),
|
||||
charge_period);
|
||||
if (i >= 0)
|
||||
regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
|
||||
i + 0x08);
|
||||
else
|
||||
dev_warn(codec->dev,
|
||||
"Invalid split-cap charge period of %d ns.\n",
|
||||
charge_period);
|
||||
}
|
||||
|
||||
/* enable factory trim */
|
||||
ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* start all channels */
|
||||
ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
|
||||
ret = tas5086_init(codec->dev, priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -780,12 +841,6 @@ static int tas5086_probe(struct snd_soc_codec *codec)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* mute all channels for now */
|
||||
ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
|
||||
TAS5086_SOFT_MUTE_ALL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -803,6 +858,7 @@ static int tas5086_remove(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
|
||||
.probe = tas5086_probe,
|
||||
.remove = tas5086_remove,
|
||||
.suspend = tas5086_soc_suspend,
|
||||
.resume = tas5086_soc_resume,
|
||||
.controls = tas5086_controls,
|
||||
.num_controls = ARRAY_SIZE(tas5086_controls),
|
||||
|
@ -862,17 +918,8 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
|
|||
if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
|
||||
gpio_nreset = -EINVAL;
|
||||
|
||||
if (gpio_is_valid(gpio_nreset)) {
|
||||
/* Reset codec - minimum assertion time is 400ns */
|
||||
gpio_direction_output(gpio_nreset, 0);
|
||||
udelay(1);
|
||||
gpio_set_value(gpio_nreset, 1);
|
||||
|
||||
/* Codec needs ~15ms to wake up */
|
||||
msleep(15);
|
||||
}
|
||||
|
||||
priv->gpio_nreset = gpio_nreset;
|
||||
tas5086_reset(priv);
|
||||
|
||||
/* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
|
||||
ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
|
@ -37,11 +38,27 @@
|
|||
/*
|
||||
* AIC23 register cache
|
||||
*/
|
||||
static const u16 tlv320aic23_reg[] = {
|
||||
0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */
|
||||
0x001A, 0x0004, 0x0007, 0x0001, /* 4 */
|
||||
0x0020, 0x0000, 0x0000, 0x0000, /* 8 */
|
||||
0x0000, 0x0000, 0x0000, 0x0000, /* 12 */
|
||||
static const struct reg_default tlv320aic23_reg[] = {
|
||||
{ 0, 0x0097 },
|
||||
{ 1, 0x0097 },
|
||||
{ 2, 0x00F9 },
|
||||
{ 3, 0x00F9 },
|
||||
{ 4, 0x001A },
|
||||
{ 5, 0x0004 },
|
||||
{ 6, 0x0007 },
|
||||
{ 7, 0x0001 },
|
||||
{ 8, 0x0020 },
|
||||
{ 9, 0x0000 },
|
||||
};
|
||||
|
||||
static const struct regmap_config tlv320aic23_regmap = {
|
||||
.reg_bits = 7,
|
||||
.val_bits = 9,
|
||||
|
||||
.max_register = TLV320AIC23_RESET,
|
||||
.reg_defaults = tlv320aic23_reg,
|
||||
.num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static const char *rec_src_text[] = { "Line", "Mic" };
|
||||
|
@ -171,7 +188,7 @@ static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
|
|||
|
||||
/* AIC23 driver data */
|
||||
struct aic23 {
|
||||
enum snd_soc_control_type control_type;
|
||||
struct regmap *regmap;
|
||||
int mclk;
|
||||
int requested_adc;
|
||||
int requested_dac;
|
||||
|
@ -532,7 +549,9 @@ static int tlv320aic23_suspend(struct snd_soc_codec *codec)
|
|||
|
||||
static int tlv320aic23_resume(struct snd_soc_codec *codec)
|
||||
{
|
||||
snd_soc_cache_sync(codec);
|
||||
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
|
||||
regcache_mark_dirty(aic23->regmap);
|
||||
regcache_sync(aic23->regmap);
|
||||
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
|
@ -540,10 +559,9 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec)
|
|||
|
||||
static int tlv320aic23_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -552,16 +570,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
|
|||
/* Reset codec */
|
||||
snd_soc_write(codec, TLV320AIC23_RESET, 0);
|
||||
|
||||
/* Write the register default value to cache for reserved registers,
|
||||
* so the write to the these registers are suppressed by the cache
|
||||
* restore code when it skips writes of default registers.
|
||||
*/
|
||||
snd_soc_cache_write(codec, 0x0A, 0);
|
||||
snd_soc_cache_write(codec, 0x0B, 0);
|
||||
snd_soc_cache_write(codec, 0x0C, 0);
|
||||
snd_soc_cache_write(codec, 0x0D, 0);
|
||||
snd_soc_cache_write(codec, 0x0E, 0);
|
||||
|
||||
/* power on device */
|
||||
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
|
@ -586,9 +594,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
|
|||
|
||||
snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1);
|
||||
|
||||
snd_soc_add_codec_controls(codec, tlv320aic23_snd_controls,
|
||||
ARRAY_SIZE(tlv320aic23_snd_controls));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -599,21 +604,19 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec)
|
|||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
|
||||
.reg_cache_size = ARRAY_SIZE(tlv320aic23_reg),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = tlv320aic23_reg,
|
||||
.probe = tlv320aic23_probe,
|
||||
.remove = tlv320aic23_remove,
|
||||
.suspend = tlv320aic23_suspend,
|
||||
.resume = tlv320aic23_resume,
|
||||
.set_bias_level = tlv320aic23_set_bias_level,
|
||||
.controls = tlv320aic23_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(tlv320aic23_snd_controls),
|
||||
.dapm_widgets = tlv320aic23_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
|
||||
.dapm_routes = tlv320aic23_intercon,
|
||||
.num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
/*
|
||||
* If the i2c layer weren't so broken, we could pass this kind of data
|
||||
* around
|
||||
|
@ -631,8 +634,11 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c,
|
|||
if (aic23 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap);
|
||||
if (IS_ERR(aic23->regmap))
|
||||
return PTR_ERR(aic23->regmap);
|
||||
|
||||
i2c_set_clientdata(i2c, aic23);
|
||||
aic23->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
|
||||
|
@ -660,29 +666,7 @@ static struct i2c_driver tlv320aic23_i2c_driver = {
|
|||
.id_table = tlv320aic23_id,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static int __init tlv320aic23_modinit(void)
|
||||
{
|
||||
int ret;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
ret = i2c_add_driver(&tlv320aic23_i2c_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
module_init(tlv320aic23_modinit);
|
||||
|
||||
static void __exit tlv320aic23_exit(void)
|
||||
{
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_del_driver(&tlv320aic23_i2c_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(tlv320aic23_exit);
|
||||
module_i2c_driver(tlv320aic23_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
|
||||
MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
|
||||
|
|
|
@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
|
|||
/* AIC26 driver private data */
|
||||
struct aic26 {
|
||||
struct spi_device *spi;
|
||||
struct regmap *regmap;
|
||||
struct snd_soc_codec *codec;
|
||||
int master;
|
||||
int datfm;
|
||||
|
@ -40,85 +41,6 @@ struct aic26 {
|
|||
int keyclick_len;
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Register access routines
|
||||
*/
|
||||
static unsigned int aic26_reg_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 *cache = codec->reg_cache;
|
||||
u16 cmd, value;
|
||||
u8 buffer[2];
|
||||
int rc;
|
||||
|
||||
if (reg >= AIC26_NUM_REGS) {
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do SPI transfer; first 16bits are command; remaining is
|
||||
* register contents */
|
||||
cmd = AIC26_READ_COMMAND_WORD(reg);
|
||||
buffer[0] = (cmd >> 8) & 0xff;
|
||||
buffer[1] = cmd & 0xff;
|
||||
rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2);
|
||||
if (rc) {
|
||||
dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
|
||||
return -EIO;
|
||||
}
|
||||
value = (buffer[0] << 8) | buffer[1];
|
||||
|
||||
/* Update the cache before returning with the value */
|
||||
cache[reg] = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
if (reg >= AIC26_NUM_REGS) {
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cache[reg];
|
||||
}
|
||||
|
||||
static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 *cache = codec->reg_cache;
|
||||
u16 cmd;
|
||||
u8 buffer[4];
|
||||
int rc;
|
||||
|
||||
if (reg >= AIC26_NUM_REGS) {
|
||||
WARN_ON_ONCE(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Do SPI transfer; first 16bits are command; remaining is data
|
||||
* to write into register */
|
||||
cmd = AIC26_WRITE_COMMAND_WORD(reg);
|
||||
buffer[0] = (cmd >> 8) & 0xff;
|
||||
buffer[1] = cmd & 0xff;
|
||||
buffer[2] = value >> 8;
|
||||
buffer[3] = value;
|
||||
rc = spi_write(aic26->spi, buffer, 4);
|
||||
if (rc) {
|
||||
dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* update cache before returning */
|
||||
cache[reg] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget tlv320aic26_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("MICIN"),
|
||||
SND_SOC_DAPM_INPUT("AUX"),
|
||||
|
@ -195,19 +117,15 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
|
|||
snd_soc_write(codec, AIC26_REG_PLL_PROG2, reg);
|
||||
|
||||
/* Audio Control 3 (master mode, fsref rate) */
|
||||
reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3);
|
||||
reg &= ~0xf800;
|
||||
if (aic26->master)
|
||||
reg |= 0x0800;
|
||||
reg = 0x0800;
|
||||
if (fsref == 48000)
|
||||
reg |= 0x2000;
|
||||
snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
|
||||
reg = 0x2000;
|
||||
snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL3, 0xf800, reg);
|
||||
|
||||
/* Audio Control 1 (FSref divisor) */
|
||||
reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1);
|
||||
reg &= ~0x0fff;
|
||||
reg |= wlen | aic26->datfm | (divisor << 3) | divisor;
|
||||
snd_soc_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
|
||||
reg = wlen | aic26->datfm | (divisor << 3) | divisor;
|
||||
snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL1, 0xfff, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -219,16 +137,16 @@ static int aic26_mute(struct snd_soc_dai *dai, int mute)
|
|||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN);
|
||||
u16 reg;
|
||||
|
||||
dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",
|
||||
dai, mute);
|
||||
|
||||
if (mute)
|
||||
reg |= 0x8080;
|
||||
reg = 0x8080;
|
||||
else
|
||||
reg &= ~0x8080;
|
||||
snd_soc_write(codec, AIC26_REG_DAC_GAIN, reg);
|
||||
reg = 0;
|
||||
snd_soc_update_bits(codec, AIC26_REG_DAC_GAIN, 0x8000, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -346,7 +264,7 @@ static ssize_t aic26_keyclick_show(struct device *dev,
|
|||
struct aic26 *aic26 = dev_get_drvdata(dev);
|
||||
int val, amp, freq, len;
|
||||
|
||||
val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2);
|
||||
val = snd_soc_read(aic26->codec, AIC26_REG_AUDIO_CTRL2);
|
||||
amp = (val >> 12) & 0x7;
|
||||
freq = (125 << ((val >> 8) & 0x7)) >> 1;
|
||||
len = 2 * (1 + ((val >> 4) & 0xf));
|
||||
|
@ -360,11 +278,9 @@ static ssize_t aic26_keyclick_set(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct aic26 *aic26 = dev_get_drvdata(dev);
|
||||
int val;
|
||||
|
||||
val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2);
|
||||
val |= 0x8000;
|
||||
snd_soc_write(aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
|
||||
snd_soc_update_bits(aic26->codec, AIC26_REG_AUDIO_CTRL2,
|
||||
0x8000, 0x800);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -377,7 +293,9 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
|
|||
static int aic26_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct aic26 *aic26 = dev_get_drvdata(codec->dev);
|
||||
int ret, err, i, reg;
|
||||
int ret, reg;
|
||||
|
||||
snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
|
||||
|
||||
aic26->codec = codec;
|
||||
|
||||
|
@ -393,37 +311,30 @@ static int aic26_probe(struct snd_soc_codec *codec)
|
|||
reg |= 0x0800; /* set master mode */
|
||||
snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
|
||||
|
||||
/* Fill register cache */
|
||||
for (i = 0; i < codec->driver->reg_cache_size; i++)
|
||||
snd_soc_read(codec, i);
|
||||
|
||||
/* Register the sysfs files for debugging */
|
||||
/* Create SysFS files */
|
||||
ret = device_create_file(codec->dev, &dev_attr_keyclick);
|
||||
if (ret)
|
||||
dev_info(codec->dev, "error creating sysfs files\n");
|
||||
|
||||
/* register controls */
|
||||
dev_dbg(codec->dev, "Registering controls\n");
|
||||
err = snd_soc_add_codec_controls(codec, aic26_snd_controls,
|
||||
ARRAY_SIZE(aic26_snd_controls));
|
||||
WARN_ON(err < 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver aic26_soc_codec_dev = {
|
||||
.probe = aic26_probe,
|
||||
.read = aic26_reg_read,
|
||||
.write = aic26_reg_write,
|
||||
.reg_cache_size = AIC26_NUM_REGS,
|
||||
.reg_word_size = sizeof(u16),
|
||||
.controls = aic26_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(aic26_snd_controls),
|
||||
.dapm_widgets = tlv320aic26_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets),
|
||||
.dapm_routes = tlv320aic26_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes),
|
||||
};
|
||||
|
||||
static const struct regmap_config aic26_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 16,
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* SPI device portion of driver: probe and release routines and SPI
|
||||
* driver registration.
|
||||
|
@ -440,6 +351,10 @@ static int aic26_spi_probe(struct spi_device *spi)
|
|||
if (!aic26)
|
||||
return -ENOMEM;
|
||||
|
||||
aic26->regmap = devm_regmap_init_spi(spi, &aic26_regmap);
|
||||
if (IS_ERR(aic26->regmap))
|
||||
return PTR_ERR(aic26->regmap);
|
||||
|
||||
/* Initialize the driver data */
|
||||
aic26->spi = spi;
|
||||
dev_set_drvdata(&spi->dev, aic26);
|
||||
|
|
|
@ -9,10 +9,7 @@
|
|||
#define _TLV320AIC16_H_
|
||||
|
||||
/* AIC26 Registers */
|
||||
#define AIC26_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5))
|
||||
#define AIC26_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5))
|
||||
#define AIC26_PAGE_ADDR(page, offset) ((page << 6) | offset)
|
||||
#define AIC26_NUM_REGS AIC26_PAGE_ADDR(3, 0)
|
||||
#define AIC26_PAGE_ADDR(page, offset) ((page << 11) | offset << 5)
|
||||
|
||||
/* Page 0: Auxiliary data registers */
|
||||
#define AIC26_REG_BAT1 AIC26_PAGE_ADDR(0, 0x05)
|
||||
|
|
|
@ -60,9 +60,8 @@ struct aic32x4_rate_divs {
|
|||
};
|
||||
|
||||
struct aic32x4_priv {
|
||||
struct regmap *regmap;
|
||||
u32 sysclk;
|
||||
u8 page_no;
|
||||
void *control_data;
|
||||
u32 power_cfg;
|
||||
u32 micpga_routing;
|
||||
bool swapdacs;
|
||||
|
@ -262,67 +261,25 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
|
|||
{"Right ADC", NULL, "Right Input Mixer"},
|
||||
};
|
||||
|
||||
static inline int aic32x4_change_page(struct snd_soc_codec *codec,
|
||||
unsigned int new_page)
|
||||
{
|
||||
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 data[2];
|
||||
int ret;
|
||||
static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
|
||||
{
|
||||
.selector_reg = 0,
|
||||
.selector_mask = 0xff,
|
||||
.window_start = 0,
|
||||
.window_len = 128,
|
||||
.range_min = AIC32X4_PAGE1,
|
||||
.range_max = AIC32X4_PAGE1 + 127,
|
||||
},
|
||||
};
|
||||
|
||||
data[0] = 0x00;
|
||||
data[1] = new_page & 0xff;
|
||||
static const struct regmap_config aic32x4_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
ret = codec->hw_write(codec->control_data, data, 2);
|
||||
if (ret == 2) {
|
||||
aic32x4->page_no = new_page;
|
||||
return 0;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static int aic32x4_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int page = reg / 128;
|
||||
unsigned int fixed_reg = reg % 128;
|
||||
u8 data[2];
|
||||
int ret;
|
||||
|
||||
/* A write to AIC32X4_PSEL is really a non-explicit page change */
|
||||
if (reg == AIC32X4_PSEL)
|
||||
return aic32x4_change_page(codec, val);
|
||||
|
||||
if (aic32x4->page_no != page) {
|
||||
ret = aic32x4_change_page(codec, page);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
data[0] = fixed_reg & 0xff;
|
||||
data[1] = val & 0xff;
|
||||
|
||||
if (codec->hw_write(codec->control_data, data, 2) == 2)
|
||||
return 0;
|
||||
else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static unsigned int aic32x4_read(struct snd_soc_codec *codec, unsigned int reg)
|
||||
{
|
||||
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int page = reg / 128;
|
||||
unsigned int fixed_reg = reg % 128;
|
||||
int ret;
|
||||
|
||||
if (aic32x4->page_no != page) {
|
||||
ret = aic32x4_change_page(codec, page);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
return i2c_smbus_read_byte_data(codec->control_data, fixed_reg & 0xff);
|
||||
}
|
||||
.max_register = AIC32X4_RMICPGAVOL,
|
||||
.ranges = aic32x4_regmap_pages,
|
||||
.num_ranges = ARRAY_SIZE(aic32x4_regmap_pages),
|
||||
};
|
||||
|
||||
static inline int aic32x4_get_divs(int mclk, int rate)
|
||||
{
|
||||
|
@ -617,16 +574,10 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
|
|||
{
|
||||
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
|
||||
u32 tmp_reg;
|
||||
int ret;
|
||||
|
||||
codec->hw_write = (hw_write_t) i2c_master_send;
|
||||
codec->control_data = aic32x4->control_data;
|
||||
snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
|
||||
|
||||
if (aic32x4->rstn_gpio >= 0) {
|
||||
ret = devm_gpio_request_one(codec->dev, aic32x4->rstn_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ndelay(10);
|
||||
gpio_set_value(aic32x4->rstn_gpio, 1);
|
||||
}
|
||||
|
@ -692,8 +643,6 @@ static int aic32x4_remove(struct snd_soc_codec *codec)
|
|||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
|
||||
.read = aic32x4_read,
|
||||
.write = aic32x4_write,
|
||||
.probe = aic32x4_probe,
|
||||
.remove = aic32x4_remove,
|
||||
.suspend = aic32x4_suspend,
|
||||
|
@ -720,7 +669,10 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
|
|||
if (aic32x4 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
aic32x4->control_data = i2c;
|
||||
aic32x4->regmap = devm_regmap_init_i2c(i2c, &aic32x4_regmap);
|
||||
if (IS_ERR(aic32x4->regmap))
|
||||
return PTR_ERR(aic32x4->regmap);
|
||||
|
||||
i2c_set_clientdata(i2c, aic32x4);
|
||||
|
||||
if (pdata) {
|
||||
|
@ -735,6 +687,13 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
|
|||
aic32x4->rstn_gpio = -1;
|
||||
}
|
||||
|
||||
if (aic32x4->rstn_gpio >= 0) {
|
||||
ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_aic32x4, &aic32x4_dai, 1);
|
||||
return ret;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
|
@ -72,9 +73,9 @@ struct aic3x_disable_nb {
|
|||
/* codec private data */
|
||||
struct aic3x_priv {
|
||||
struct snd_soc_codec *codec;
|
||||
struct regmap *regmap;
|
||||
struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
|
||||
struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
|
||||
enum snd_soc_control_type control_type;
|
||||
struct aic3x_setup_data *setup;
|
||||
unsigned int sysclk;
|
||||
struct list_head list;
|
||||
|
@ -90,41 +91,45 @@ struct aic3x_priv {
|
|||
enum aic3x_micbias_voltage micbias_vg;
|
||||
};
|
||||
|
||||
/*
|
||||
* AIC3X register cache
|
||||
* We can't read the AIC3X register space when we are
|
||||
* using 2 wire for device control, so we cache them instead.
|
||||
* There is no point in caching the reset register
|
||||
*/
|
||||
static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
|
||||
0x00, 0x00, 0x00, 0x10, /* 0 */
|
||||
0x04, 0x00, 0x00, 0x00, /* 4 */
|
||||
0x00, 0x00, 0x00, 0x01, /* 8 */
|
||||
0x00, 0x00, 0x00, 0x80, /* 12 */
|
||||
0x80, 0xff, 0xff, 0x78, /* 16 */
|
||||
0x78, 0x78, 0x78, 0x78, /* 20 */
|
||||
0x78, 0x00, 0x00, 0xfe, /* 24 */
|
||||
0x00, 0x00, 0xfe, 0x00, /* 28 */
|
||||
0x18, 0x18, 0x00, 0x00, /* 32 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 36 */
|
||||
0x00, 0x00, 0x00, 0x80, /* 40 */
|
||||
0x80, 0x00, 0x00, 0x00, /* 44 */
|
||||
0x00, 0x00, 0x00, 0x04, /* 48 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 52 */
|
||||
0x00, 0x00, 0x04, 0x00, /* 56 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 60 */
|
||||
0x00, 0x04, 0x00, 0x00, /* 64 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 68 */
|
||||
0x04, 0x00, 0x00, 0x00, /* 72 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 76 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 80 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 84 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 88 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 92 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 96 */
|
||||
0x00, 0x00, 0x02, 0x00, /* 100 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 104 */
|
||||
0x00, 0x00, /* 108 */
|
||||
static const struct reg_default aic3x_reg[] = {
|
||||
{ 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, { 3, 0x10 },
|
||||
{ 4, 0x04 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
|
||||
{ 8, 0x00 }, { 9, 0x00 }, { 10, 0x00 }, { 11, 0x01 },
|
||||
{ 12, 0x00 }, { 13, 0x00 }, { 14, 0x00 }, { 15, 0x80 },
|
||||
{ 16, 0x80 }, { 17, 0xff }, { 18, 0xff }, { 19, 0x78 },
|
||||
{ 20, 0x78 }, { 21, 0x78 }, { 22, 0x78 }, { 23, 0x78 },
|
||||
{ 24, 0x78 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0xfe },
|
||||
{ 28, 0x00 }, { 29, 0x00 }, { 30, 0xfe }, { 31, 0x00 },
|
||||
{ 32, 0x18 }, { 33, 0x18 }, { 34, 0x00 }, { 35, 0x00 },
|
||||
{ 36, 0x00 }, { 37, 0x00 }, { 38, 0x00 }, { 39, 0x00 },
|
||||
{ 40, 0x00 }, { 41, 0x00 }, { 42, 0x00 }, { 43, 0x80 },
|
||||
{ 44, 0x80 }, { 45, 0x00 }, { 46, 0x00 }, { 47, 0x00 },
|
||||
{ 48, 0x00 }, { 49, 0x00 }, { 50, 0x00 }, { 51, 0x04 },
|
||||
{ 52, 0x00 }, { 53, 0x00 }, { 54, 0x00 }, { 55, 0x00 },
|
||||
{ 56, 0x00 }, { 57, 0x00 }, { 58, 0x04 }, { 59, 0x00 },
|
||||
{ 60, 0x00 }, { 61, 0x00 }, { 62, 0x00 }, { 63, 0x00 },
|
||||
{ 64, 0x00 }, { 65, 0x04 }, { 66, 0x00 }, { 67, 0x00 },
|
||||
{ 68, 0x00 }, { 69, 0x00 }, { 70, 0x00 }, { 71, 0x00 },
|
||||
{ 72, 0x04 }, { 73, 0x00 }, { 74, 0x00 }, { 75, 0x00 },
|
||||
{ 76, 0x00 }, { 77, 0x00 }, { 78, 0x00 }, { 79, 0x00 },
|
||||
{ 80, 0x00 }, { 81, 0x00 }, { 82, 0x00 }, { 83, 0x00 },
|
||||
{ 84, 0x00 }, { 85, 0x00 }, { 86, 0x00 }, { 87, 0x00 },
|
||||
{ 88, 0x00 }, { 89, 0x00 }, { 90, 0x00 }, { 91, 0x00 },
|
||||
{ 92, 0x00 }, { 93, 0x00 }, { 94, 0x00 }, { 95, 0x00 },
|
||||
{ 96, 0x00 }, { 97, 0x00 }, { 98, 0x00 }, { 99, 0x00 },
|
||||
{ 100, 0x00 }, { 101, 0x00 }, { 102, 0x02 }, { 103, 0x00 },
|
||||
{ 104, 0x00 }, { 105, 0x00 }, { 106, 0x00 }, { 107, 0x00 },
|
||||
{ 108, 0x00 }, { 109, 0x00 },
|
||||
};
|
||||
|
||||
static const struct regmap_config aic3x_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = DAC_ICC_ADJ,
|
||||
.reg_defaults = aic3x_reg,
|
||||
.num_reg_defaults = ARRAY_SIZE(aic3x_reg),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
|
||||
|
@ -828,12 +833,6 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)
|
|||
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
|
||||
snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
|
||||
ARRAY_SIZE(aic3x_dapm_widgets));
|
||||
|
||||
/* set up audio path interconnects */
|
||||
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
|
||||
|
||||
if (aic3x->model == AIC3X_MODEL_3007) {
|
||||
snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
|
||||
ARRAY_SIZE(aic3007_dapm_widgets));
|
||||
|
@ -1082,29 +1081,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int aic3x_init_3007(struct snd_soc_codec *codec)
|
||||
{
|
||||
u8 tmp1, tmp2, *cache = codec->reg_cache;
|
||||
|
||||
/*
|
||||
* There is no need to cache writes to undocumented page 0xD but
|
||||
* respective page 0 register cache entries must be preserved
|
||||
*/
|
||||
tmp1 = cache[0xD];
|
||||
tmp2 = cache[0x8];
|
||||
/* Class-D speaker driver init; datasheet p. 46 */
|
||||
snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D);
|
||||
snd_soc_write(codec, 0xD, 0x0D);
|
||||
snd_soc_write(codec, 0x8, 0x5C);
|
||||
snd_soc_write(codec, 0x8, 0x5D);
|
||||
snd_soc_write(codec, 0x8, 0x5C);
|
||||
snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00);
|
||||
cache[0xD] = tmp1;
|
||||
cache[0x8] = tmp2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aic3x_regulator_event(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
|
@ -1119,7 +1095,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,
|
|||
*/
|
||||
if (gpio_is_valid(aic3x->gpio_reset))
|
||||
gpio_set_value(aic3x->gpio_reset, 0);
|
||||
aic3x->codec->cache_sync = 1;
|
||||
regcache_mark_dirty(aic3x->regmap);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1128,8 +1104,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,
|
|||
static int aic3x_set_power(struct snd_soc_codec *codec, int power)
|
||||
{
|
||||
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
|
||||
int i, ret;
|
||||
u8 *cache = codec->reg_cache;
|
||||
int ret;
|
||||
|
||||
if (power) {
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
|
||||
|
@ -1137,12 +1112,6 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
|
|||
if (ret)
|
||||
goto out;
|
||||
aic3x->power = 1;
|
||||
/*
|
||||
* Reset release and cache sync is necessary only if some
|
||||
* supply was off or if there were cached writes
|
||||
*/
|
||||
if (!codec->cache_sync)
|
||||
goto out;
|
||||
|
||||
if (gpio_is_valid(aic3x->gpio_reset)) {
|
||||
udelay(1);
|
||||
|
@ -1150,12 +1119,8 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
|
|||
}
|
||||
|
||||
/* Sync reg_cache with the hardware */
|
||||
codec->cache_only = 0;
|
||||
for (i = AIC3X_SAMPLE_RATE_SEL_REG; i < ARRAY_SIZE(aic3x_reg); i++)
|
||||
snd_soc_write(codec, i, cache[i]);
|
||||
if (aic3x->model == AIC3X_MODEL_3007)
|
||||
aic3x_init_3007(codec);
|
||||
codec->cache_sync = 0;
|
||||
regcache_cache_only(aic3x->regmap, false);
|
||||
regcache_sync(aic3x->regmap);
|
||||
} else {
|
||||
/*
|
||||
* Do soft reset to this codec instance in order to clear
|
||||
|
@ -1163,10 +1128,10 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
|
|||
* remain on
|
||||
*/
|
||||
snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
|
||||
codec->cache_sync = 1;
|
||||
regcache_mark_dirty(aic3x->regmap);
|
||||
aic3x->power = 0;
|
||||
/* HW writes are needless when bias is off */
|
||||
codec->cache_only = 1;
|
||||
regcache_cache_only(aic3x->regmap, true);
|
||||
ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
|
||||
aic3x->supplies);
|
||||
}
|
||||
|
@ -1321,7 +1286,6 @@ static int aic3x_init(struct snd_soc_codec *codec)
|
|||
snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
|
||||
|
||||
if (aic3x->model == AIC3X_MODEL_3007) {
|
||||
aic3x_init_3007(codec);
|
||||
snd_soc_write(codec, CLASSD_CTRL, 0);
|
||||
}
|
||||
|
||||
|
@ -1349,29 +1313,12 @@ static int aic3x_probe(struct snd_soc_codec *codec)
|
|||
INIT_LIST_HEAD(&aic3x->list);
|
||||
aic3x->codec = codec;
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(aic3x->gpio_reset) &&
|
||||
!aic3x_is_shared_reset(aic3x)) {
|
||||
ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
|
||||
if (ret != 0)
|
||||
goto err_gpio;
|
||||
gpio_direction_output(aic3x->gpio_reset, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
|
||||
aic3x->supplies[i].supply = aic3x_supply_names[i];
|
||||
|
||||
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
|
||||
aic3x->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
|
||||
goto err_get;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
|
||||
aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
|
||||
aic3x->disable_nb[i].aic3x = aic3x;
|
||||
|
@ -1385,7 +1332,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
|
|||
}
|
||||
}
|
||||
|
||||
codec->cache_only = 1;
|
||||
regcache_mark_dirty(aic3x->regmap);
|
||||
aic3x_init(codec);
|
||||
|
||||
if (aic3x->setup) {
|
||||
|
@ -1396,8 +1343,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)
|
|||
(aic3x->setup->gpio_func[1] & 0xf) << 4);
|
||||
}
|
||||
|
||||
snd_soc_add_codec_controls(codec, aic3x_snd_controls,
|
||||
ARRAY_SIZE(aic3x_snd_controls));
|
||||
if (aic3x->model == AIC3X_MODEL_3007)
|
||||
snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
|
||||
|
||||
|
@ -1428,12 +1373,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)
|
|||
while (i--)
|
||||
regulator_unregister_notifier(aic3x->supplies[i].consumer,
|
||||
&aic3x->disable_nb[i].nb);
|
||||
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
|
||||
err_get:
|
||||
if (gpio_is_valid(aic3x->gpio_reset) &&
|
||||
!aic3x_is_shared_reset(aic3x))
|
||||
gpio_free(aic3x->gpio_reset);
|
||||
err_gpio:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1444,15 +1383,9 @@ static int aic3x_remove(struct snd_soc_codec *codec)
|
|||
|
||||
aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
list_del(&aic3x->list);
|
||||
if (gpio_is_valid(aic3x->gpio_reset) &&
|
||||
!aic3x_is_shared_reset(aic3x)) {
|
||||
gpio_set_value(aic3x->gpio_reset, 0);
|
||||
gpio_free(aic3x->gpio_reset);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
|
||||
regulator_unregister_notifier(aic3x->supplies[i].consumer,
|
||||
&aic3x->disable_nb[i].nb);
|
||||
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1460,13 +1393,16 @@ static int aic3x_remove(struct snd_soc_codec *codec)
|
|||
static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
|
||||
.set_bias_level = aic3x_set_bias_level,
|
||||
.idle_bias_off = true,
|
||||
.reg_cache_size = ARRAY_SIZE(aic3x_reg),
|
||||
.reg_word_size = sizeof(u8),
|
||||
.reg_cache_default = aic3x_reg,
|
||||
.probe = aic3x_probe,
|
||||
.remove = aic3x_remove,
|
||||
.suspend = aic3x_suspend,
|
||||
.resume = aic3x_resume,
|
||||
.controls = aic3x_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(aic3x_snd_controls),
|
||||
.dapm_widgets = aic3x_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets),
|
||||
.dapm_routes = intercon,
|
||||
.num_dapm_routes = ARRAY_SIZE(intercon),
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1483,6 +1419,16 @@ static const struct i2c_device_id aic3x_i2c_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
|
||||
|
||||
static const struct reg_default aic3007_class_d[] = {
|
||||
/* Class-D speaker driver init; datasheet p. 46 */
|
||||
{ AIC3X_PAGE_SELECT, 0x0D },
|
||||
{ 0xD, 0x0D },
|
||||
{ 0x8, 0x5C },
|
||||
{ 0x8, 0x5D },
|
||||
{ 0x8, 0x5C },
|
||||
{ AIC3X_PAGE_SELECT, 0x00 },
|
||||
};
|
||||
|
||||
/*
|
||||
* If the i2c layer weren't so broken, we could pass this kind of data
|
||||
* around
|
||||
|
@ -1494,7 +1440,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
|
|||
struct aic3x_priv *aic3x;
|
||||
struct aic3x_setup_data *ai3x_setup;
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
int ret;
|
||||
int ret, i;
|
||||
u32 value;
|
||||
|
||||
aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
|
||||
|
@ -1503,7 +1449,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
aic3x->control_type = SND_SOC_I2C;
|
||||
aic3x->regmap = devm_regmap_init_i2c(i2c, &aic3x_regmap);
|
||||
if (IS_ERR(aic3x->regmap)) {
|
||||
ret = PTR_ERR(aic3x->regmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(aic3x->regmap, true);
|
||||
|
||||
i2c_set_clientdata(i2c, aic3x);
|
||||
if (pdata) {
|
||||
|
@ -1555,14 +1507,54 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
|
|||
|
||||
aic3x->model = id->driver_data;
|
||||
|
||||
if (gpio_is_valid(aic3x->gpio_reset) &&
|
||||
!aic3x_is_shared_reset(aic3x)) {
|
||||
ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
gpio_direction_output(aic3x->gpio_reset, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
|
||||
aic3x->supplies[i].supply = aic3x_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies),
|
||||
aic3x->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
if (aic3x->model == AIC3X_MODEL_3007) {
|
||||
ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
|
||||
ARRAY_SIZE(aic3007_class_d));
|
||||
if (ret != 0)
|
||||
dev_err(&i2c->dev, "Failed to init class D: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_aic3x, &aic3x_dai, 1);
|
||||
return ret;
|
||||
|
||||
err_gpio:
|
||||
if (gpio_is_valid(aic3x->gpio_reset) &&
|
||||
!aic3x_is_shared_reset(aic3x))
|
||||
gpio_free(aic3x->gpio_reset);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aic3x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct aic3x_priv *aic3x = i2c_get_clientdata(client);
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
if (gpio_is_valid(aic3x->gpio_reset) &&
|
||||
!aic3x_is_shared_reset(aic3x)) {
|
||||
gpio_set_value(aic3x->gpio_reset, 0);
|
||||
gpio_free(aic3x->gpio_reset);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <sound/tpa6130a2-plat.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include "tpa6130a2.h"
|
||||
|
||||
|
@ -364,30 +365,33 @@ static int tpa6130a2_probe(struct i2c_client *client,
|
|||
{
|
||||
struct device *dev;
|
||||
struct tpa6130a2_data *data;
|
||||
struct tpa6130a2_platform_data *pdata;
|
||||
struct tpa6130a2_platform_data *pdata = client->dev.platform_data;
|
||||
struct device_node *np = client->dev.of_node;
|
||||
const char *regulator;
|
||||
int ret;
|
||||
|
||||
dev = &client->dev;
|
||||
|
||||
if (client->dev.platform_data == NULL) {
|
||||
dev_err(dev, "Platform data not set\n");
|
||||
dump_stack();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (data == NULL) {
|
||||
dev_err(dev, "Can not allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
data->power_gpio = pdata->power_gpio;
|
||||
} else if (np) {
|
||||
data->power_gpio = of_get_named_gpio(np, "power-gpio", 0);
|
||||
} else {
|
||||
dev_err(dev, "Platform data not set\n");
|
||||
dump_stack();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
tpa6130a2_client = client;
|
||||
|
||||
i2c_set_clientdata(tpa6130a2_client, data);
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
data->power_gpio = pdata->power_gpio;
|
||||
data->id = id->driver_data;
|
||||
|
||||
mutex_init(&data->mutex);
|
||||
|
@ -466,10 +470,20 @@ static const struct i2c_device_id tpa6130a2_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tpa6130a2_id);
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id tpa6130a2_of_match[] = {
|
||||
{ .compatible = "ti,tpa6130a2", },
|
||||
{ .compatible = "ti,tpa6140a2" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tpa6130a2_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver tpa6130a2_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tpa6130a2",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(tpa6130a2_of_match),
|
||||
},
|
||||
.probe = tpa6130a2_probe,
|
||||
.remove = tpa6130a2_remove,
|
||||
|
|
|
@ -46,13 +46,7 @@
|
|||
/* TWL4030 PMBR1 Register GPIO6 mux bits */
|
||||
#define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2)
|
||||
|
||||
/* Shadow register used by the audio driver */
|
||||
#define TWL4030_REG_SW_SHADOW 0x4A
|
||||
#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
|
||||
|
||||
/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
|
||||
#define TWL4030_HFL_EN 0x01
|
||||
#define TWL4030_HFR_EN 0x02
|
||||
#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1)
|
||||
|
||||
/*
|
||||
* twl4030 register cache & default register settings
|
||||
|
@ -132,7 +126,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
|
|||
0x00, /* REG_VIBRA_PWM_SET (0x47) */
|
||||
0x00, /* REG_ANAMIC_GAIN (0x48) */
|
||||
0x00, /* REG_MISC_SET_2 (0x49) */
|
||||
0x00, /* REG_SW_SHADOW (0x4A) - Shadow, non HW register */
|
||||
};
|
||||
|
||||
/* codec private data */
|
||||
|
@ -198,42 +191,41 @@ static int twl4030_write(struct snd_soc_codec *codec,
|
|||
int write_to_reg = 0;
|
||||
|
||||
twl4030_write_reg_cache(codec, reg, value);
|
||||
if (likely(reg < TWL4030_REG_SW_SHADOW)) {
|
||||
/* Decide if the given register can be written */
|
||||
switch (reg) {
|
||||
case TWL4030_REG_EAR_CTL:
|
||||
if (twl4030->earpiece_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PREDL_CTL:
|
||||
if (twl4030->predrivel_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PREDR_CTL:
|
||||
if (twl4030->predriver_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PRECKL_CTL:
|
||||
if (twl4030->carkitl_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PRECKR_CTL:
|
||||
if (twl4030->carkitr_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_HS_GAIN_SET:
|
||||
if (twl4030->hsl_enabled || twl4030->hsr_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
default:
|
||||
/* All other register can be written */
|
||||
/* Decide if the given register can be written */
|
||||
switch (reg) {
|
||||
case TWL4030_REG_EAR_CTL:
|
||||
if (twl4030->earpiece_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
}
|
||||
if (write_to_reg)
|
||||
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
|
||||
value, reg);
|
||||
break;
|
||||
case TWL4030_REG_PREDL_CTL:
|
||||
if (twl4030->predrivel_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PREDR_CTL:
|
||||
if (twl4030->predriver_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PRECKL_CTL:
|
||||
if (twl4030->carkitl_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PRECKR_CTL:
|
||||
if (twl4030->carkitr_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_HS_GAIN_SET:
|
||||
if (twl4030->hsl_enabled || twl4030->hsr_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
default:
|
||||
/* All other register can be written */
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
}
|
||||
if (write_to_reg)
|
||||
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
|
||||
value, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -532,7 +524,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
|
|||
|
||||
/* Handsfree Left virtual mute */
|
||||
static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
|
||||
SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0);
|
||||
SOC_DAPM_SINGLE_VIRT("Switch", 1);
|
||||
|
||||
/* Handsfree Right */
|
||||
static const char *twl4030_handsfreer_texts[] =
|
||||
|
@ -548,7 +540,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
|
|||
|
||||
/* Handsfree Right virtual mute */
|
||||
static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
|
||||
SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0);
|
||||
SOC_DAPM_SINGLE_VIRT("Switch", 1);
|
||||
|
||||
/* Vibra */
|
||||
/* Vibra audio path selection */
|
||||
|
|
|
@ -54,12 +54,7 @@ enum twl6040_dai_id {
|
|||
#define TWL6040_OUTHF_0dB 0x03
|
||||
#define TWL6040_OUTHF_M52dB 0x1D
|
||||
|
||||
/* Shadow register used by the driver */
|
||||
#define TWL6040_REG_SW_SHADOW 0x2F
|
||||
#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1)
|
||||
|
||||
/* TWL6040_REG_SW_SHADOW (0x2F) fields */
|
||||
#define TWL6040_EAR_PATH_ENABLE 0x01
|
||||
#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
|
||||
|
||||
struct twl6040_jack_data {
|
||||
struct snd_soc_jack *jack;
|
||||
|
@ -135,8 +130,6 @@ static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = {
|
|||
0x00, /* REG_HFOTRIM 0x2C */
|
||||
0x09, /* REG_ACCCTL 0x2D */
|
||||
0x00, /* REG_STATUS 0x2E (ro) */
|
||||
|
||||
0x00, /* REG_SW_SHADOW 0x2F - Shadow, non HW register */
|
||||
};
|
||||
|
||||
/* List of registers to be restored after power up */
|
||||
|
@ -220,12 +213,8 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
|
|||
if (reg >= TWL6040_CACHEREGNUM)
|
||||
return -EIO;
|
||||
|
||||
if (likely(reg < TWL6040_REG_SW_SHADOW)) {
|
||||
value = twl6040_reg_read(twl6040, reg);
|
||||
twl6040_write_reg_cache(codec, reg, value);
|
||||
} else {
|
||||
value = twl6040_read_reg_cache(codec, reg);
|
||||
}
|
||||
value = twl6040_reg_read(twl6040, reg);
|
||||
twl6040_write_reg_cache(codec, reg, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -246,7 +235,7 @@ static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,
|
|||
return priv->dl2_unmuted;
|
||||
default:
|
||||
return 1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -261,8 +250,7 @@ static int twl6040_write(struct snd_soc_codec *codec,
|
|||
return -EIO;
|
||||
|
||||
twl6040_write_reg_cache(codec, reg, value);
|
||||
if (likely(reg < TWL6040_REG_SW_SHADOW) &&
|
||||
twl6040_is_path_unmuted(codec, reg))
|
||||
if (twl6040_is_path_unmuted(codec, reg))
|
||||
return twl6040_reg_write(twl6040, reg, value);
|
||||
else
|
||||
return 0;
|
||||
|
@ -555,7 +543,7 @@ static const struct snd_kcontrol_new hfr_mux_controls =
|
|||
SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
|
||||
|
||||
static const struct snd_kcontrol_new ep_path_enable_control =
|
||||
SOC_DAPM_SINGLE("Switch", TWL6040_REG_SW_SHADOW, 0, 1, 0);
|
||||
SOC_DAPM_SINGLE_VIRT("Switch", 1);
|
||||
|
||||
static const struct snd_kcontrol_new auxl_switch_control =
|
||||
SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0);
|
||||
|
@ -1100,7 +1088,7 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
|
|||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
|
|
|
@ -32,13 +32,6 @@
|
|||
|
||||
#include "wm8400.h"
|
||||
|
||||
/* Fake register for internal state */
|
||||
#define WM8400_INTDRIVBITS (WM8400_REGISTER_COUNT + 1)
|
||||
#define WM8400_INMIXL_PWR 0
|
||||
#define WM8400_AINLMUX_PWR 1
|
||||
#define WM8400_INMIXR_PWR 2
|
||||
#define WM8400_AINRMUX_PWR 3
|
||||
|
||||
static struct regulator_bulk_data power[] = {
|
||||
{
|
||||
.supply = "I2S1VDD",
|
||||
|
@ -74,32 +67,6 @@ struct wm8400_priv {
|
|||
int fll_in, fll_out;
|
||||
};
|
||||
|
||||
static inline unsigned int wm8400_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (reg == WM8400_INTDRIVBITS)
|
||||
return wm8400->fake_register;
|
||||
else
|
||||
return wm8400_reg_read(wm8400->wm8400, reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* write to the wm8400 register space
|
||||
*/
|
||||
static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (reg == WM8400_INTDRIVBITS) {
|
||||
wm8400->fake_register = value;
|
||||
return 0;
|
||||
} else
|
||||
return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value);
|
||||
}
|
||||
|
||||
static void wm8400_codec_reset(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
|
||||
|
@ -352,32 +319,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
|
|||
* _DAPM_ Controls
|
||||
*/
|
||||
|
||||
static int inmixer_event (struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
u16 reg, fakepower;
|
||||
|
||||
reg = snd_soc_read(w->codec, WM8400_POWER_MANAGEMENT_2);
|
||||
fakepower = snd_soc_read(w->codec, WM8400_INTDRIVBITS);
|
||||
|
||||
if (fakepower & ((1 << WM8400_INMIXL_PWR) |
|
||||
(1 << WM8400_AINLMUX_PWR))) {
|
||||
reg |= WM8400_AINL_ENA;
|
||||
} else {
|
||||
reg &= ~WM8400_AINL_ENA;
|
||||
}
|
||||
|
||||
if (fakepower & ((1 << WM8400_INMIXR_PWR) |
|
||||
(1 << WM8400_AINRMUX_PWR))) {
|
||||
reg |= WM8400_AINR_ENA;
|
||||
} else {
|
||||
reg &= ~WM8400_AINR_ENA;
|
||||
}
|
||||
snd_soc_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outmixer_event (struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol * kcontrol, int event)
|
||||
{
|
||||
|
@ -658,27 +599,26 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2,
|
|||
0, &wm8400_dapm_rin34_pga_controls[0],
|
||||
ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("INL", WM8400_POWER_MANAGEMENT_2, WM8400_AINL_ENA_SHIFT,
|
||||
0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("INR", WM8400_POWER_MANAGEMENT_2, WM8400_AINR_ENA_SHIFT,
|
||||
0, NULL, 0),
|
||||
|
||||
/* INMIXL */
|
||||
SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0,
|
||||
SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
|
||||
&wm8400_dapm_inmixl_controls[0],
|
||||
ARRAY_SIZE(wm8400_dapm_inmixl_controls),
|
||||
inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
ARRAY_SIZE(wm8400_dapm_inmixl_controls)),
|
||||
|
||||
/* AINLMUX */
|
||||
SND_SOC_DAPM_MUX_E("AILNMUX", WM8400_INTDRIVBITS, WM8400_AINLMUX_PWR, 0,
|
||||
&wm8400_dapm_ainlmux_controls, inmixer_event,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_MUX("AILNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainlmux_controls),
|
||||
|
||||
/* INMIXR */
|
||||
SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0,
|
||||
SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
|
||||
&wm8400_dapm_inmixr_controls[0],
|
||||
ARRAY_SIZE(wm8400_dapm_inmixr_controls),
|
||||
inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
ARRAY_SIZE(wm8400_dapm_inmixr_controls)),
|
||||
|
||||
/* AINRMUX */
|
||||
SND_SOC_DAPM_MUX_E("AIRNMUX", WM8400_INTDRIVBITS, WM8400_AINRMUX_PWR, 0,
|
||||
&wm8400_dapm_ainrmux_controls, inmixer_event,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_MUX("AIRNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainrmux_controls),
|
||||
|
||||
/* Output Side */
|
||||
/* DACs */
|
||||
|
@ -789,11 +729,13 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = {
|
|||
{"LIN34 PGA", "LIN3 Switch", "LIN3"},
|
||||
{"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"},
|
||||
/* INMIXL */
|
||||
{"INMIXL", NULL, "INL"},
|
||||
{"INMIXL", "Record Left Volume", "LOMIX"},
|
||||
{"INMIXL", "LIN2 Volume", "LIN2"},
|
||||
{"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
|
||||
{"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
|
||||
/* AILNMUX */
|
||||
{"AILNMUX", NULL, "INL"},
|
||||
{"AILNMUX", "INMIXL Mix", "INMIXL"},
|
||||
{"AILNMUX", "DIFFINL Mix", "LIN12 PGA"},
|
||||
{"AILNMUX", "DIFFINL Mix", "LIN34 PGA"},
|
||||
|
@ -808,12 +750,14 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = {
|
|||
/* RIN34 PGA */
|
||||
{"RIN34 PGA", "RIN3 Switch", "RIN3"},
|
||||
{"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"},
|
||||
/* INMIXL */
|
||||
/* INMIXR */
|
||||
{"INMIXR", NULL, "INR"},
|
||||
{"INMIXR", "Record Right Volume", "ROMIX"},
|
||||
{"INMIXR", "RIN2 Volume", "RIN2"},
|
||||
{"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
|
||||
{"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
|
||||
/* AIRNMUX */
|
||||
{"AIRNMUX", NULL, "INR"},
|
||||
{"AIRNMUX", "INMIXR Mix", "INMIXR"},
|
||||
{"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"},
|
||||
{"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"},
|
||||
|
@ -1365,9 +1309,12 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
|
|||
return -ENOMEM;
|
||||
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
codec->control_data = priv->wm8400 = wm8400;
|
||||
priv->wm8400 = wm8400;
|
||||
codec->control_data = wm8400->regmap;
|
||||
priv->codec = codec;
|
||||
|
||||
snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
|
||||
|
||||
ret = devm_regulator_bulk_get(wm8400->dev,
|
||||
ARRAY_SIZE(power), &power[0]);
|
||||
if (ret != 0) {
|
||||
|
@ -1414,8 +1361,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
|
|||
.remove = wm8400_codec_remove,
|
||||
.suspend = wm8400_suspend,
|
||||
.resume = wm8400_resume,
|
||||
.read = snd_soc_read,
|
||||
.write = wm8400_write,
|
||||
.set_bias_level = wm8400_set_bias_level,
|
||||
|
||||
.controls = wm8400_snd_controls,
|
||||
|
|
|
@ -3242,7 +3242,7 @@ static void wm8962_free_beep(struct snd_soc_codec *codec)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)
|
||||
static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)
|
||||
{
|
||||
int mask = 0;
|
||||
int val = 0;
|
||||
|
@ -3263,8 +3263,8 @@ static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)
|
|||
}
|
||||
|
||||
if (mask)
|
||||
snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1,
|
||||
mask, val);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_ANALOGUE_CLOCKING1,
|
||||
mask, val);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
@ -3276,7 +3276,6 @@ static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip)
|
|||
static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
|
||||
struct snd_soc_codec *codec = wm8962->codec;
|
||||
|
||||
/* The WM8962 GPIOs aren't linearly numbered. For simplicity
|
||||
* we export linear numbers and error out if the unsupported
|
||||
|
@ -3292,7 +3291,7 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
wm8962_set_gpio_mode(codec, offset + 1);
|
||||
wm8962_set_gpio_mode(wm8962, offset + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3376,8 +3375,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
|
|||
{
|
||||
int ret;
|
||||
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8962_pdata *pdata = &wm8962->pdata;
|
||||
int i, trigger, irq_pol;
|
||||
int i;
|
||||
bool dmicclk, dmicdat;
|
||||
|
||||
wm8962->codec = codec;
|
||||
|
@ -3409,75 +3407,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
|
|||
}
|
||||
}
|
||||
|
||||
/* SYSCLK defaults to on; make sure it is off so we can safely
|
||||
* write to registers if the device is declocked.
|
||||
*/
|
||||
snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0);
|
||||
|
||||
/* Ensure we have soft control over all registers */
|
||||
snd_soc_update_bits(codec, WM8962_CLOCKING2,
|
||||
WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
|
||||
|
||||
/* Ensure that the oscillator and PLLs are disabled */
|
||||
snd_soc_update_bits(codec, WM8962_PLL2,
|
||||
WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
|
||||
0);
|
||||
|
||||
/* Apply static configuration for GPIOs */
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
|
||||
if (pdata->gpio_init[i]) {
|
||||
wm8962_set_gpio_mode(codec, i + 1);
|
||||
snd_soc_write(codec, 0x200 + i,
|
||||
pdata->gpio_init[i] & 0xffff);
|
||||
}
|
||||
|
||||
|
||||
/* Put the speakers into mono mode? */
|
||||
if (pdata->spk_mono)
|
||||
snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_2,
|
||||
WM8962_SPK_MONO_MASK, WM8962_SPK_MONO);
|
||||
|
||||
/* Micbias setup, detection enable and detection
|
||||
* threasholds. */
|
||||
if (pdata->mic_cfg)
|
||||
snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
|
||||
WM8962_MICDET_ENA |
|
||||
WM8962_MICDET_THR_MASK |
|
||||
WM8962_MICSHORT_THR_MASK |
|
||||
WM8962_MICBIAS_LVL,
|
||||
pdata->mic_cfg);
|
||||
|
||||
/* Latch volume update bits */
|
||||
snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME,
|
||||
WM8962_IN_VU, WM8962_IN_VU);
|
||||
snd_soc_update_bits(codec, WM8962_RIGHT_INPUT_VOLUME,
|
||||
WM8962_IN_VU, WM8962_IN_VU);
|
||||
snd_soc_update_bits(codec, WM8962_LEFT_ADC_VOLUME,
|
||||
WM8962_ADC_VU, WM8962_ADC_VU);
|
||||
snd_soc_update_bits(codec, WM8962_RIGHT_ADC_VOLUME,
|
||||
WM8962_ADC_VU, WM8962_ADC_VU);
|
||||
snd_soc_update_bits(codec, WM8962_LEFT_DAC_VOLUME,
|
||||
WM8962_DAC_VU, WM8962_DAC_VU);
|
||||
snd_soc_update_bits(codec, WM8962_RIGHT_DAC_VOLUME,
|
||||
WM8962_DAC_VU, WM8962_DAC_VU);
|
||||
snd_soc_update_bits(codec, WM8962_SPKOUTL_VOLUME,
|
||||
WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
|
||||
snd_soc_update_bits(codec, WM8962_SPKOUTR_VOLUME,
|
||||
WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
|
||||
snd_soc_update_bits(codec, WM8962_HPOUTL_VOLUME,
|
||||
WM8962_HPOUT_VU, WM8962_HPOUT_VU);
|
||||
snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME,
|
||||
WM8962_HPOUT_VU, WM8962_HPOUT_VU);
|
||||
|
||||
/* Stereo control for EQ */
|
||||
snd_soc_update_bits(codec, WM8962_EQ1, WM8962_EQ_SHARED_COEFF, 0);
|
||||
|
||||
/* Don't debouce interrupts so we don't need SYSCLK */
|
||||
snd_soc_update_bits(codec, WM8962_IRQ_DEBOUNCE,
|
||||
WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB |
|
||||
WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB,
|
||||
0);
|
||||
|
||||
wm8962_add_widgets(codec);
|
||||
|
||||
/* Save boards having to disable DMIC when not in use */
|
||||
|
@ -3506,36 +3435,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
|
|||
wm8962_init_beep(codec);
|
||||
wm8962_init_gpio(codec);
|
||||
|
||||
if (wm8962->irq) {
|
||||
if (pdata->irq_active_low) {
|
||||
trigger = IRQF_TRIGGER_LOW;
|
||||
irq_pol = WM8962_IRQ_POL;
|
||||
} else {
|
||||
trigger = IRQF_TRIGGER_HIGH;
|
||||
irq_pol = 0;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL,
|
||||
WM8962_IRQ_POL, irq_pol);
|
||||
|
||||
ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq,
|
||||
trigger | IRQF_ONESHOT,
|
||||
"wm8962", codec->dev);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
|
||||
wm8962->irq, ret);
|
||||
wm8962->irq = 0;
|
||||
/* Non-fatal */
|
||||
} else {
|
||||
/* Enable some IRQs by default */
|
||||
snd_soc_update_bits(codec,
|
||||
WM8962_INTERRUPT_STATUS_2_MASK,
|
||||
WM8962_FLL_LOCK_EINT |
|
||||
WM8962_TEMP_SHUT_EINT |
|
||||
WM8962_FIFOS_ERR_EINT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3544,9 +3443,6 @@ static int wm8962_remove(struct snd_soc_codec *codec)
|
|||
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
|
||||
int i;
|
||||
|
||||
if (wm8962->irq)
|
||||
free_irq(wm8962->irq, codec);
|
||||
|
||||
cancel_delayed_work_sync(&wm8962->mic_work);
|
||||
|
||||
wm8962_free_gpio(codec);
|
||||
|
@ -3619,7 +3515,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
|
|||
struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev);
|
||||
struct wm8962_priv *wm8962;
|
||||
unsigned int reg;
|
||||
int ret, i;
|
||||
int ret, i, irq_pol, trigger;
|
||||
|
||||
wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv),
|
||||
GFP_KERNEL);
|
||||
|
@ -3704,6 +3600,77 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
|
|||
goto err_enable;
|
||||
}
|
||||
|
||||
/* SYSCLK defaults to on; make sure it is off so we can safely
|
||||
* write to registers if the device is declocked.
|
||||
*/
|
||||
regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
|
||||
WM8962_SYSCLK_ENA, 0);
|
||||
|
||||
/* Ensure we have soft control over all registers */
|
||||
regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
|
||||
WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
|
||||
|
||||
/* Ensure that the oscillator and PLLs are disabled */
|
||||
regmap_update_bits(wm8962->regmap, WM8962_PLL2,
|
||||
WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
|
||||
0);
|
||||
|
||||
/* Apply static configuration for GPIOs */
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
|
||||
if (pdata->gpio_init[i]) {
|
||||
wm8962_set_gpio_mode(wm8962, i + 1);
|
||||
regmap_write(wm8962->regmap, 0x200 + i,
|
||||
pdata->gpio_init[i] & 0xffff);
|
||||
}
|
||||
|
||||
|
||||
/* Put the speakers into mono mode? */
|
||||
if (pdata->spk_mono)
|
||||
regmap_update_bits(wm8962->regmap, WM8962_CLASS_D_CONTROL_2,
|
||||
WM8962_SPK_MONO_MASK, WM8962_SPK_MONO);
|
||||
|
||||
/* Micbias setup, detection enable and detection
|
||||
* threasholds. */
|
||||
if (pdata->mic_cfg)
|
||||
regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4,
|
||||
WM8962_MICDET_ENA |
|
||||
WM8962_MICDET_THR_MASK |
|
||||
WM8962_MICSHORT_THR_MASK |
|
||||
WM8962_MICBIAS_LVL,
|
||||
pdata->mic_cfg);
|
||||
|
||||
/* Latch volume update bits */
|
||||
regmap_update_bits(wm8962->regmap, WM8962_LEFT_INPUT_VOLUME,
|
||||
WM8962_IN_VU, WM8962_IN_VU);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_RIGHT_INPUT_VOLUME,
|
||||
WM8962_IN_VU, WM8962_IN_VU);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_LEFT_ADC_VOLUME,
|
||||
WM8962_ADC_VU, WM8962_ADC_VU);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_RIGHT_ADC_VOLUME,
|
||||
WM8962_ADC_VU, WM8962_ADC_VU);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_LEFT_DAC_VOLUME,
|
||||
WM8962_DAC_VU, WM8962_DAC_VU);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_RIGHT_DAC_VOLUME,
|
||||
WM8962_DAC_VU, WM8962_DAC_VU);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_SPKOUTL_VOLUME,
|
||||
WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_SPKOUTR_VOLUME,
|
||||
WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_HPOUTL_VOLUME,
|
||||
WM8962_HPOUT_VU, WM8962_HPOUT_VU);
|
||||
regmap_update_bits(wm8962->regmap, WM8962_HPOUTR_VOLUME,
|
||||
WM8962_HPOUT_VU, WM8962_HPOUT_VU);
|
||||
|
||||
/* Stereo control for EQ */
|
||||
regmap_update_bits(wm8962->regmap, WM8962_EQ1,
|
||||
WM8962_EQ_SHARED_COEFF, 0);
|
||||
|
||||
/* Don't debouce interrupts so we don't need SYSCLK */
|
||||
regmap_update_bits(wm8962->regmap, WM8962_IRQ_DEBOUNCE,
|
||||
WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB |
|
||||
WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB,
|
||||
0);
|
||||
|
||||
if (wm8962->pdata.in4_dc_measure) {
|
||||
ret = regmap_register_patch(wm8962->regmap,
|
||||
wm8962_dc_measure,
|
||||
|
@ -3714,6 +3681,37 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
|
|||
ret);
|
||||
}
|
||||
|
||||
if (wm8962->irq) {
|
||||
if (pdata->irq_active_low) {
|
||||
trigger = IRQF_TRIGGER_LOW;
|
||||
irq_pol = WM8962_IRQ_POL;
|
||||
} else {
|
||||
trigger = IRQF_TRIGGER_HIGH;
|
||||
irq_pol = 0;
|
||||
}
|
||||
|
||||
regmap_update_bits(wm8962->regmap, WM8962_INTERRUPT_CONTROL,
|
||||
WM8962_IRQ_POL, irq_pol);
|
||||
|
||||
ret = devm_request_threaded_irq(&i2c->dev, wm8962->irq, NULL,
|
||||
wm8962_irq,
|
||||
trigger | IRQF_ONESHOT,
|
||||
"wm8962", &i2c->dev);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
|
||||
wm8962->irq, ret);
|
||||
wm8962->irq = 0;
|
||||
/* Non-fatal */
|
||||
} else {
|
||||
/* Enable some IRQs by default */
|
||||
regmap_update_bits(wm8962->regmap,
|
||||
WM8962_INTERRUPT_STATUS_2_MASK,
|
||||
WM8962_FLL_LOCK_EINT |
|
||||
WM8962_TEMP_SHUT_EINT |
|
||||
WM8962_FIFOS_ERR_EINT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_enable(&i2c->dev);
|
||||
pm_request_idle(&i2c->dev);
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
config SND_DAVINCI_SOC
|
||||
tristate "SoC Audio for the TI DAVINCI chip"
|
||||
depends on ARCH_DAVINCI
|
||||
tristate "SoC Audio for the TI DAVINCI or AM33XX chip"
|
||||
depends on ARCH_DAVINCI || SOC_AM33XX
|
||||
help
|
||||
Platform driver for daVinci or AM33xx
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the DAVINCI AC97 or I2S interface. You will also need
|
||||
the DAVINCI AC97, I2S, or McASP interface. You will also need
|
||||
to select the audio interfaces to support below.
|
||||
|
||||
config SND_DAVINCI_SOC_I2S
|
||||
|
@ -15,6 +16,17 @@ config SND_DAVINCI_SOC_MCASP
|
|||
config SND_DAVINCI_SOC_VCIF
|
||||
tristate
|
||||
|
||||
config SND_AM33XX_SOC_EVM
|
||||
tristate "SoC Audio for the AM33XX chip based boards"
|
||||
depends on SND_DAVINCI_SOC && SOC_AM33XX
|
||||
select SND_SOC_TLV320AIC3X
|
||||
select SND_DAVINCI_SOC_MCASP
|
||||
help
|
||||
Say Y or M if you want to add support for SoC audio on AM33XX
|
||||
boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
|
||||
AM335X-EVMSK, and BeagelBone with AudioCape boards have this
|
||||
setup.
|
||||
|
||||
config SND_DAVINCI_SOC_EVM
|
||||
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
|
||||
depends on SND_DAVINCI_SOC
|
||||
|
|
|
@ -13,6 +13,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
|
|||
snd-soc-evm-objs := davinci-evm.o
|
||||
|
||||
obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
|
||||
obj-$(CONFIG_SND_AM33XX_SOC_EVM) += snd-soc-evm.o
|
||||
obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o
|
||||
obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o
|
||||
obj-$(CONFIG_SND_DA850_SOC_EVM) += snd-soc-evm.o
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/edma.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
|
@ -23,10 +24,16 @@
|
|||
#include <asm/dma.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <linux/edma.h>
|
||||
|
||||
#include "davinci-pcm.h"
|
||||
#include "davinci-i2s.h"
|
||||
#include "davinci-mcasp.h"
|
||||
|
||||
struct snd_soc_card_drvdata_davinci {
|
||||
unsigned sysclk;
|
||||
};
|
||||
|
||||
#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
|
||||
SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
|
||||
static int evm_hw_params(struct snd_pcm_substream *substream,
|
||||
|
@ -35,27 +42,11 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_card *soc_card = codec->card;
|
||||
int ret = 0;
|
||||
unsigned sysclk;
|
||||
|
||||
/* ASP1 on DM355 EVM is clocked by an external oscillator */
|
||||
if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() ||
|
||||
machine_is_davinci_dm365_evm())
|
||||
sysclk = 27000000;
|
||||
|
||||
/* ASP0 in DM6446 EVM is clocked by U55, as configured by
|
||||
* board-dm644x-evm.c using GPIOs from U18. There are six
|
||||
* options; here we "know" we use a 48 KHz sample rate.
|
||||
*/
|
||||
else if (machine_is_davinci_evm())
|
||||
sysclk = 12288000;
|
||||
|
||||
else if (machine_is_davinci_da830_evm() ||
|
||||
machine_is_davinci_da850_evm())
|
||||
sysclk = 24576000;
|
||||
|
||||
else
|
||||
return -EINVAL;
|
||||
unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
|
||||
snd_soc_card_get_drvdata(soc_card))->sysclk;
|
||||
|
||||
/* set codec DAI configuration */
|
||||
ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT);
|
||||
|
@ -133,13 +124,22 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
|
|||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
struct device_node *np = codec->card->dev->of_node;
|
||||
int ret;
|
||||
|
||||
/* Add davinci-evm specific widgets */
|
||||
snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
|
||||
ARRAY_SIZE(aic3x_dapm_widgets));
|
||||
|
||||
/* Set up davinci-evm specific audio path audio_map */
|
||||
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
|
||||
if (np) {
|
||||
ret = snd_soc_of_parse_audio_routing(codec->card,
|
||||
"ti,audio-routing");
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* Set up davinci-evm specific audio path audio_map */
|
||||
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
|
||||
}
|
||||
|
||||
/* not connected */
|
||||
snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
|
||||
|
@ -243,35 +243,65 @@ static struct snd_soc_dai_link da850_evm_dai = {
|
|||
};
|
||||
|
||||
/* davinci dm6446 evm audio machine driver */
|
||||
/*
|
||||
* ASP0 in DM6446 EVM is clocked by U55, as configured by
|
||||
* board-dm644x-evm.c using GPIOs from U18. There are six
|
||||
* options; here we "know" we use a 48 KHz sample rate.
|
||||
*/
|
||||
static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = {
|
||||
.sysclk = 12288000,
|
||||
};
|
||||
|
||||
static struct snd_soc_card dm6446_snd_soc_card_evm = {
|
||||
.name = "DaVinci DM6446 EVM",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &dm6446_evm_dai,
|
||||
.num_links = 1,
|
||||
.drvdata = &dm6446_snd_soc_card_drvdata,
|
||||
};
|
||||
|
||||
/* davinci dm355 evm audio machine driver */
|
||||
/* ASP1 on DM355 EVM is clocked by an external oscillator */
|
||||
static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = {
|
||||
.sysclk = 27000000,
|
||||
};
|
||||
|
||||
static struct snd_soc_card dm355_snd_soc_card_evm = {
|
||||
.name = "DaVinci DM355 EVM",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &dm355_evm_dai,
|
||||
.num_links = 1,
|
||||
.drvdata = &dm355_snd_soc_card_drvdata,
|
||||
};
|
||||
|
||||
/* davinci dm365 evm audio machine driver */
|
||||
static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = {
|
||||
.sysclk = 27000000,
|
||||
};
|
||||
|
||||
static struct snd_soc_card dm365_snd_soc_card_evm = {
|
||||
.name = "DaVinci DM365 EVM",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &dm365_evm_dai,
|
||||
.num_links = 1,
|
||||
.drvdata = &dm365_snd_soc_card_drvdata,
|
||||
};
|
||||
|
||||
/* davinci dm6467 evm audio machine driver */
|
||||
static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = {
|
||||
.sysclk = 27000000,
|
||||
};
|
||||
|
||||
static struct snd_soc_card dm6467_snd_soc_card_evm = {
|
||||
.name = "DaVinci DM6467 EVM",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = dm6467_evm_dai,
|
||||
.num_links = ARRAY_SIZE(dm6467_evm_dai),
|
||||
.drvdata = &dm6467_snd_soc_card_drvdata,
|
||||
};
|
||||
|
||||
static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = {
|
||||
.sysclk = 24576000,
|
||||
};
|
||||
|
||||
static struct snd_soc_card da830_snd_soc_card = {
|
||||
|
@ -279,6 +309,11 @@ static struct snd_soc_card da830_snd_soc_card = {
|
|||
.owner = THIS_MODULE,
|
||||
.dai_link = &da830_evm_dai,
|
||||
.num_links = 1,
|
||||
.drvdata = &da830_snd_soc_card_drvdata,
|
||||
};
|
||||
|
||||
static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = {
|
||||
.sysclk = 24576000,
|
||||
};
|
||||
|
||||
static struct snd_soc_card da850_snd_soc_card = {
|
||||
|
@ -286,8 +321,101 @@ static struct snd_soc_card da850_snd_soc_card = {
|
|||
.owner = THIS_MODULE,
|
||||
.dai_link = &da850_evm_dai,
|
||||
.num_links = 1,
|
||||
.drvdata = &da850_snd_soc_card_drvdata,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
|
||||
/*
|
||||
* The struct is used as place holder. It will be completely
|
||||
* filled with data from dt node.
|
||||
*/
|
||||
static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
|
||||
.name = "TLV320AIC3X",
|
||||
.stream_name = "AIC3X",
|
||||
.codec_dai_name = "tlv320aic3x-hifi",
|
||||
.ops = &evm_ops,
|
||||
.init = evm_aic3x_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id davinci_evm_dt_ids[] = {
|
||||
{
|
||||
.compatible = "ti,da830-evm-audio",
|
||||
.data = (void *) &evm_dai_tlv320aic3x,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
|
||||
|
||||
/* davinci evm audio machine driver */
|
||||
static struct snd_soc_card evm_soc_card = {
|
||||
.owner = THIS_MODULE,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static int davinci_evm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct of_device_id *match =
|
||||
of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
|
||||
struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data;
|
||||
struct snd_soc_card_drvdata_davinci *drvdata = NULL;
|
||||
int ret = 0;
|
||||
|
||||
evm_soc_card.dai_link = dai;
|
||||
|
||||
dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);
|
||||
if (!dai->codec_of_node)
|
||||
return -EINVAL;
|
||||
|
||||
dai->cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
|
||||
if (!dai->cpu_of_node)
|
||||
return -EINVAL;
|
||||
|
||||
dai->platform_of_node = dai->cpu_of_node;
|
||||
|
||||
evm_soc_card.dev = &pdev->dev;
|
||||
ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
|
||||
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int davinci_evm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver davinci_evm_driver = {
|
||||
.probe = davinci_evm_probe,
|
||||
.remove = davinci_evm_remove,
|
||||
.driver = {
|
||||
.name = "davinci_evm",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(davinci_evm_dt_ids),
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *evm_snd_device;
|
||||
|
||||
static int __init evm_init(void)
|
||||
|
@ -296,6 +424,15 @@ static int __init evm_init(void)
|
|||
int index;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If dtb is there, the devices will be created dynamically.
|
||||
* Only register platfrom driver structure.
|
||||
*/
|
||||
#if defined(CONFIG_OF)
|
||||
if (of_have_populated_dt())
|
||||
return platform_driver_register(&davinci_evm_driver);
|
||||
#endif
|
||||
|
||||
if (machine_is_davinci_evm()) {
|
||||
evm_snd_dev_data = &dm6446_snd_soc_card_evm;
|
||||
index = 0;
|
||||
|
@ -331,6 +468,13 @@ static int __init evm_init(void)
|
|||
|
||||
static void __exit evm_exit(void)
|
||||
{
|
||||
#if defined(CONFIG_OF)
|
||||
if (of_have_populated_dt()) {
|
||||
platform_driver_unregister(&davinci_evm_driver);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
platform_device_unregister(evm_snd_device);
|
||||
}
|
||||
|
||||
|
|
|
@ -1001,18 +1001,40 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
|
|||
.name = "davinci-mcasp",
|
||||
};
|
||||
|
||||
/* Some HW specific values and defaults. The rest is filled in from DT. */
|
||||
static struct snd_platform_data dm646x_mcasp_pdata = {
|
||||
.tx_dma_offset = 0x400,
|
||||
.rx_dma_offset = 0x400,
|
||||
.asp_chan_q = EVENTQ_0,
|
||||
.version = MCASP_VERSION_1,
|
||||
};
|
||||
|
||||
static struct snd_platform_data da830_mcasp_pdata = {
|
||||
.tx_dma_offset = 0x2000,
|
||||
.rx_dma_offset = 0x2000,
|
||||
.asp_chan_q = EVENTQ_0,
|
||||
.version = MCASP_VERSION_2,
|
||||
};
|
||||
|
||||
static struct snd_platform_data omap2_mcasp_pdata = {
|
||||
.tx_dma_offset = 0,
|
||||
.rx_dma_offset = 0,
|
||||
.asp_chan_q = EVENTQ_0,
|
||||
.version = MCASP_VERSION_3,
|
||||
};
|
||||
|
||||
static const struct of_device_id mcasp_dt_ids[] = {
|
||||
{
|
||||
.compatible = "ti,dm646x-mcasp-audio",
|
||||
.data = (void *)MCASP_VERSION_1,
|
||||
.data = &dm646x_mcasp_pdata,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,da830-mcasp-audio",
|
||||
.data = (void *)MCASP_VERSION_2,
|
||||
.data = &da830_mcasp_pdata,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,omap2-mcasp-audio",
|
||||
.data = (void *)MCASP_VERSION_3,
|
||||
.compatible = "ti,am33xx-mcasp-audio",
|
||||
.data = &omap2_mcasp_pdata,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
@ -1025,9 +1047,9 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
|
|||
struct snd_platform_data *pdata = NULL;
|
||||
const struct of_device_id *match =
|
||||
of_match_device(mcasp_dt_ids, &pdev->dev);
|
||||
struct of_phandle_args dma_spec;
|
||||
|
||||
const u32 *of_serial_dir32;
|
||||
u8 *of_serial_dir;
|
||||
u32 val;
|
||||
int i, ret = 0;
|
||||
|
||||
|
@ -1035,20 +1057,13 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
|
|||
pdata = pdev->dev.platform_data;
|
||||
return pdata;
|
||||
} else if (match) {
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
ret = -ENOMEM;
|
||||
goto nodata;
|
||||
}
|
||||
pdata = (struct snd_platform_data *) match->data;
|
||||
} else {
|
||||
/* control shouldn't reach here. something is wrong */
|
||||
ret = -EINVAL;
|
||||
goto nodata;
|
||||
}
|
||||
|
||||
if (match->data)
|
||||
pdata->version = (u8)((int)match->data);
|
||||
|
||||
ret = of_property_read_u32(np, "op-mode", &val);
|
||||
if (ret >= 0)
|
||||
pdata->op_mode = val;
|
||||
|
@ -1065,35 +1080,46 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
|
|||
pdata->tdm_slots = val;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-serializer", &val);
|
||||
if (ret >= 0)
|
||||
pdata->num_serializer = val;
|
||||
|
||||
of_serial_dir32 = of_get_property(np, "serial-dir", &val);
|
||||
val /= sizeof(u32);
|
||||
if (val != pdata->num_serializer) {
|
||||
dev_err(&pdev->dev,
|
||||
"num-serializer(%d) != serial-dir size(%d)\n",
|
||||
pdata->num_serializer, val);
|
||||
ret = -EINVAL;
|
||||
goto nodata;
|
||||
}
|
||||
|
||||
if (of_serial_dir32) {
|
||||
of_serial_dir = devm_kzalloc(&pdev->dev,
|
||||
(sizeof(*of_serial_dir) * val),
|
||||
GFP_KERNEL);
|
||||
u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
|
||||
(sizeof(*of_serial_dir) * val),
|
||||
GFP_KERNEL);
|
||||
if (!of_serial_dir) {
|
||||
ret = -ENOMEM;
|
||||
goto nodata;
|
||||
}
|
||||
|
||||
for (i = 0; i < pdata->num_serializer; i++)
|
||||
for (i = 0; i < val; i++)
|
||||
of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
|
||||
|
||||
pdata->num_serializer = val;
|
||||
pdata->serial_dir = of_serial_dir;
|
||||
}
|
||||
|
||||
ret = of_property_match_string(np, "dma-names", "tx");
|
||||
if (ret < 0)
|
||||
goto nodata;
|
||||
|
||||
ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
|
||||
&dma_spec);
|
||||
if (ret < 0)
|
||||
goto nodata;
|
||||
|
||||
pdata->tx_dma_channel = dma_spec.args[0];
|
||||
|
||||
ret = of_property_match_string(np, "dma-names", "rx");
|
||||
if (ret < 0)
|
||||
goto nodata;
|
||||
|
||||
ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
|
||||
&dma_spec);
|
||||
if (ret < 0)
|
||||
goto nodata;
|
||||
|
||||
pdata->rx_dma_channel = dma_spec.args[0];
|
||||
|
||||
ret = of_property_read_u32(np, "tx-num-evt", &val);
|
||||
if (ret >= 0)
|
||||
pdata->txnumevt = val;
|
||||
|
@ -1124,7 +1150,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
|
|||
static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_pcm_dma_params *dma_data;
|
||||
struct resource *mem, *ioarea, *res;
|
||||
struct resource *mem, *ioarea, *res, *dat;
|
||||
struct snd_platform_data *pdata;
|
||||
struct davinci_audio_dev *dev;
|
||||
int ret;
|
||||
|
@ -1145,10 +1171,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "no mem resource?\n");
|
||||
return -ENODEV;
|
||||
dev_warn(dev->dev,
|
||||
"\"mpu\" mem resource not found, using index 0\n");
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "no mem resource?\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
ioarea = devm_request_mem_region(&pdev->dev, mem->start,
|
||||
|
@ -1182,40 +1213,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
|||
dev->rxnumevt = pdata->rxnumevt;
|
||||
dev->dev = &pdev->dev;
|
||||
|
||||
dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
|
||||
if (!dat)
|
||||
dat = mem;
|
||||
|
||||
dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
dma_data->asp_chan_q = pdata->asp_chan_q;
|
||||
dma_data->ram_chan_q = pdata->ram_chan_q;
|
||||
dma_data->sram_pool = pdata->sram_pool;
|
||||
dma_data->sram_size = pdata->sram_size_playback;
|
||||
dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
|
||||
mem->start);
|
||||
dma_data->dma_addr = dat->start + pdata->tx_dma_offset;
|
||||
|
||||
/* first TX, then RX */
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no DMA resource\n");
|
||||
ret = -ENODEV;
|
||||
goto err_release_clk;
|
||||
}
|
||||
|
||||
dma_data->channel = res->start;
|
||||
if (res)
|
||||
dma_data->channel = res->start;
|
||||
else
|
||||
dma_data->channel = pdata->tx_dma_channel;
|
||||
|
||||
dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
|
||||
dma_data->asp_chan_q = pdata->asp_chan_q;
|
||||
dma_data->ram_chan_q = pdata->ram_chan_q;
|
||||
dma_data->sram_pool = pdata->sram_pool;
|
||||
dma_data->sram_size = pdata->sram_size_capture;
|
||||
dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
|
||||
mem->start);
|
||||
dma_data->dma_addr = dat->start + pdata->rx_dma_offset;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no DMA resource\n");
|
||||
ret = -ENODEV;
|
||||
goto err_release_clk;
|
||||
}
|
||||
if (res)
|
||||
dma_data->channel = res->start;
|
||||
else
|
||||
dma_data->channel = pdata->rx_dma_channel;
|
||||
|
||||
dma_data->channel = res->start;
|
||||
dev_set_drvdata(&pdev->dev, dev);
|
||||
ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
|
||||
&davinci_mcasp_dai[pdata->op_mode], 1);
|
||||
|
@ -1251,12 +1278,51 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int davinci_mcasp_suspend(struct device *dev)
|
||||
{
|
||||
struct davinci_audio_dev *a = dev_get_drvdata(dev);
|
||||
void __iomem *base = a->base;
|
||||
|
||||
a->context.txfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_TXFMCTL_REG);
|
||||
a->context.rxfmtctl = mcasp_get_reg(base + DAVINCI_MCASP_RXFMCTL_REG);
|
||||
a->context.txfmt = mcasp_get_reg(base + DAVINCI_MCASP_TXFMT_REG);
|
||||
a->context.rxfmt = mcasp_get_reg(base + DAVINCI_MCASP_RXFMT_REG);
|
||||
a->context.aclkxctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKXCTL_REG);
|
||||
a->context.aclkrctl = mcasp_get_reg(base + DAVINCI_MCASP_ACLKRCTL_REG);
|
||||
a->context.pdir = mcasp_get_reg(base + DAVINCI_MCASP_PDIR_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_mcasp_resume(struct device *dev)
|
||||
{
|
||||
struct davinci_audio_dev *a = dev_get_drvdata(dev);
|
||||
void __iomem *base = a->base;
|
||||
|
||||
mcasp_set_reg(base + DAVINCI_MCASP_TXFMCTL_REG, a->context.txfmtctl);
|
||||
mcasp_set_reg(base + DAVINCI_MCASP_RXFMCTL_REG, a->context.rxfmtctl);
|
||||
mcasp_set_reg(base + DAVINCI_MCASP_TXFMT_REG, a->context.txfmt);
|
||||
mcasp_set_reg(base + DAVINCI_MCASP_RXFMT_REG, a->context.rxfmt);
|
||||
mcasp_set_reg(base + DAVINCI_MCASP_ACLKXCTL_REG, a->context.aclkxctl);
|
||||
mcasp_set_reg(base + DAVINCI_MCASP_ACLKRCTL_REG, a->context.aclkrctl);
|
||||
mcasp_set_reg(base + DAVINCI_MCASP_PDIR_REG, a->context.pdir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops,
|
||||
davinci_mcasp_suspend,
|
||||
davinci_mcasp_resume);
|
||||
|
||||
static struct platform_driver davinci_mcasp_driver = {
|
||||
.probe = davinci_mcasp_probe,
|
||||
.remove = davinci_mcasp_remove,
|
||||
.driver = {
|
||||
.name = "davinci-mcasp",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &davinci_mcasp_pm_ops,
|
||||
.of_match_table = mcasp_dt_ids,
|
||||
},
|
||||
};
|
||||
|
@ -1266,4 +1332,3 @@ module_platform_driver(davinci_mcasp_driver);
|
|||
MODULE_AUTHOR("Steve Chen");
|
||||
MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
|
@ -43,6 +43,18 @@ struct davinci_audio_dev {
|
|||
/* McASP FIFO related */
|
||||
u8 txnumevt;
|
||||
u8 rxnumevt;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct {
|
||||
u32 txfmtctl;
|
||||
u32 rxfmtctl;
|
||||
u32 txfmt;
|
||||
u32 rxfmt;
|
||||
u32 aclkxctl;
|
||||
u32 aclkrctl;
|
||||
u32 pdir;
|
||||
} context;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* DAVINCI_MCASP_H */
|
||||
|
|
|
@ -963,7 +963,7 @@ static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
|
|||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
|
||||
|
@ -982,7 +982,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
|
|||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config fsl_spdif_regmap_config = {
|
||||
|
@ -1172,23 +1172,16 @@ static int fsl_spdif_probe(struct platform_device *pdev)
|
|||
/* Register with ASoC */
|
||||
dev_set_drvdata(&pdev->dev, spdif_priv);
|
||||
|
||||
ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
|
||||
&spdif_priv->cpu_dai_drv, 1);
|
||||
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
|
||||
&spdif_priv->cpu_dai_drv, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = imx_pcm_dma_init(pdev);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
|
||||
goto error_component;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error_component:
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1196,7 +1189,6 @@ static int fsl_spdif_probe(struct platform_device *pdev)
|
|||
static int fsl_spdif_remove(struct platform_device *pdev)
|
||||
{
|
||||
imx_pcm_dma_exit(pdev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -469,19 +469,12 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
|
|||
* parameters, then the second stream may be
|
||||
* constrained to the wrong sample rate or size.
|
||||
*/
|
||||
if (!first_runtime->sample_bits) {
|
||||
dev_err(substream->pcm->card->dev,
|
||||
"set sample size in %s stream first\n",
|
||||
substream->stream ==
|
||||
SNDRV_PCM_STREAM_PLAYBACK
|
||||
? "capture" : "playback");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
|
||||
if (first_runtime->sample_bits) {
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
|
||||
first_runtime->sample_bits,
|
||||
first_runtime->sample_bits);
|
||||
}
|
||||
}
|
||||
|
||||
ssi_private->second_stream = substream;
|
||||
|
@ -748,7 +741,7 @@ static void fsl_ssi_ac97_init(void)
|
|||
fsl_ssi_setup(fsl_ac97_data);
|
||||
}
|
||||
|
||||
void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
||||
static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
||||
unsigned short val)
|
||||
{
|
||||
struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
|
||||
|
@ -770,7 +763,7 @@ void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
|
|||
udelay(100);
|
||||
}
|
||||
|
||||
unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
|
||||
static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
|
||||
unsigned short reg)
|
||||
{
|
||||
struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
|
||||
|
@ -936,7 +929,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
|||
ssi_private->ssi_phys = res.start;
|
||||
|
||||
ssi_private->irq = irq_of_parse_and_map(np, 0);
|
||||
if (ssi_private->irq == 0) {
|
||||
if (!ssi_private->irq) {
|
||||
dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
@ -1135,7 +1128,6 @@ static int fsl_ssi_remove(struct platform_device *pdev)
|
|||
if (ssi_private->ssi_on_imx)
|
||||
imx_pcm_dma_exit(pdev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
device_remove_file(&pdev->dev, &ssi_private->dev_attr);
|
||||
if (ssi_private->ssi_on_imx)
|
||||
clk_disable_unprepare(ssi_private->clk);
|
||||
|
|
|
@ -66,13 +66,10 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
|
|||
size_t count, loff_t *ppos)
|
||||
{
|
||||
ssize_t ret;
|
||||
char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
char *buf;
|
||||
int port = (int)file->private_data;
|
||||
u32 pdcr, ptcr;
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (audmux_clk) {
|
||||
ret = clk_prepare_enable(audmux_clk);
|
||||
if (ret)
|
||||
|
@ -85,6 +82,10 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
|
|||
if (audmux_clk)
|
||||
clk_disable_unprepare(audmux_clk);
|
||||
|
||||
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
|
||||
pdcr, ptcr);
|
||||
|
||||
|
|
|
@ -160,6 +160,7 @@ static struct platform_driver imx_mc13783_audio_driver = {
|
|||
.driver = {
|
||||
.name = "imx_mc13783",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = imx_mc13783_probe,
|
||||
.remove = imx_mc13783_remove
|
||||
|
|
|
@ -25,12 +25,10 @@
|
|||
|
||||
static bool filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct snd_dmaengine_dai_dma_data *dma_data = param;
|
||||
|
||||
if (!imx_dma_is_general_purpose(chan))
|
||||
return false;
|
||||
|
||||
chan->private = dma_data->filter_data;
|
||||
chan->private = param;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
|
|||
data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
|
||||
data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
|
||||
|
||||
ret = snd_soc_register_card(&data->card);
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
|
||||
goto fail;
|
||||
|
@ -186,7 +186,6 @@ static int imx_sgtl5000_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_card(&data->card);
|
||||
clk_put(data->codec_clk);
|
||||
|
||||
return 0;
|
||||
|
@ -202,6 +201,7 @@ static struct platform_driver imx_sgtl5000_driver = {
|
|||
.driver = {
|
||||
.name = "imx-sgtl5000",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
.of_match_table = imx_sgtl5000_dt_ids,
|
||||
},
|
||||
.probe = imx_sgtl5000_probe,
|
||||
|
|
|
@ -87,7 +87,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto error_dir;
|
||||
|
||||
ret = snd_soc_register_card(&data->card);
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret);
|
||||
goto error_dir;
|
||||
|
@ -119,8 +119,6 @@ static int imx_spdif_audio_remove(struct platform_device *pdev)
|
|||
if (data->txdev)
|
||||
platform_device_unregister(data->txdev);
|
||||
|
||||
snd_soc_unregister_card(&data->card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -613,7 +613,6 @@ static int imx_ssi_probe(struct platform_device *pdev)
|
|||
failed_pcm:
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
failed_register:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
clk_disable_unprepare(ssi->clk);
|
||||
failed_clk:
|
||||
snd_soc_set_ac97_ops(NULL);
|
||||
|
@ -623,7 +622,6 @@ static int imx_ssi_probe(struct platform_device *pdev)
|
|||
|
||||
static int imx_ssi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct imx_ssi *ssi = platform_get_drvdata(pdev);
|
||||
|
||||
if (!ssi->dma_init)
|
||||
|
@ -637,7 +635,6 @@ static int imx_ssi_remove(struct platform_device *pdev)
|
|||
if (ssi->flags & IMX_SSI_USE_AC97)
|
||||
ac97_ssi = NULL;
|
||||
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
clk_disable_unprepare(ssi->clk);
|
||||
snd_soc_set_ac97_ops(NULL);
|
||||
|
||||
|
|
|
@ -266,7 +266,7 @@ static int imx_wm8962_probe(struct platform_device *pdev)
|
|||
data->card.late_probe = imx_wm8962_late_probe;
|
||||
data->card.set_bias_level = imx_wm8962_set_bias_level;
|
||||
|
||||
ret = snd_soc_register_card(&data->card);
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
|
||||
goto clk_fail;
|
||||
|
@ -296,7 +296,6 @@ static int imx_wm8962_remove(struct platform_device *pdev)
|
|||
|
||||
if (!IS_ERR(data->codec_clk))
|
||||
clk_disable_unprepare(data->codec_clk);
|
||||
snd_soc_unregister_card(&data->card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -311,6 +310,7 @@ static struct platform_driver imx_wm8962_driver = {
|
|||
.driver = {
|
||||
.name = "imx-wm8962",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
.of_match_table = imx_wm8962_dt_ids,
|
||||
},
|
||||
.probe = imx_wm8962_probe,
|
||||
|
|
|
@ -27,6 +27,11 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
|
|||
if (!ret && daifmt)
|
||||
ret = snd_soc_dai_set_fmt(dai, daifmt);
|
||||
|
||||
if (ret == -ENOTSUPP) {
|
||||
dev_dbg(dai->dev, "ASoC: set_fmt is not supported\n");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!ret && set->sysclk)
|
||||
ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
|
||||
|
||||
|
|
|
@ -29,9 +29,7 @@
|
|||
#define KIRKWOOD_FORMATS \
|
||||
(SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE | \
|
||||
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \
|
||||
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE)
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
|
||||
{
|
||||
|
@ -161,7 +159,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
|
|||
* Enable Error interrupts. We're only ack'ing them but
|
||||
* it's useful for diagnostics
|
||||
*/
|
||||
writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
|
||||
writel((unsigned int)-1, priv->io + KIRKWOOD_ERR_MASK);
|
||||
}
|
||||
|
||||
dram = mv_mbus_dram_info();
|
||||
|
|
|
@ -103,7 +103,7 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai,
|
|||
{
|
||||
uint32_t clks_ctrl;
|
||||
|
||||
if (rate == 44100 || rate == 48000 || rate == 96000) {
|
||||
if (IS_ERR(priv->extclk)) {
|
||||
/* use internal dco for the supported rates
|
||||
* defined in kirkwood_i2s_dai */
|
||||
dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
|
||||
|
@ -160,9 +160,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
|
|||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
|
||||
ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
|
||||
KIRKWOOD_PLAYCTL_I2S_EN;
|
||||
KIRKWOOD_PLAYCTL_I2S_EN |
|
||||
KIRKWOOD_PLAYCTL_SPDIF_EN;
|
||||
ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
|
||||
KIRKWOOD_RECCTL_I2S_EN;
|
||||
KIRKWOOD_RECCTL_I2S_EN |
|
||||
KIRKWOOD_RECCTL_SPDIF_EN;
|
||||
break;
|
||||
/*
|
||||
* doesn't work... S20_3LE != kirkwood 20bit format ?
|
||||
|
@ -178,9 +180,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
|
|||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
|
||||
ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
|
||||
KIRKWOOD_PLAYCTL_I2S_EN;
|
||||
KIRKWOOD_PLAYCTL_I2S_EN |
|
||||
KIRKWOOD_PLAYCTL_SPDIF_EN;
|
||||
ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
|
||||
KIRKWOOD_RECCTL_I2S_EN;
|
||||
KIRKWOOD_RECCTL_I2S_EN |
|
||||
KIRKWOOD_RECCTL_SPDIF_EN;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
|
||||
|
@ -240,6 +244,11 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
|
|||
ctl);
|
||||
}
|
||||
|
||||
if (dai->id == 0)
|
||||
ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */
|
||||
else
|
||||
ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
/* configure */
|
||||
|
@ -258,7 +267,8 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
|
|||
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
/* stop audio, disable interrupts */
|
||||
ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
|
||||
ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
|
||||
KIRKWOOD_PLAYCTL_SPDIF_MUTE;
|
||||
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
|
||||
|
||||
value = readl(priv->io + KIRKWOOD_INT_MASK);
|
||||
|
@ -272,13 +282,15 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
|
|||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
|
||||
ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
|
||||
KIRKWOOD_PLAYCTL_SPDIF_MUTE;
|
||||
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
|
||||
ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
|
||||
KIRKWOOD_PLAYCTL_SPDIF_MUTE);
|
||||
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
|
||||
break;
|
||||
|
||||
|
@ -301,7 +313,13 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
|
|||
case SNDRV_PCM_TRIGGER_START:
|
||||
/* configure */
|
||||
ctl = priv->ctl_rec;
|
||||
value = ctl & ~KIRKWOOD_RECCTL_I2S_EN;
|
||||
if (dai->id == 0)
|
||||
ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN; /* i2s */
|
||||
else
|
||||
ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */
|
||||
|
||||
value = ctl & ~(KIRKWOOD_RECCTL_I2S_EN |
|
||||
KIRKWOOD_RECCTL_SPDIF_EN);
|
||||
writel(value, priv->io + KIRKWOOD_RECCTL);
|
||||
|
||||
/* enable interrupts */
|
||||
|
@ -361,9 +379,8 @@ static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
|
||||
static int kirkwood_i2s_init(struct kirkwood_dma_data *priv)
|
||||
{
|
||||
struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned long value;
|
||||
unsigned int reg_data;
|
||||
|
||||
|
@ -404,9 +421,10 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
|
|||
.set_fmt = kirkwood_i2s_set_fmt,
|
||||
};
|
||||
|
||||
|
||||
static struct snd_soc_dai_driver kirkwood_i2s_dai = {
|
||||
.probe = kirkwood_i2s_probe,
|
||||
static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = {
|
||||
{
|
||||
.name = "i2s",
|
||||
.id = 0,
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
|
@ -422,10 +440,32 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = {
|
|||
.formats = KIRKWOOD_I2S_FORMATS,
|
||||
},
|
||||
.ops = &kirkwood_i2s_dai_ops,
|
||||
},
|
||||
{
|
||||
.name = "spdif",
|
||||
.id = 1,
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_96000,
|
||||
.formats = KIRKWOOD_I2S_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
|
||||
SNDRV_PCM_RATE_96000,
|
||||
.formats = KIRKWOOD_I2S_FORMATS,
|
||||
},
|
||||
.ops = &kirkwood_i2s_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
|
||||
.probe = kirkwood_i2s_probe,
|
||||
static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = {
|
||||
{
|
||||
.name = "i2s",
|
||||
.id = 0,
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
|
@ -443,6 +483,28 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
|
|||
.formats = KIRKWOOD_I2S_FORMATS,
|
||||
},
|
||||
.ops = &kirkwood_i2s_dai_ops,
|
||||
},
|
||||
{
|
||||
.name = "spdif",
|
||||
.id = 1,
|
||||
.playback = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000 |
|
||||
SNDRV_PCM_RATE_CONTINUOUS |
|
||||
SNDRV_PCM_RATE_KNOT,
|
||||
.formats = KIRKWOOD_I2S_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000 |
|
||||
SNDRV_PCM_RATE_CONTINUOUS |
|
||||
SNDRV_PCM_RATE_KNOT,
|
||||
.formats = KIRKWOOD_I2S_FORMATS,
|
||||
},
|
||||
.ops = &kirkwood_i2s_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver kirkwood_i2s_component = {
|
||||
|
@ -452,7 +514,7 @@ static const struct snd_soc_component_driver kirkwood_i2s_component = {
|
|||
static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
|
||||
struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai;
|
||||
struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai;
|
||||
struct kirkwood_dma_data *priv;
|
||||
struct resource *mem;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
@ -496,7 +558,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
|
|||
return err;
|
||||
|
||||
priv->extclk = devm_clk_get(&pdev->dev, "extclk");
|
||||
if (!IS_ERR(priv->extclk)) {
|
||||
if (IS_ERR(priv->extclk)) {
|
||||
if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
} else {
|
||||
if (priv->extclk == priv->clk) {
|
||||
devm_clk_put(&pdev->dev, priv->extclk);
|
||||
priv->extclk = ERR_PTR(-EINVAL);
|
||||
|
@ -521,7 +586,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
|
||||
soc_dai, 1);
|
||||
soc_dai, 2);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_component failed\n");
|
||||
goto err_component;
|
||||
|
@ -532,6 +597,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "snd_soc_register_platform failed\n");
|
||||
goto err_platform;
|
||||
}
|
||||
|
||||
kirkwood_i2s_init(priv);
|
||||
|
||||
return 0;
|
||||
err_platform:
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
|
|
@ -52,7 +52,7 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
|
|||
{
|
||||
.name = "CS42L51",
|
||||
.stream_name = "CS42L51 HiFi",
|
||||
.cpu_dai_name = "mvebu-audio",
|
||||
.cpu_dai_name = "i2s",
|
||||
.platform_name = "mvebu-audio",
|
||||
.codec_dai_name = "cs42l51-hifi",
|
||||
.codec_name = "cs42l51-codec.0-004a",
|
||||
|
|
|
@ -68,7 +68,7 @@ static struct snd_soc_dai_link t5325_dai[] = {
|
|||
{
|
||||
.name = "ALC5621",
|
||||
.stream_name = "ALC5621 HiFi",
|
||||
.cpu_dai_name = "mvebu-audio",
|
||||
.cpu_dai_name = "i2s",
|
||||
.platform_name = "mvebu-audio",
|
||||
.codec_dai_name = "alc5621-hifi",
|
||||
.codec_name = "alc562x-codec.0-001a",
|
||||
|
|
|
@ -123,8 +123,8 @@
|
|||
/* need to find where they come from */
|
||||
#define KIRKWOOD_SND_MIN_PERIODS 8
|
||||
#define KIRKWOOD_SND_MAX_PERIODS 16
|
||||
#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000
|
||||
#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000
|
||||
#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x800
|
||||
#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x8000
|
||||
#define KIRKWOOD_SND_MAX_BUFFER_BYTES (KIRKWOOD_SND_MAX_PERIOD_BYTES \
|
||||
* KIRKWOOD_SND_MAX_PERIODS)
|
||||
|
||||
|
|
|
@ -400,7 +400,7 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
|
|||
}
|
||||
/* register the soc card */
|
||||
snd_soc_card_mfld.dev = &pdev->dev;
|
||||
ret_val = snd_soc_register_card(&snd_soc_card_mfld);
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld);
|
||||
if (ret_val) {
|
||||
pr_debug("snd_soc_register_card failed %d\n", ret_val);
|
||||
return ret_val;
|
||||
|
@ -410,20 +410,12 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_mfld_mc_remove(struct platform_device *pdev)
|
||||
{
|
||||
pr_debug("snd_mfld_mc_remove called\n");
|
||||
snd_soc_unregister_card(&snd_soc_card_mfld);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver snd_mfld_mc_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "msic_audio",
|
||||
},
|
||||
.probe = snd_mfld_mc_probe,
|
||||
.remove = snd_mfld_mc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(snd_mfld_mc_driver);
|
||||
|
|
|
@ -494,6 +494,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct mxs_saif *master_saif;
|
||||
u32 delay;
|
||||
int ret;
|
||||
|
||||
master_saif = mxs_saif_get_master(saif);
|
||||
if (!master_saif)
|
||||
|
@ -503,23 +504,37 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (saif->state == MXS_SAIF_STATE_RUNNING)
|
||||
return 0;
|
||||
|
||||
dev_dbg(cpu_dai->dev, "start\n");
|
||||
|
||||
clk_enable(master_saif->clk);
|
||||
if (!master_saif->mclk_in_use)
|
||||
__raw_writel(BM_SAIF_CTRL_RUN,
|
||||
master_saif->base + SAIF_CTRL + MXS_SET_ADDR);
|
||||
ret = clk_enable(master_saif->clk);
|
||||
if (ret) {
|
||||
dev_err(saif->dev, "Failed to enable master clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the saif's master is not himself, we also need to enable
|
||||
* itself clk for its internal basic logic to work.
|
||||
*/
|
||||
if (saif != master_saif) {
|
||||
clk_enable(saif->clk);
|
||||
ret = clk_enable(saif->clk);
|
||||
if (ret) {
|
||||
dev_err(saif->dev, "Failed to enable master clock\n");
|
||||
clk_disable(master_saif->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__raw_writel(BM_SAIF_CTRL_RUN,
|
||||
saif->base + SAIF_CTRL + MXS_SET_ADDR);
|
||||
}
|
||||
|
||||
if (!master_saif->mclk_in_use)
|
||||
__raw_writel(BM_SAIF_CTRL_RUN,
|
||||
master_saif->base + SAIF_CTRL + MXS_SET_ADDR);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
/*
|
||||
* write data to saif data register to trigger
|
||||
|
@ -543,6 +558,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
}
|
||||
|
||||
master_saif->ongoing = 1;
|
||||
saif->state = MXS_SAIF_STATE_RUNNING;
|
||||
|
||||
dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n",
|
||||
__raw_readl(saif->base + SAIF_CTRL),
|
||||
|
@ -555,6 +571,9 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (saif->state == MXS_SAIF_STATE_STOPPED)
|
||||
return 0;
|
||||
|
||||
dev_dbg(cpu_dai->dev, "stop\n");
|
||||
|
||||
/* wait a while for the current sample to complete */
|
||||
|
@ -575,6 +594,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
}
|
||||
|
||||
master_saif->ongoing = 0;
|
||||
saif->state = MXS_SAIF_STATE_STOPPED;
|
||||
|
||||
break;
|
||||
default:
|
||||
|
@ -768,8 +788,8 @@ static int mxs_saif_probe(struct platform_device *pdev)
|
|||
dev_warn(&pdev->dev, "failed to init clocks\n");
|
||||
}
|
||||
|
||||
ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
|
||||
&mxs_saif_dai, 1);
|
||||
ret = devm_snd_soc_register_component(&pdev->dev, &mxs_saif_component,
|
||||
&mxs_saif_dai, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register DAI failed\n");
|
||||
return ret;
|
||||
|
@ -778,21 +798,15 @@ static int mxs_saif_probe(struct platform_device *pdev)
|
|||
ret = mxs_pcm_platform_register(&pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
|
||||
goto failed_pdev_alloc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed_pdev_alloc:
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxs_saif_remove(struct platform_device *pdev)
|
||||
{
|
||||
mxs_pcm_platform_unregister(&pdev->dev);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -124,6 +124,11 @@ struct mxs_saif {
|
|||
|
||||
u32 fifo_underrun;
|
||||
u32 fifo_overrun;
|
||||
|
||||
enum {
|
||||
MXS_SAIF_STATE_STOPPED,
|
||||
MXS_SAIF_STATE_RUNNING,
|
||||
} state;
|
||||
};
|
||||
|
||||
extern int mxs_saif_put_mclk(unsigned int saif_id);
|
||||
|
|
|
@ -122,14 +122,12 @@ static struct snd_soc_card mxs_sgtl5000 = {
|
|||
.num_links = ARRAY_SIZE(mxs_sgtl5000_dai),
|
||||
};
|
||||
|
||||
static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
|
||||
static int mxs_sgtl5000_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &mxs_sgtl5000;
|
||||
int ret, i;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *saif_np[2], *codec_np;
|
||||
int i;
|
||||
|
||||
if (!np)
|
||||
return 1; /* no device tree */
|
||||
|
||||
saif_np[0] = of_parse_phandle(np, "saif-controllers", 0);
|
||||
saif_np[1] = of_parse_phandle(np, "saif-controllers", 1);
|
||||
|
@ -152,18 +150,6 @@ static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
|
|||
of_node_put(saif_np[0]);
|
||||
of_node_put(saif_np[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxs_sgtl5000_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &mxs_sgtl5000;
|
||||
int ret;
|
||||
|
||||
ret = mxs_sgtl5000_probe_dt(pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w).
|
||||
* The Sgtl5000 sysclk is derived from saif0 mclk and it's range
|
||||
|
|
|
@ -490,14 +490,9 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
|
|||
|
||||
mcpdm->dev = &pdev->dev;
|
||||
|
||||
return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component,
|
||||
&omap_mcpdm_dai, 1);
|
||||
}
|
||||
|
||||
static int asoc_mcpdm_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
return 0;
|
||||
return devm_snd_soc_register_component(&pdev->dev,
|
||||
&omap_mcpdm_component,
|
||||
&omap_mcpdm_dai, 1);
|
||||
}
|
||||
|
||||
static const struct of_device_id omap_mcpdm_of_match[] = {
|
||||
|
@ -514,7 +509,6 @@ static struct platform_driver asoc_mcpdm_driver = {
|
|||
},
|
||||
|
||||
.probe = asoc_mcpdm_probe,
|
||||
.remove = asoc_mcpdm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(asoc_mcpdm_driver);
|
||||
|
|
|
@ -338,9 +338,9 @@ static int omap_twl4030_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
snd_soc_card_set_drvdata(card, priv);
|
||||
ret = snd_soc_register_card(card);
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
|
||||
dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -357,7 +357,6 @@ static int omap_twl4030_remove(struct platform_device *pdev)
|
|||
snd_soc_jack_free_gpios(&priv->hs_jack,
|
||||
ARRAY_SIZE(hs_jack_gpios),
|
||||
hs_jack_gpios);
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -163,6 +163,7 @@ static struct platform_driver mmp_driver = {
|
|||
.driver = {
|
||||
.name = "brownstone-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = brownstone_probe,
|
||||
.remove = brownstone_remove,
|
||||
|
|
|
@ -329,6 +329,7 @@ static struct platform_driver corgi_driver = {
|
|||
.driver = {
|
||||
.name = "corgi-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = corgi_probe,
|
||||
.remove = corgi_remove,
|
||||
|
|
|
@ -178,6 +178,7 @@ static struct platform_driver e740_driver = {
|
|||
.driver = {
|
||||
.name = "e740-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = e740_probe,
|
||||
.remove = e740_remove,
|
||||
|
|
|
@ -160,6 +160,7 @@ static struct platform_driver e750_driver = {
|
|||
.driver = {
|
||||
.name = "e750-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = e750_probe,
|
||||
.remove = e750_remove,
|
||||
|
|
|
@ -150,6 +150,7 @@ static struct platform_driver e800_driver = {
|
|||
.driver = {
|
||||
.name = "e800-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = e800_probe,
|
||||
.remove = e800_remove,
|
||||
|
|
|
@ -91,6 +91,7 @@ static struct platform_driver imote2_driver = {
|
|||
.driver = {
|
||||
.name = "imote2-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = imote2_probe,
|
||||
.remove = imote2_remove,
|
||||
|
|
|
@ -215,6 +215,7 @@ static struct platform_driver mioa701_wm9713_driver = {
|
|||
.driver = {
|
||||
.name = "mioa701-wm9713",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -455,8 +455,8 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev)
|
|||
priv->dai_fmt = (unsigned int) -1;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
|
||||
&mmp_sspa_dai, 1);
|
||||
return devm_snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
|
||||
&mmp_sspa_dai, 1);
|
||||
}
|
||||
|
||||
static int asoc_mmp_sspa_remove(struct platform_device *pdev)
|
||||
|
@ -466,7 +466,6 @@ static int asoc_mmp_sspa_remove(struct platform_device *pdev)
|
|||
clk_disable(priv->audio_clk);
|
||||
clk_put(priv->audio_clk);
|
||||
clk_put(priv->sysclk);
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -181,6 +181,7 @@ static struct platform_driver palm27x_wm9712_driver = {
|
|||
.driver = {
|
||||
.name = "palm27x-asoc",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -303,6 +303,7 @@ static struct platform_driver poodle_driver = {
|
|||
.driver = {
|
||||
.name = "poodle-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = poodle_probe,
|
||||
.remove = poodle_remove,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue