Merge remote-tracking branch 'asoc/fix/ab8500' into asoc-linus

This commit is contained in:
Mark Brown 2013-11-20 15:20:24 +00:00
commit 8b880f48ee
130 changed files with 4175 additions and 3001 deletions

View File

@ -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>;
};

View File

@ -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";
};

View File

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

View File

@ -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 = <&regulator>;
IOVDD-supply = <&regulator>;
DRVDD-supply = <&regulator>;
DVDD-supply = <&regulator>;
};

View File

@ -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>;
};

View File

@ -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(&params->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.

View File

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

View File

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

View File

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

View File

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

View File

@ -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);

View File

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

View File

@ -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),
&reg_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);
}

View File

@ -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);

View File

@ -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);
}

View File

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

View File

@ -84,6 +84,8 @@ struct snd_platform_data {
u8 version;
u8 txnumevt;
u8 rxnumevt;
int tx_dma_channel;
int rx_dma_channel;
};
enum {

View File

@ -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");

22
include/sound/cs42l73.h Normal file
View File

@ -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 */

View File

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

View File

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

View File

@ -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)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

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

View File

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

View File

@ -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++) {

View File

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

View File

@ -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);

View File

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

View File

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

View File

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

View File

@ -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);

View File

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

View File

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

View File

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

View File

@ -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, &reg);
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, &reg);
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,

View File

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

View File

@ -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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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));
}

View File

@ -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);

View File

@ -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>");

View File

@ -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);

View File

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

View File

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

View File

@ -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;
}

View File

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

View File

@ -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 */

View File

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

View File

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

View File

@ -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);

View File

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

View File

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

View File

@ -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);
}

View File

@ -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");

View File

@ -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 */

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

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

View File

@ -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;
}

View File

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

View File

@ -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;
}

View File

@ -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);

View File

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

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

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

View File

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

View File

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

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

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

View File

@ -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);

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -215,6 +215,7 @@ static struct platform_driver mioa701_wm9713_driver = {
.driver = {
.name = "mioa701-wm9713",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
},
};

View File

@ -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;
}

View File

@ -181,6 +181,7 @@ static struct platform_driver palm27x_wm9712_driver = {
.driver = {
.name = "palm27x-asoc",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
},
};

View File

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