ASoC: Updates for v4.2

The big thing this release has been Liam's addition of topology support
 to the core.  We've also seen quite a bit of driver work and the
 continuation of Lars' refactoring for component support.
 
  - Support for loading ASoC topology maps from firmware, intended to be
    used to allow self-describing DSP firmware images to be built which
    can map controls added by the DSP to userspace without the kernel
    needing to know about individual DSP firmwares.
  - Lots of refactoring to avoid direct access to snd_soc_codec where
    it's not needed supporting future refactoring.
  - Big refactoring and cleanup serieses for the Wolfson ADSP and TI
    TAS2552 drivers.
  - Support for TI TAS571x power amplifiers.
  - Support for Qualcomm APQ8016 and ZTE ZX296702 SoCs.
  - Support for x86 systems with RT5650 and Qualcomm Storm.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJVddV1AAoJECTWi3JdVIfQQQsH/RG3lgOeot5jLWMsxJSKChEl
 KI+aaMcOw6Dj2LDccN8i6vUp8q44cKSXIc7lGLOzJW4K+OydCCGAvE+sJGyRE1dd
 yOHwcbvjJi4zFlt01RZchJ/Wa/S6zFucl5N9HxWsV4bEtfAA59IuhJLtospUlwsA
 mf9mpvSdeUAeh3lM2+AqAbXhTo6dYfD5ky5nrtpAkZjG8gqUG0u8Tpauja0lLcHi
 72/3EkzKR6KHaefyPw3LdN+/H/YK79uHCVcctZnQg5xUUymcO16ReoTxKwV9cnDb
 lBJ6wO8RpUAO9evoG2Yj/l4p+czDCm5VkHMq0nPklHVRh7s/2PwKfox1aw4Pumg=
 =wolq
 -----END PGP SIGNATURE-----

Merge tag 'asoc-v4.2' into asoc-next

ASoC: Updates for v4.2

The big thing this release has been Liam's addition of topology support
to the core.  We've also seen quite a bit of driver work and the
continuation of Lars' refactoring for component support.

 - Support for loading ASoC topology maps from firmware, intended to be
   used to allow self-describing DSP firmware images to be built which
   can map controls added by the DSP to userspace without the kernel
   needing to know about individual DSP firmwares.
 - Lots of refactoring to avoid direct access to snd_soc_codec where
   it's not needed supporting future refactoring.
 - Big refactoring and cleanup serieses for the Wolfson ADSP and TI
   TAS2552 drivers.
 - Support for TI TAS571x power amplifiers.
 - Support for Qualcomm APQ8016 and ZTE ZX296702 SoCs.
 - Support for x86 systems with RT5650 and Qualcomm Storm.

# gpg: Signature made Mon 08 Jun 2015 18:48:37 BST using RSA key ID 5D5487D0
# gpg: Oops: keyid_from_fingerprint: no pubkey
# gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>"
# gpg:                 aka "Mark Brown <broonie@debian.org>"
# gpg:                 aka "Mark Brown <broonie@kernel.org>"
# gpg:                 aka "Mark Brown <broonie@tardis.ed.ac.uk>"
# gpg:                 aka "Mark Brown <broonie@linaro.org>"
# gpg:                 aka "Mark Brown <Mark.Brown@linaro.org>"
This commit is contained in:
Mark Brown 2015-06-22 11:19:31 +01:00
commit 89fc594ba5
222 changed files with 9466 additions and 2318 deletions

View File

@ -20,6 +20,8 @@ Optional properties:
pin configurations as described in the datasheet,
table 53. Note that the value of this property has
to be prefixed with '/bits/ 8'.
- avdd-supply: Power supply for AVDD, providing 3.3V
- dvdd-supply: Power supply for DVDD, providing 3.3V
Examples:
@ -28,6 +30,8 @@ Examples:
compatible = "adi,adau1701";
reg = <0x34>;
reset-gpio = <&gpio 23 0>;
avdd-supply = <&vdd_3v3_reg>;
dvdd-supply = <&vdd_3v3_reg>;
adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4
0x4 0x4 0x4 0x4 0x4 0x4>;

View File

@ -0,0 +1,13 @@
Bluetooth-SCO audio CODEC
This device support generic Bluetooth SCO link.
Required properties:
- compatible : "delta,dfbmcs320"
Example:
codec: bt_sco {
compatible = "delta,dfbmcs320";
};

View File

@ -0,0 +1,13 @@
GTM601 UMTS modem audio interface CODEC
This device has no configuration interface. Sample rate is fixed - 8kHz.
Required properties:
- compatible : "option,gtm601"
Example:
codec: gtm601_codec {
compatible = "option,gtm601";
};

View File

@ -18,6 +18,12 @@ Optional properties:
- maxim,dmic-freq: Frequency at which to clock DMIC
- maxim,micbias: Micbias voltage applies to the analog mic, valid voltages value are:
0 - 2.2v
1 - 2.55v
2 - 2.4v
3 - 2.8v
Pins on the device (for linking into audio routes):
* MIC1

View File

@ -4,12 +4,21 @@ This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
Required properties:
- compatible : "qcom,lpass-cpu"
- compatible : "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"
- clocks : Must contain an entry for each entry in clock-names.
- clock-names : A list which must include the following entries:
* "ahbix-clk"
* "mi2s-osr-clk"
* "mi2s-bit-clk"
: required clocks for "qcom,lpass-cpu-apq8016"
* "ahbix-clk"
* "mi2s-bit-clk0"
* "mi2s-bit-clk1"
* "mi2s-bit-clk2"
* "mi2s-bit-clk3"
* "pcnoc-mport-clk"
* "pcnoc-sway-clk"
- interrupts : Must contain an entry for each entry in
interrupt-names.
- interrupt-names : A list which must include the following entries:
@ -22,6 +31,8 @@ Required properties:
- reg-names : A list which must include the following entries:
* "lpass-lpaif"
Optional properties:
- qcom,adsp : Phandle for the audio DSP node

View File

@ -48,7 +48,7 @@ DAI subnode properties:
Example:
rcar_sound: rcar_sound@ec500000 {
rcar_sound: sound@ec500000 {
#sound-dai-cells = <1>;
compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
reg = <0 0xec500000 0 0x1000>, /* SCU */

View File

@ -18,6 +18,7 @@ Required properties:
Optional properties:
- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin.
- realtek,in1-differential
- realtek,in2-differential
@ -70,6 +71,7 @@ rt5677 {
realtek,pow-ldo2-gpio =
<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
realtek,reset-gpio = <&gpio TEGRA_GPIO(BB, 3) GPIO_ACTIVE_LOW>;
realtek,in1-differential = "true";
realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */
realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */

View File

@ -0,0 +1,41 @@
Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers
The codec is controlled through an I2C interface. It also has two other
signals that can be wired up to GPIOs: reset (strongly recommended), and
powerdown (optional).
Required properties:
- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719"
- reg: The I2C address of the device
- #sound-dai-cells: must be equal to 0
Optional properties:
- reset-gpios: GPIO specifier for the TAS571x's active low reset line
- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line
- clocks: clock phandle for the MCLK input
- clock-names: should be "mclk"
- AVDD-supply: regulator phandle for the AVDD supply (all chips)
- DVDD-supply: regulator phandle for the DVDD supply (all chips)
- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719)
- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719)
- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719)
- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711)
- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711)
- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711)
- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711)
Example:
tas5717: audio-codec@2a {
compatible = "ti,tas5717";
reg = <0x2a>;
#sound-dai-cells = <0>;
reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
pdn-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
clocks = <&clk_core CLK_I2S>;
clock-names = "mclk";
};

View File

@ -10,9 +10,20 @@ Required properties:
- reg : the I2C address of the device for I2C, the chip select
number for SPI.
Optional properties:
- diff-mode: Differential output mode configuration. Default value for field
DIFF in register R8 (MODE_CONTROL_2). If absent, the default is 0, shall be:
0 = stereo
1 = mono left
2 = stereo reversed
3 = mono right
Example:
codec: wm8741@1a {
compatible = "wlf,wm8741";
reg = <0x1a>;
diff-mode = <3>;
};

View File

@ -0,0 +1,44 @@
ZTE ZX296702 I2S controller
Required properties:
- compatible : Must be "zte,zx296702-i2s"
- reg : Must contain I2S core's registers location and length
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
- clock-names: "tx" for the clock to the I2S interface.
- dmas: Pairs of phandle and specifier for the DMA channel that is used by
the core. The core expects two dma channels for transmit.
- dma-names : Must be "tx" and "rx"
For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
please check:
* resource-names.txt
* clock/clock-bindings.txt
* dma/dma.txt
Example:
i2s0: i2s0@0b005000 {
#sound-dai-cells = <0>;
compatible = "zte,zx296702-i2s";
reg = <0x0b005000 0x1000>;
clocks = <&lsp0clk ZX296702_I2S0_DIV>;
clock-names = "tx";
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma 5>, <&dma 6>;
dma-names = "tx", "rx";
status = "okay";
};
sound {
compatible = "simple-audio-card";
simple-audio-card,name = "zx296702_snd";
simple-audio-card,format = "left_j";
simple-audio-card,bitclock-master = <&sndcodec>;
simple-audio-card,frame-master = <&sndcodec>;
sndcpu: simple-audio-card,cpu {
sound-dai = <&i2s0>;
};
sndcodec: simple-audio-card,codec {
sound-dai = <&acodec>;
};
};

View File

@ -0,0 +1,28 @@
ZTE ZX296702 SPDIF controller
Required properties:
- compatible : Must be "zte,zx296702-spdif"
- reg : Must contain SPDIF core's registers location and length
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
- clock-names: "tx" for the clock to the SPDIF interface.
- dmas: Pairs of phandle and specifier for the DMA channel that is used by
the core. The core expects one dma channel for transmit.
- dma-names : Must be "tx"
For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
please check:
* resource-names.txt
* clock/clock-bindings.txt
* dma/dma.txt
Example:
spdif0: spdif0@0b004000 {
compatible = "zte,zx296702-spdif";
reg = <0x0b004000 0x1000>;
clocks = <&lsp0clk ZX296702_SPDIF0_DIV>;
clock-names = "tx";
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&dma 4>;
dma-names = "tx";
status = "okay";
};

View File

@ -54,6 +54,7 @@ cosmic Cosmic Circuits
crystalfontz Crystalfontz America, Inc.
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
davicom DAVICOM Semiconductor, Inc.
delta Delta Electronics, Inc.
denx Denx Software Engineering
digi Digi International Inc.
digilent Diglent, Inc.

View File

@ -9924,6 +9924,12 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/ti/netcp*
TI TAS571X FAMILY ASoC CODEC DRIVER
M: Kevin Cernekee <cernekee@chromium.org>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Odd Fixes
F: sound/soc/codecs/tas571x*
TI TWL4030 SERIES SOC CODEC DRIVER
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)

View File

@ -465,6 +465,7 @@ static dma_cookie_t rcar_dmac_tx_submit(struct dma_async_tx_descriptor *tx)
static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
{
struct rcar_dmac_desc_page *page;
unsigned long flags;
LIST_HEAD(list);
unsigned int i;
@ -482,10 +483,10 @@ static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
list_add_tail(&desc->node, &list);
}
spin_lock_irq(&chan->lock);
spin_lock_irqsave(&chan->lock, flags);
list_splice_tail(&list, &chan->desc.free);
list_add_tail(&page->node, &chan->desc.pages);
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags);
return 0;
}
@ -516,6 +517,7 @@ static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
{
struct rcar_dmac_desc *desc, *_desc;
unsigned long flags;
LIST_HEAD(list);
/*
@ -524,9 +526,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
* list_for_each_entry_safe, isn't safe if we release the channel lock
* around the rcar_dmac_desc_put() call.
*/
spin_lock_irq(&chan->lock);
spin_lock_irqsave(&chan->lock, flags);
list_splice_init(&chan->desc.wait, &list);
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags);
list_for_each_entry_safe(desc, _desc, &list, node) {
if (async_tx_test_ack(&desc->async_tx)) {
@ -539,9 +541,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
return;
/* Put the remaining descriptors back in the wait list. */
spin_lock_irq(&chan->lock);
spin_lock_irqsave(&chan->lock, flags);
list_splice(&list, &chan->desc.wait);
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags);
}
/*
@ -556,12 +558,13 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
{
struct rcar_dmac_desc *desc;
unsigned long flags;
int ret;
/* Recycle acked descriptors before attempting allocation. */
rcar_dmac_desc_recycle_acked(chan);
spin_lock_irq(&chan->lock);
spin_lock_irqsave(&chan->lock, flags);
while (list_empty(&chan->desc.free)) {
/*
@ -570,17 +573,17 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
* allocated descriptors. If the allocation fails return an
* error.
*/
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags);
ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT);
if (ret < 0)
return NULL;
spin_lock_irq(&chan->lock);
spin_lock_irqsave(&chan->lock, flags);
}
desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node);
list_del(&desc->node);
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags);
return desc;
}
@ -593,6 +596,7 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
{
struct rcar_dmac_desc_page *page;
unsigned long flags;
LIST_HEAD(list);
unsigned int i;
@ -606,10 +610,10 @@ static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
list_add_tail(&chunk->node, &list);
}
spin_lock_irq(&chan->lock);
spin_lock_irqsave(&chan->lock, flags);
list_splice_tail(&list, &chan->desc.chunks_free);
list_add_tail(&page->node, &chan->desc.pages);
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags);
return 0;
}
@ -627,9 +631,10 @@ static struct rcar_dmac_xfer_chunk *
rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
{
struct rcar_dmac_xfer_chunk *chunk;
unsigned long flags;
int ret;
spin_lock_irq(&chan->lock);
spin_lock_irqsave(&chan->lock, flags);
while (list_empty(&chan->desc.chunks_free)) {
/*
@ -638,18 +643,18 @@ rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
* allocated descriptors. If the allocation fails return an
* error.
*/
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags);
ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT);
if (ret < 0)
return NULL;
spin_lock_irq(&chan->lock);
spin_lock_irqsave(&chan->lock, flags);
}
chunk = list_first_entry(&chan->desc.chunks_free,
struct rcar_dmac_xfer_chunk, node);
list_del(&chunk->node);
spin_unlock_irq(&chan->lock);
spin_unlock_irqrestore(&chan->lock, flags);
return chunk;
}

View File

@ -78,11 +78,6 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
if (ret != 0)
return ret;
ret = regmap_update_bits(regmap, ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
ARIZONA_SUBSYS_MAX_FREQ, val);
if (ret != 0)
return ret;
if (val)
return 0;

View File

@ -0,0 +1,9 @@
#ifndef __DT_APQ8016_LPASS_H
#define __DT_APQ8016_LPASS_H
#define MI2S_PRIMARY 0
#define MI2S_SECONDARY 1
#define MI2S_TERTIARY 2
#define MI2S_QUATERNARY 3
#endif /* __DT_APQ8016_LPASS_H */

View File

@ -0,0 +1,9 @@
#ifndef __AUDIO_JACK_EVENTS_H
#define __AUDIO_JACK_EVENTS_H
#define JACK_HEADPHONE 1
#define JACK_MICROPHONE 2
#define JACK_LINEOUT 3
#define JACK_LINEIN 4
#endif /* __AUDIO_JACK_EVENTS_H */

View File

@ -0,0 +1,18 @@
#ifndef __DT_TAS2552_H
#define __DT_TAS2552_H
#define TAS2552_PLL_CLKIN (0)
#define TAS2552_PDM_CLK (1)
#define TAS2552_CLK_TARGET_MASK (1)
#define TAS2552_PLL_CLKIN_MCLK ((0 << 1) | TAS2552_PLL_CLKIN)
#define TAS2552_PLL_CLKIN_BCLK ((1 << 1) | TAS2552_PLL_CLKIN)
#define TAS2552_PLL_CLKIN_IVCLKIN ((2 << 1) | TAS2552_PLL_CLKIN)
#define TAS2552_PLL_CLKIN_1_8_FIXED ((3 << 1) | TAS2552_PLL_CLKIN)
#define TAS2552_PDM_CLK_PLL ((0 << 1) | TAS2552_PDM_CLK)
#define TAS2552_PDM_CLK_IVCLKIN ((1 << 1) | TAS2552_PDM_CLK)
#define TAS2552_PDM_CLK_BCLK ((2 << 1) | TAS2552_PDM_CLK)
#define TAS2552_PDM_CLK_MCLK ((3 << 1) | TAS2552_PDM_CLK)
#endif /* __DT_TAS2552_H */

View File

@ -90,11 +90,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
* makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well.
*/
#define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1)
/*
* The platforms dmaengine driver does not support reporting the amount of
* bytes that are still left to transfer.
*/
#define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2)
/*
* The PCM is half duplex and the DMA channel is shared between capture and
* playback.

View File

@ -15,7 +15,6 @@ struct rt5645_platform_data {
/* IN2 can optionally be differential */
bool in2_diff;
bool dmic_en;
unsigned int dmic1_data_pin;
/* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */
unsigned int dmic2_data_pin;
@ -24,8 +23,6 @@ struct rt5645_platform_data {
unsigned int hp_det_gpio;
bool gpio_hp_det_active_high;
/* true if codec's jd function is used */
bool en_jd_func;
unsigned int jd_mode;
};

View File

@ -15,6 +15,8 @@
#include <linux/types.h>
#include <sound/control.h>
#include <sound/soc-topology.h>
#include <sound/asoc.h>
struct device;
@ -107,6 +109,10 @@ struct device;
{ .id = snd_soc_dapm_mux, .name = wname, \
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_demux, .name = wname, \
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = 1}
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
@ -444,11 +450,15 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
struct snd_kcontrol *kcontrol);
int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level);
/* dapm widget types */
enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */
snd_soc_dapm_output, /* output pin */
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
snd_soc_dapm_demux, /* connects the input to one of multiple outputs */
snd_soc_dapm_mixer, /* mixes several analog signals together */
snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
@ -563,6 +573,7 @@ struct snd_soc_dapm_widget {
int num_kcontrols;
const struct snd_kcontrol_new *kcontrol_news;
struct snd_kcontrol **kcontrols;
struct snd_soc_dobj dobj;
/* widget input and outputs */
struct list_head sources;
@ -585,6 +596,10 @@ struct snd_soc_dapm_update {
int val;
};
struct snd_soc_dapm_wcache {
struct snd_soc_dapm_widget *widget;
};
/* DAPM context */
struct snd_soc_dapm_context {
enum snd_soc_bias_level bias_level;
@ -606,6 +621,9 @@ struct snd_soc_dapm_context {
int (*set_bias_level)(struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level);
struct snd_soc_dapm_wcache path_sink_cache;
struct snd_soc_dapm_wcache path_source_cache;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dapm;
#endif
@ -623,4 +641,35 @@ struct snd_soc_dapm_stats {
int neighbour_checks;
};
/**
* snd_soc_dapm_init_bias_level() - Initialize DAPM bias level
* @dapm: The DAPM context to initialize
* @level: The DAPM level to initialize to
*
* This function only sets the driver internal state of the DAPM level and will
* not modify the state of the device. Hence it should not be used during normal
* operation, but only to synchronize the internal state to the device state.
* E.g. during driver probe to set the DAPM level to the one corresponding with
* the power-on reset state of the device.
*
* To change the DAPM state of the device use snd_soc_dapm_set_bias_level().
*/
static inline void snd_soc_dapm_init_bias_level(
struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
{
dapm->bias_level = level;
}
/**
* snd_soc_dapm_get_bias_level() - Get current DAPM bias level
* @dapm: The context for which to get the bias level
*
* Returns: The current bias level of the passed DAPM context.
*/
static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
struct snd_soc_dapm_context *dapm)
{
return dapm->bias_level;
}
#endif

View File

@ -0,0 +1,168 @@
/*
* linux/sound/soc-topology.h -- ALSA SoC Firmware Controls and DAPM
*
* Copyright (C) 2012 Texas Instruments Inc.
* Copyright (C) 2015 Intel Corporation.
*
* 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.
*
* Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
* algorithms, equalisers, DAIs, widgets, FE caps, BE caps, codec link caps etc.
*/
#ifndef __LINUX_SND_SOC_TPLG_H
#define __LINUX_SND_SOC_TPLG_H
#include <sound/asoc.h>
#include <linux/list.h>
struct firmware;
struct snd_kcontrol;
struct snd_soc_tplg_pcm_be;
struct snd_ctl_elem_value;
struct snd_ctl_elem_info;
struct snd_soc_dapm_widget;
struct snd_soc_component;
struct snd_soc_tplg_pcm_fe;
struct snd_soc_dapm_context;
struct snd_soc_card;
/* object scan be loaded and unloaded in groups with identfying indexes */
#define SND_SOC_TPLG_INDEX_ALL 0 /* ID that matches all FW objects */
/* dynamic object type */
enum snd_soc_dobj_type {
SND_SOC_DOBJ_NONE = 0, /* object is not dynamic */
SND_SOC_DOBJ_MIXER,
SND_SOC_DOBJ_ENUM,
SND_SOC_DOBJ_BYTES,
SND_SOC_DOBJ_PCM,
SND_SOC_DOBJ_DAI_LINK,
SND_SOC_DOBJ_CODEC_LINK,
SND_SOC_DOBJ_WIDGET,
};
/* dynamic control object */
struct snd_soc_dobj_control {
struct snd_kcontrol *kcontrol;
char **dtexts;
unsigned long *dvalues;
};
/* dynamic widget object */
struct snd_soc_dobj_widget {
unsigned int kcontrol_enum:1; /* this widget is an enum kcontrol */
};
/* dynamic PCM DAI object */
struct snd_soc_dobj_pcm_dai {
struct snd_soc_tplg_pcm_dai *pd;
unsigned int count;
};
/* generic dynamic object - all dynamic objects belong to this struct */
struct snd_soc_dobj {
enum snd_soc_dobj_type type;
unsigned int index; /* objects can belong in different groups */
struct list_head list;
struct snd_soc_tplg_ops *ops;
union {
struct snd_soc_dobj_control control;
struct snd_soc_dobj_widget widget;
struct snd_soc_dobj_pcm_dai pcm_dai;
};
void *private; /* core does not touch this */
};
/*
* Kcontrol operations - used to map handlers onto firmware based controls.
*/
struct snd_soc_tplg_kcontrol_ops {
u32 id;
int (*get)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int (*put)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int (*info)(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
};
/*
* DAPM widget event handlers - used to map handlers onto widgets.
*/
struct snd_soc_tplg_widget_events {
u16 type;
int (*event_handler)(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event);
};
/*
* Public API - Used by component drivers to load and unload dynamic objects
* and their resources.
*/
struct snd_soc_tplg_ops {
/* external kcontrol init - used for any driver specific init */
int (*control_load)(struct snd_soc_component *,
struct snd_kcontrol_new *, struct snd_soc_tplg_ctl_hdr *);
int (*control_unload)(struct snd_soc_component *,
struct snd_soc_dobj *);
/* external widget init - used for any driver specific init */
int (*widget_load)(struct snd_soc_component *,
struct snd_soc_dapm_widget *,
struct snd_soc_tplg_dapm_widget *);
int (*widget_unload)(struct snd_soc_component *,
struct snd_soc_dobj *);
/* FE - used for any driver specific init */
int (*pcm_dai_load)(struct snd_soc_component *,
struct snd_soc_tplg_pcm_dai *pcm_dai, int num_fe);
int (*pcm_dai_unload)(struct snd_soc_component *,
struct snd_soc_dobj *);
/* callback to handle vendor bespoke data */
int (*vendor_load)(struct snd_soc_component *,
struct snd_soc_tplg_hdr *);
int (*vendor_unload)(struct snd_soc_component *,
struct snd_soc_tplg_hdr *);
/* completion - called at completion of firmware loading */
void (*complete)(struct snd_soc_component *);
/* manifest - optional to inform component of manifest */
int (*manifest)(struct snd_soc_component *,
struct snd_soc_tplg_manifest *);
/* bespoke kcontrol handlers available for binding */
const struct snd_soc_tplg_kcontrol_ops *io_ops;
int io_ops_count;
};
/* gets a pointer to data from the firmware block header */
static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr)
{
const void *ptr = hdr;
return ptr + sizeof(*hdr);
}
/* Dynamic Object loading and removal for component drivers */
int snd_soc_tplg_component_load(struct snd_soc_component *comp,
struct snd_soc_tplg_ops *ops, const struct firmware *fw,
u32 index);
int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index);
/* Widget removal - widgets also removed wth component API */
void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w);
void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
u32 index);
/* Binds event handlers to dynamic widgets */
int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
const struct snd_soc_tplg_widget_events *events, int num_events,
u16 event_type);
#endif

View File

@ -27,6 +27,7 @@
#include <sound/compress_driver.h>
#include <sound/control.h>
#include <sound/ac97_codec.h>
#include <sound/soc-topology.h>
/*
* Convenience kcontrol builders
@ -190,8 +191,12 @@
#define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xitems, xtexts, xvalues) \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
.mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues}
#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xnitmes, xtexts, xvalues) \
SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xnitmes, xtexts, xvalues)
#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xitems, xtexts, xvalues)
#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
{ .reg = xreg, .shift_l = xshift, .shift_r = xshift, \
.mask = xmask, .items = xitems, .texts = xtexts, \
.values = xvalues, .autodisable = 1}
#define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts)
#define SOC_ENUM(xname, xenum) \
@ -312,6 +317,11 @@
ARRAY_SIZE(xtexts), xtexts, xvalues)
#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
const struct soc_enum name = SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, \
xshift, xmask, ARRAY_SIZE(xtexts), xtexts, xvalues)
#define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
@ -767,6 +777,9 @@ struct snd_soc_component {
struct mutex io_mutex;
/* attached dynamic objects */
struct list_head dobj_list;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
#endif
@ -819,7 +832,7 @@ struct snd_soc_codec {
/* component */
struct snd_soc_component component;
/* dapm */
/* Don't access this directly, use snd_soc_codec_get_dapm() */
struct snd_soc_dapm_context dapm;
#ifdef CONFIG_DEBUG_FS
@ -961,30 +974,6 @@ struct snd_soc_dai_link {
enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
/* Keep DAI active over suspend */
unsigned int ignore_suspend:1;
/* Symmetry requirements */
unsigned int symmetric_rates:1;
unsigned int symmetric_channels:1;
unsigned int symmetric_samplebits:1;
/* Mark this pcm with non atomic ops */
bool nonatomic;
/* Do not create a PCM for this DAI link (Backend link) */
unsigned int no_pcm:1;
/* This DAI link can route to other DAI links at runtime (Frontend)*/
unsigned int dynamic:1;
/* DPCM capture and Playback support */
unsigned int dpcm_capture:1;
unsigned int dpcm_playback:1;
/* pmdown_time is ignored at stop */
unsigned int ignore_pmdown_time:1;
/* codec/machine specific init - e.g. add machine controls */
int (*init)(struct snd_soc_pcm_runtime *rtd);
@ -999,6 +988,33 @@ struct snd_soc_dai_link {
/* For unidirectional dai links */
bool playback_only;
bool capture_only;
/* Mark this pcm with non atomic ops */
bool nonatomic;
/* Keep DAI active over suspend */
unsigned int ignore_suspend:1;
/* Symmetry requirements */
unsigned int symmetric_rates:1;
unsigned int symmetric_channels:1;
unsigned int symmetric_samplebits:1;
/* Do not create a PCM for this DAI link (Backend link) */
unsigned int no_pcm:1;
/* This DAI link can route to other DAI links at runtime (Frontend)*/
unsigned int dynamic:1;
/* DPCM capture and Playback support */
unsigned int dpcm_capture:1;
unsigned int dpcm_playback:1;
/* DPCM used FE & BE merged format */
unsigned int dpcm_merged_format:1;
/* pmdown_time is ignored at stop */
unsigned int ignore_pmdown_time:1;
};
struct snd_soc_codec_conf {
@ -1111,6 +1127,9 @@ struct snd_soc_card {
struct list_head dapm_list;
struct list_head dapm_dirty;
/* attached dynamic objects */
struct list_head dobj_list;
/* Generic DAPM context for the card */
struct snd_soc_dapm_context dapm;
struct snd_soc_dapm_stats dapm_stats;
@ -1170,6 +1189,7 @@ struct soc_mixer_control {
unsigned int sign_bit;
unsigned int invert:1;
unsigned int autodisable:1;
struct snd_soc_dobj dobj;
};
struct soc_bytes {
@ -1180,6 +1200,8 @@ struct soc_bytes {
struct soc_bytes_ext {
int max;
struct snd_soc_dobj dobj;
/* used for TLV byte control */
int (*get)(unsigned int __user *bytes, unsigned int size);
int (*put)(const unsigned int __user *bytes, unsigned int size);
@ -1200,6 +1222,8 @@ struct soc_enum {
unsigned int mask;
const char * const *texts;
const unsigned int *values;
unsigned int autodisable:1;
struct snd_soc_dobj dobj;
};
/**
@ -1281,6 +1305,58 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
return component->dapm_ptr;
}
/**
* snd_soc_codec_get_dapm() - Returns the DAPM context for the CODEC
* @codec: The CODEC for which to get the DAPM context
*
* Note: Use this function instead of directly accessing the CODEC's dapm field
*/
static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm(
struct snd_soc_codec *codec)
{
return &codec->dapm;
}
/**
* snd_soc_dapm_init_bias_level() - Initialize CODEC DAPM bias level
* @dapm: The CODEC for which to initialize the DAPM bias level
* @level: The DAPM level to initialize to
*
* Initializes the CODEC DAPM bias level. See snd_soc_dapm_init_bias_level().
*/
static inline void snd_soc_codec_init_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
snd_soc_dapm_init_bias_level(snd_soc_codec_get_dapm(codec), level);
}
/**
* snd_soc_dapm_get_bias_level() - Get current CODEC DAPM bias level
* @codec: The CODEC for which to get the DAPM bias level
*
* Returns: The current DAPM bias level of the CODEC.
*/
static inline enum snd_soc_bias_level snd_soc_codec_get_bias_level(
struct snd_soc_codec *codec)
{
return snd_soc_dapm_get_bias_level(snd_soc_codec_get_dapm(codec));
}
/**
* snd_soc_codec_force_bias_level() - Set the CODEC DAPM bias level
* @codec: The CODEC for which to set the level
* @level: The level to set to
*
* Forces the CODEC bias level to a specific state. See
* snd_soc_dapm_force_bias_level().
*/
static inline int snd_soc_codec_force_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
return snd_soc_dapm_force_bias_level(snd_soc_codec_get_dapm(codec),
level);
}
/**
* snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
* @kcontrol: The kcontrol

View File

@ -31,12 +31,7 @@
* ~(sizeof(unsigned int) - 1)) ....
*/
#define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */
#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
#include <uapi/sound/tlv.h>
#define TLV_ITEM(type, ...) \
(type), TLV_LENGTH(__VA_ARGS__), __VA_ARGS__
@ -90,12 +85,4 @@
#define TLV_DB_GAIN_MUTE -9999999
/*
* channel-mapping TLV items
* TLV length must match with num_channels
*/
#define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */
#define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */
#define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */
#endif /* __SOUND_TLV_H */

388
include/uapi/sound/asoc.h Normal file
View File

@ -0,0 +1,388 @@
/*
* uapi/sound/asoc.h -- ALSA SoC Firmware Controls and DAPM
*
* Copyright (C) 2012 Texas Instruments Inc.
* Copyright (C) 2015 Intel Corporation.
*
* 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.
*
* Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
* algorithms, equalisers, DAIs, widgets etc.
*/
#ifndef __LINUX_UAPI_SND_ASOC_H
#define __LINUX_UAPI_SND_ASOC_H
#include <linux/types.h>
#include <sound/asound.h>
/*
* Maximum number of channels topology kcontrol can represent.
*/
#define SND_SOC_TPLG_MAX_CHAN 8
/*
* Maximum number of PCM formats capability
*/
#define SND_SOC_TPLG_MAX_FORMATS 16
/*
* Maximum number of PCM stream configs
*/
#define SND_SOC_TPLG_STREAM_CONFIG_MAX 8
/* individual kcontrol info types - can be mixed with other types */
#define SND_SOC_TPLG_CTL_VOLSW 1
#define SND_SOC_TPLG_CTL_VOLSW_SX 2
#define SND_SOC_TPLG_CTL_VOLSW_XR_SX 3
#define SND_SOC_TPLG_CTL_ENUM 4
#define SND_SOC_TPLG_CTL_BYTES 5
#define SND_SOC_TPLG_CTL_ENUM_VALUE 6
#define SND_SOC_TPLG_CTL_RANGE 7
#define SND_SOC_TPLG_CTL_STROBE 8
/* individual widget kcontrol info types - can be mixed with other types */
#define SND_SOC_TPLG_DAPM_CTL_VOLSW 64
#define SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE 65
#define SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT 66
#define SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE 67
#define SND_SOC_TPLG_DAPM_CTL_PIN 68
/* DAPM widget types - add new items to the end */
#define SND_SOC_TPLG_DAPM_INPUT 0
#define SND_SOC_TPLG_DAPM_OUTPUT 1
#define SND_SOC_TPLG_DAPM_MUX 2
#define SND_SOC_TPLG_DAPM_MIXER 3
#define SND_SOC_TPLG_DAPM_PGA 4
#define SND_SOC_TPLG_DAPM_OUT_DRV 5
#define SND_SOC_TPLG_DAPM_ADC 6
#define SND_SOC_TPLG_DAPM_DAC 7
#define SND_SOC_TPLG_DAPM_SWITCH 8
#define SND_SOC_TPLG_DAPM_PRE 9
#define SND_SOC_TPLG_DAPM_POST 10
#define SND_SOC_TPLG_DAPM_AIF_IN 11
#define SND_SOC_TPLG_DAPM_AIF_OUT 12
#define SND_SOC_TPLG_DAPM_DAI_IN 13
#define SND_SOC_TPLG_DAPM_DAI_OUT 14
#define SND_SOC_TPLG_DAPM_DAI_LINK 15
#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DAI_LINK
/* Header magic number and string sizes */
#define SND_SOC_TPLG_MAGIC 0x41536F43 /* ASoC */
/* string sizes */
#define SND_SOC_TPLG_NUM_TEXTS 16
/* ABI version */
#define SND_SOC_TPLG_ABI_VERSION 0x2
/* Max size of TLV data */
#define SND_SOC_TPLG_TLV_SIZE 32
/*
* File and Block header data types.
* Add new generic and vendor types to end of list.
* Generic types are handled by the core whilst vendors types are passed
* to the component drivers for handling.
*/
#define SND_SOC_TPLG_TYPE_MIXER 1
#define SND_SOC_TPLG_TYPE_BYTES 2
#define SND_SOC_TPLG_TYPE_ENUM 3
#define SND_SOC_TPLG_TYPE_DAPM_GRAPH 4
#define SND_SOC_TPLG_TYPE_DAPM_WIDGET 5
#define SND_SOC_TPLG_TYPE_DAI_LINK 6
#define SND_SOC_TPLG_TYPE_PCM 7
#define SND_SOC_TPLG_TYPE_MANIFEST 8
#define SND_SOC_TPLG_TYPE_CODEC_LINK 9
#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_CODEC_LINK
/* vendor block IDs - please add new vendor types to end */
#define SND_SOC_TPLG_TYPE_VENDOR_FW 1000
#define SND_SOC_TPLG_TYPE_VENDOR_CONFIG 1001
#define SND_SOC_TPLG_TYPE_VENDOR_COEFF 1002
#define SND_SOC_TPLG_TYPEVENDOR_CODEC 1003
#define SND_SOC_TPLG_STREAM_PLAYBACK 0
#define SND_SOC_TPLG_STREAM_CAPTURE 1
/*
* Block Header.
* This header preceeds all object and object arrays below.
*/
struct snd_soc_tplg_hdr {
__le32 magic; /* magic number */
__le32 abi; /* ABI version */
__le32 version; /* optional vendor specific version details */
__le32 type; /* SND_SOC_TPLG_TYPE_ */
__le32 size; /* size of this structure */
__le32 vendor_type; /* optional vendor specific type info */
__le32 payload_size; /* data bytes, excluding this header */
__le32 index; /* identifier for block */
__le32 count; /* number of elements in block */
} __attribute__((packed));
/*
* Private data.
* All topology objects may have private data that can be used by the driver or
* firmware. Core will ignore this data.
*/
struct snd_soc_tplg_private {
__le32 size; /* in bytes of private data */
char data[0];
} __attribute__((packed));
/*
* Kcontrol TLV data.
*/
struct snd_soc_tplg_ctl_tlv {
__le32 size; /* in bytes aligned to 4 */
__le32 numid; /* control element numeric identification */
__le32 count; /* number of elem in data array */
__le32 data[SND_SOC_TPLG_TLV_SIZE];
} __attribute__((packed));
/*
* Kcontrol channel data
*/
struct snd_soc_tplg_channel {
__le32 size; /* in bytes of this structure */
__le32 reg;
__le32 shift;
__le32 id; /* ID maps to Left, Right, LFE etc */
} __attribute__((packed));
/*
* Kcontrol Operations IDs
*/
struct snd_soc_tplg_kcontrol_ops_id {
__le32 get;
__le32 put;
__le32 info;
} __attribute__((packed));
/*
* kcontrol header
*/
struct snd_soc_tplg_ctl_hdr {
__le32 size; /* in bytes of this structure */
__le32 type;
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
__le32 access;
struct snd_soc_tplg_kcontrol_ops_id ops;
__le32 tlv_size; /* non zero means control has TLV data */
} __attribute__((packed));
/*
* Stream Capabilities
*/
struct snd_soc_tplg_stream_caps {
__le32 size; /* in bytes of this structure */
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
__le64 formats[SND_SOC_TPLG_MAX_FORMATS]; /* supported formats SNDRV_PCM_FMTBIT_* */
__le32 rates; /* supported rates SNDRV_PCM_RATE_* */
__le32 rate_min; /* min rate */
__le32 rate_max; /* max rate */
__le32 channels_min; /* min channels */
__le32 channels_max; /* max channels */
__le32 periods_min; /* min number of periods */
__le32 periods_max; /* max number of periods */
__le32 period_size_min; /* min period size bytes */
__le32 period_size_max; /* max period size bytes */
__le32 buffer_size_min; /* min buffer size bytes */
__le32 buffer_size_max; /* max buffer size bytes */
} __attribute__((packed));
/*
* FE or BE Stream configuration supported by SW/FW
*/
struct snd_soc_tplg_stream {
__le32 size; /* in bytes of this structure */
__le64 format; /* SNDRV_PCM_FMTBIT_* */
__le32 rate; /* SNDRV_PCM_RATE_* */
__le32 period_bytes; /* size of period in bytes */
__le32 buffer_bytes; /* size of buffer in bytes */
__le32 channels; /* channels */
__le32 tdm_slot; /* optional BE bitmask of supported TDM slots */
__le32 dai_fmt; /* SND_SOC_DAIFMT_ */
} __attribute__((packed));
/*
* Duplex stream configuration supported by SW/FW.
*/
struct snd_soc_tplg_stream_config {
__le32 size; /* in bytes of this structure */
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
struct snd_soc_tplg_stream playback;
struct snd_soc_tplg_stream capture;
} __attribute__((packed));
/*
* Manifest. List totals for each payload type. Not used in parsing, but will
* be passed to the component driver before any other objects in order for any
* global componnent resource allocations.
*
* File block representation for manifest :-
* +-----------------------------------+----+
* | struct snd_soc_tplg_hdr | 1 |
* +-----------------------------------+----+
* | struct snd_soc_tplg_manifest | 1 |
* +-----------------------------------+----+
*/
struct snd_soc_tplg_manifest {
__le32 size; /* in bytes of this structure */
__le32 control_elems; /* number of control elements */
__le32 widget_elems; /* number of widget elements */
__le32 graph_elems; /* number of graph elements */
__le32 dai_elems; /* number of DAI elements */
__le32 dai_link_elems; /* number of DAI link elements */
} __attribute__((packed));
/*
* Mixer kcontrol.
*
* File block representation for mixer kcontrol :-
* +-----------------------------------+----+
* | struct snd_soc_tplg_hdr | 1 |
* +-----------------------------------+----+
* | struct snd_soc_tplg_mixer_control | N |
* +-----------------------------------+----+
*/
struct snd_soc_tplg_mixer_control {
struct snd_soc_tplg_ctl_hdr hdr;
__le32 size; /* in bytes of this structure */
__le32 min;
__le32 max;
__le32 platform_max;
__le32 invert;
__le32 num_channels;
struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
struct snd_soc_tplg_ctl_tlv tlv;
struct snd_soc_tplg_private priv;
} __attribute__((packed));
/*
* Enumerated kcontrol
*
* File block representation for enum kcontrol :-
* +-----------------------------------+----+
* | struct snd_soc_tplg_hdr | 1 |
* +-----------------------------------+----+
* | struct snd_soc_tplg_enum_control | N |
* +-----------------------------------+----+
*/
struct snd_soc_tplg_enum_control {
struct snd_soc_tplg_ctl_hdr hdr;
__le32 size; /* in bytes of this structure */
__le32 num_channels;
struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
__le32 items;
__le32 mask;
__le32 count;
char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
__le32 values[SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN / 4];
struct snd_soc_tplg_private priv;
} __attribute__((packed));
/*
* Bytes kcontrol
*
* File block representation for bytes kcontrol :-
* +-----------------------------------+----+
* | struct snd_soc_tplg_hdr | 1 |
* +-----------------------------------+----+
* | struct snd_soc_tplg_bytes_control | N |
* +-----------------------------------+----+
*/
struct snd_soc_tplg_bytes_control {
struct snd_soc_tplg_ctl_hdr hdr;
__le32 size; /* in bytes of this structure */
__le32 max;
__le32 mask;
__le32 base;
__le32 num_regs;
struct snd_soc_tplg_private priv;
} __attribute__((packed));
/*
* DAPM Graph Element
*
* File block representation for DAPM graph elements :-
* +-------------------------------------+----+
* | struct snd_soc_tplg_hdr | 1 |
* +-------------------------------------+----+
* | struct snd_soc_tplg_dapm_graph_elem | N |
* +-------------------------------------+----+
*/
struct snd_soc_tplg_dapm_graph_elem {
char sink[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
char control[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
char source[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
} __attribute__((packed));
/*
* DAPM Widget.
*
* File block representation for DAPM widget :-
* +-------------------------------------+-----+
* | struct snd_soc_tplg_hdr | 1 |
* +-------------------------------------+-----+
* | struct snd_soc_tplg_dapm_widget | N |
* +-------------------------------------+-----+
* | struct snd_soc_tplg_enum_control | 0|1 |
* | struct snd_soc_tplg_mixer_control | 0|N |
* +-------------------------------------+-----+
*
* Optional enum or mixer control can be appended to the end of each widget
* in the block.
*/
struct snd_soc_tplg_dapm_widget {
__le32 size; /* in bytes of this structure */
__le32 id; /* SND_SOC_DAPM_CTL */
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
char sname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
__le32 reg; /* negative reg = no direct dapm */
__le32 shift; /* bits to shift */
__le32 mask; /* non-shifted mask */
__u32 invert; /* invert the power bit */
__u32 ignore_suspend; /* kept enabled over suspend */
__u16 event_flags;
__u16 event_type;
__u16 num_kcontrols;
struct snd_soc_tplg_private priv;
/*
* kcontrols that relate to this widget
* follow here after widget private data
*/
} __attribute__((packed));
struct snd_soc_tplg_pcm_cfg_caps {
struct snd_soc_tplg_stream_caps caps;
struct snd_soc_tplg_stream_config configs[SND_SOC_TPLG_STREAM_CONFIG_MAX];
__le32 num_configs; /* number of configs */
} __attribute__((packed));
/*
* Describes SW/FW specific features of PCM or DAI link.
*
* File block representation for PCM/DAI-Link :-
* +-----------------------------------+-----+
* | struct snd_soc_tplg_hdr | 1 |
* +-----------------------------------+-----+
* | struct snd_soc_tplg_dapm_pcm_dai | N |
* +-----------------------------------+-----+
*/
struct snd_soc_tplg_pcm_dai {
__le32 size; /* in bytes of this structure */
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
__le32 id; /* unique ID - used to match */
__le32 playback; /* supports playback mode */
__le32 capture; /* supports capture mode */
__le32 compress; /* 1 = compressed; 0 = PCM */
struct snd_soc_tplg_pcm_cfg_caps capconf[2]; /* capabilities and configs */
} __attribute__((packed));
#endif

31
include/uapi/sound/tlv.h Normal file
View File

@ -0,0 +1,31 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __UAPI_SOUND_TLV_H
#define __UAPI_SOUND_TLV_H
#define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */
#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
/*
* channel-mapping TLV items
* TLV length must match with num_channels
*/
#define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */
#define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */
#define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */
#endif

View File

@ -57,6 +57,7 @@ source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
source "sound/soc/ux500/Kconfig"
source "sound/soc/xtensa/Kconfig"
source "sound/soc/zte/Kconfig"
# Supported codecs
source "sound/soc/codecs/Kconfig"

View File

@ -1,5 +1,6 @@
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
snd-soc-core-objs += soc-topology.o
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
@ -38,3 +39,4 @@ obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
obj-$(CONFIG_SND_SOC) += ux500/
obj-$(CONFIG_SND_SOC) += xtensa/
obj-$(CONFIG_SND_SOC) += zte/

View File

@ -6,27 +6,22 @@ config SND_ATMEL_SOC
the ATMEL SSC interface. You will also need
to select the audio interfaces to support below.
if SND_ATMEL_SOC
config SND_ATMEL_SOC_PDC
tristate
depends on SND_ATMEL_SOC
bool
config SND_ATMEL_SOC_DMA
tristate
depends on SND_ATMEL_SOC
bool
select SND_SOC_GENERIC_DMAENGINE_PCM
config SND_ATMEL_SOC_SSC
tristate
depends on SND_ATMEL_SOC
help
Say Y or M if you want to add support for codecs the
ATMEL SSC interface. You will also needs to select the individual
machine drivers to support below.
config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
depends on ARCH_AT91 || COMPILE_TEST
depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI
depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_SOC_WM8731
@ -37,7 +32,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
config SND_ATMEL_SOC_WM8904
tristate "Atmel ASoC driver for boards using WM8904 codec"
depends on ARCH_AT91 || COMPILE_TEST
depends on ATMEL_SSC && SND_ATMEL_SOC && I2C
depends on ATMEL_SSC && I2C
select SND_ATMEL_SOC_SSC
select SND_ATMEL_SOC_DMA
select SND_SOC_WM8904
@ -48,10 +43,11 @@ config SND_ATMEL_SOC_WM8904
config SND_AT91_SOC_SAM9X5_WM8731
tristate "SoC Audio support for WM8731-based at91sam9x5 board"
depends on ARCH_AT91 || COMPILE_TEST
depends on ATMEL_SSC && SND_ATMEL_SOC && SND_SOC_I2C_AND_SPI
depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI
select SND_ATMEL_SOC_SSC
select SND_ATMEL_SOC_DMA
select SND_SOC_WM8731
help
Say Y if you want to add support for audio SoC on an
at91sam9x5 based board that is using WM8731 codec.
endif

View File

@ -1,10 +1,8 @@
# AT91 Platform Support
snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o
snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
snd-soc-atmel-pcm-$(CONFIG_SND_ATMEL_SOC_PDC) := atmel-pcm-pdc.o
snd-soc-atmel-pcm-$(CONFIG_SND_ATMEL_SOC_DMA) += atmel-pcm-dma.o
snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o $(snd-soc-atmel-pcm-y)
obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
# AT91 Machine Support

View File

@ -124,8 +124,7 @@ static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = {
int atmel_pcm_dma_platform_register(struct device *dev)
{
return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config, 0);
}
EXPORT_SYMBOL(atmel_pcm_dma_platform_register);

View File

@ -95,8 +95,9 @@ static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
static const struct snd_soc_dapm_route intercon[] = {
/* speaker connected to LHPOUT */
/* speaker connected to LHPOUT/RHPOUT */
{"Ext Spk", NULL, "LHPOUT"},
{"Ext Spk", NULL, "RHPOUT"},
/* mic is connected to Mic Jack, with WM8731 Mic Bias */
{"MICIN", NULL, "Mic Bias"},
@ -108,9 +109,7 @@ static const struct snd_soc_dapm_route intercon[] = {
*/
static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
printk(KERN_DEBUG
@ -124,10 +123,6 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
/* not connected */
snd_soc_dapm_nc_pin(dapm, "RLINEIN");
snd_soc_dapm_nc_pin(dapm, "LLINEIN");
#ifndef ENABLE_MIC_INPUT
snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic");
#endif
@ -158,6 +153,7 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
.num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets),
.dapm_routes = intercon,
.num_dapm_routes = ARRAY_SIZE(intercon),
.fully_routed = true,
};
static int at91sam9g20ek_audio_probe(struct platform_device *pdev)

View File

@ -21,7 +21,7 @@
#include "../codecs/wm8731.h"
#include "psc.h"
static struct platform_device_id db1200_pids[] = {
static const struct platform_device_id db1200_pids[] = {
{
.name = "db1200-ac97",
.driver_data = 0,

View File

@ -60,7 +60,6 @@ int devm_ep93xx_pcm_platform_register(struct device *dev)
{
return devm_snd_dmaengine_pcm_register(dev,
&ep93xx_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
SND_DMAENGINE_PCM_FLAG_NO_DT |
SND_DMAENGINE_PCM_FLAG_COMPAT);
}

View File

@ -1140,7 +1140,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
/* Enable Audio PLL & Audio section */
data = AUDIO_PLL | AUDIO_SECTION_ON;
pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
@ -1156,7 +1156,6 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -16,7 +16,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_88PM860X if MFD_88PM860X
select SND_SOC_L3
select SND_SOC_AB8500_CODEC if ABX500_CORE
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
select SND_SOC_AC97_CODEC
select SND_SOC_AD1836 if SPI_MASTER
select SND_SOC_AD193X_SPI if SPI_MASTER
select SND_SOC_AD193X_I2C if I2C
@ -54,7 +54,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS4271_SPI if SPI_MASTER
select SND_SOC_CS42XX8_I2C if I2C
select SND_SOC_CX20442 if TTY
select SND_SOC_DA7210 if I2C
select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI
select SND_SOC_DA7213 if I2C
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS5086 if I2C
select SND_SOC_TAS571X if I2C
select SND_SOC_TFA9879 if I2C
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
@ -211,8 +212,9 @@ config SND_SOC_AB8500_CODEC
tristate
config SND_SOC_AC97_CODEC
tristate
tristate "Build generic ASoC AC97 CODEC driver"
select SND_AC97_CODEC
select SND_SOC_AC97_BUS
config SND_SOC_AD1836
tristate
@ -611,6 +613,10 @@ config SND_SOC_TAS5086
tristate "Texas Instruments TAS5086 speaker amplifier"
depends on I2C
config SND_SOC_TAS571X
tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers"
depends on I2C
config SND_SOC_TFA9879
tristate "NXP Semiconductors TFA9879 amplifier"
depends on I2C

View File

@ -106,6 +106,7 @@ snd-soc-sta350-objs := sta350.o
snd-soc-sta529-objs := sta529.o
snd-soc-stac9766-objs := stac9766.o
snd-soc-tas5086-objs := tas5086.o
snd-soc-tas571x-objs := tas571x.o
snd-soc-tfa9879-objs := tfa9879.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
@ -288,6 +289,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o

View File

@ -1209,6 +1209,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
struct device *dev = codec->dev;
bool apply_fir, apply_iir;
@ -1234,15 +1235,14 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR;
apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR;
status = snd_soc_dapm_force_enable_pin(&codec->dapm,
"ANC Configure Input");
status = snd_soc_dapm_force_enable_pin(dapm, "ANC Configure Input");
if (status < 0) {
dev_err(dev,
"%s: ERROR: Failed to enable power (status = %d)!\n",
__func__, status);
goto cleanup;
}
snd_soc_dapm_sync(&codec->dapm);
snd_soc_dapm_sync(dapm);
anc_configure(codec, apply_fir, apply_iir);
@ -1259,8 +1259,8 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
drvdata->anc_status = ANC_IIR_CONFIGURED;
}
status = snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
snd_soc_dapm_sync(&codec->dapm);
status = snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
snd_soc_dapm_sync(dapm);
cleanup:
mutex_unlock(&drvdata->ctrl_lock);
@ -1947,6 +1947,7 @@ static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec)
static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
struct amic_settings *amics)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
u8 value8;
unsigned int value;
int status;
@ -1973,15 +1974,15 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__,
amic_micbias_str(amics->mic1a_micbias));
route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias];
status = snd_soc_dapm_add_routes(&codec->dapm, route, 1);
status = snd_soc_dapm_add_routes(dapm, route, 1);
dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__,
amic_micbias_str(amics->mic1b_micbias));
route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias];
status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
status |= snd_soc_dapm_add_routes(dapm, route, 1);
dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__,
amic_micbias_str(amics->mic2_micbias));
route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias];
status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1);
status |= snd_soc_dapm_add_routes(dapm, route, 1);
if (status < 0) {
dev_err(codec->dev,
"%s: Failed to add AMic-regulator DAPM-routes (%d).\n",
@ -2461,6 +2462,7 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
static int ab8500_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct device *dev = codec->dev;
struct device_node *np = dev->of_node;
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
@ -2541,7 +2543,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
&ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value;
drvdata->sid_fir_values = (long *)fc->value;
(void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
snd_soc_dapm_disable_pin(dapm, "ANC Configure Input");
mutex_init(&drvdata->ctrl_lock);

View File

@ -44,10 +44,6 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
}
#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
SNDRV_PCM_RATE_48000)
static const struct snd_soc_dai_ops ac97_dai_ops = {
.prepare = ac97_prepare,
};
@ -58,13 +54,13 @@ static struct snd_soc_dai_driver ac97_dai = {
.stream_name = "AC97 Playback",
.channels_min = 1,
.channels_max = 2,
.rates = STD_AC97_RATES,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SND_SOC_STD_AC97_FMTS,},
.capture = {
.stream_name = "AC97 Capture",
.channels_min = 1,
.channels_max = 2,
.rates = STD_AC97_RATES,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SND_SOC_STD_AC97_FMTS,},
.ops = &ac97_dai_ops,
};

View File

@ -251,7 +251,7 @@ static int ad1836_resume(struct snd_soc_codec *codec)
static int ad1836_probe(struct snd_soc_codec *codec)
{
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
int num_dacs, num_adcs;
int ret = 0;
int i;

View File

@ -1444,7 +1444,6 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec,
ADAU1373_PWDN_CTRL3_PWR_EN, 0);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
@ -101,6 +102,10 @@
#define ADAU1701_FIRMWARE "adau1701.bin"
static const char * const supply_names[] = {
"dvdd", "avdd"
};
struct adau1701 {
int gpio_nreset;
int gpio_pll_mode[2];
@ -112,6 +117,7 @@ struct adau1701 {
u8 pin_config[12];
struct sigmadsp *sigmadsp;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
};
static const struct snd_kcontrol_new adau1701_controls[] = {
@ -565,7 +571,6 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -669,6 +674,13 @@ static int adau1701_probe(struct snd_soc_codec *codec)
if (ret)
return ret;
ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
adau1701->supplies);
if (ret < 0) {
dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
return ret;
}
/*
* Let the pll_clkdiv variable default to something that won't happen
* at runtime. That way, we can postpone the firmware download from
@ -680,7 +692,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
/* initalize with pre-configured pll mode settings */
ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
if (ret < 0)
return ret;
goto exit_regulators_disable;
/* set up pin config */
val = 0;
@ -696,10 +708,60 @@ static int adau1701_probe(struct snd_soc_codec *codec)
regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
return 0;
exit_regulators_disable:
regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
return ret;
}
static int adau1701_remove(struct snd_soc_codec *codec)
{
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
if (gpio_is_valid(adau1701->gpio_nreset))
gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
return 0;
}
#ifdef CONFIG_PM
static int adau1701_suspend(struct snd_soc_codec *codec)
{
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies),
adau1701->supplies);
return 0;
}
static int adau1701_resume(struct snd_soc_codec *codec)
{
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
adau1701->supplies);
if (ret < 0) {
dev_err(codec->dev, "Failed to enable regulators: %d\n", ret);
return ret;
}
return adau1701_reset(codec, adau1701->pll_clkdiv, 0);
}
#else
#define adau1701_resume NULL
#define adau1701_suspend NULL
#endif /* CONFIG_PM */
static struct snd_soc_codec_driver adau1701_codec_drv = {
.probe = adau1701_probe,
.remove = adau1701_remove,
.resume = adau1701_resume,
.suspend = adau1701_suspend,
.set_bias_level = adau1701_set_bias_level,
.idle_bias_off = true,
@ -730,32 +792,58 @@ static int adau1701_i2c_probe(struct i2c_client *client,
struct device *dev = &client->dev;
int gpio_nreset = -EINVAL;
int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
int ret;
int ret, i;
adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
if (!adau1701)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
adau1701->supplies[i].supply = supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(adau1701->supplies),
adau1701->supplies);
if (ret < 0) {
dev_err(dev, "Failed to get regulators: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(adau1701->supplies),
adau1701->supplies);
if (ret < 0) {
dev_err(dev, "Failed to enable regulators: %d\n", ret);
return ret;
}
adau1701->client = client;
adau1701->regmap = devm_regmap_init(dev, NULL, client,
&adau1701_regmap);
if (IS_ERR(adau1701->regmap))
return PTR_ERR(adau1701->regmap);
if (IS_ERR(adau1701->regmap)) {
ret = PTR_ERR(adau1701->regmap);
goto exit_regulators_disable;
}
if (dev->of_node) {
gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
if (gpio_nreset < 0 && gpio_nreset != -ENOENT)
return gpio_nreset;
if (gpio_nreset < 0 && gpio_nreset != -ENOENT) {
ret = gpio_nreset;
goto exit_regulators_disable;
}
gpio_pll_mode[0] = of_get_named_gpio(dev->of_node,
"adi,pll-mode-gpios", 0);
if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT)
return gpio_pll_mode[0];
if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) {
ret = gpio_pll_mode[0];
goto exit_regulators_disable;
}
gpio_pll_mode[1] = of_get_named_gpio(dev->of_node,
"adi,pll-mode-gpios", 1);
if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT)
return gpio_pll_mode[1];
if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) {
ret = gpio_pll_mode[1];
goto exit_regulators_disable;
}
of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
&adau1701->pll_clkdiv);
@ -769,7 +857,7 @@ static int adau1701_i2c_probe(struct i2c_client *client,
ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW,
"ADAU1701 Reset");
if (ret < 0)
return ret;
goto exit_regulators_disable;
}
if (gpio_is_valid(gpio_pll_mode[0]) &&
@ -778,13 +866,13 @@ static int adau1701_i2c_probe(struct i2c_client *client,
GPIOF_OUT_INIT_LOW,
"ADAU1701 PLL mode 0");
if (ret < 0)
return ret;
goto exit_regulators_disable;
ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
GPIOF_OUT_INIT_LOW,
"ADAU1701 PLL mode 1");
if (ret < 0)
return ret;
goto exit_regulators_disable;
}
adau1701->gpio_nreset = gpio_nreset;
@ -795,11 +883,17 @@ static int adau1701_i2c_probe(struct i2c_client *client,
adau1701->sigmadsp = devm_sigmadsp_init_i2c(client,
&adau1701_sigmadsp_ops, ADAU1701_FIRMWARE);
if (IS_ERR(adau1701->sigmadsp))
return PTR_ERR(adau1701->sigmadsp);
if (IS_ERR(adau1701->sigmadsp)) {
ret = PTR_ERR(adau1701->sigmadsp);
goto exit_regulators_disable;
}
ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
&adau1701_dai, 1);
exit_regulators_disable:
regulator_bulk_disable(ARRAY_SIZE(adau1701->supplies), adau1701->supplies);
return ret;
}

View File

@ -466,7 +466,6 @@ static int adau1761_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -483,6 +482,7 @@ static enum adau1761_output_mode adau1761_get_lineout_mode(
static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adau1761_platform_data *pdata = codec->dev->platform_data;
struct adau *adau = snd_soc_codec_get_drvdata(codec);
enum adau1761_digmic_jackdet_pin_mode mode;
@ -515,21 +515,18 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
if (ret)
return ret;
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_NONE: /* fallthrough */
ret = snd_soc_dapm_add_routes(&codec->dapm,
adau1761_no_dmic_routes,
ret = snd_soc_dapm_add_routes(dapm, adau1761_no_dmic_routes,
ARRAY_SIZE(adau1761_no_dmic_routes));
if (ret)
return ret;
break;
case ADAU1761_DIGMIC_JACKDET_PIN_MODE_DIGMIC:
ret = snd_soc_dapm_new_controls(&codec->dapm,
adau1761_dmic_widgets,
ret = snd_soc_dapm_new_controls(dapm, adau1761_dmic_widgets,
ARRAY_SIZE(adau1761_dmic_widgets));
if (ret)
return ret;
ret = snd_soc_dapm_add_routes(&codec->dapm,
adau1761_dmic_routes,
ret = snd_soc_dapm_add_routes(dapm, adau1761_dmic_routes,
ARRAY_SIZE(adau1761_dmic_routes));
if (ret)
return ret;
@ -547,6 +544,7 @@ static int adau1761_setup_digmic_jackdetect(struct snd_soc_codec *codec)
static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
struct adau1761_platform_data *pdata = codec->dev->platform_data;
enum adau1761_output_mode mode;
@ -577,12 +575,12 @@ static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
}
if (mode == ADAU1761_OUTPUT_MODE_HEADPHONE_CAPLESS) {
ret = snd_soc_dapm_new_controls(&codec->dapm,
ret = snd_soc_dapm_new_controls(dapm,
adau1761_capless_dapm_widgets,
ARRAY_SIZE(adau1761_capless_dapm_widgets));
if (ret)
return ret;
ret = snd_soc_dapm_add_routes(&codec->dapm,
ret = snd_soc_dapm_add_routes(dapm,
adau1761_capless_dapm_routes,
ARRAY_SIZE(adau1761_capless_dapm_routes));
} else {
@ -590,12 +588,12 @@ static int adau1761_setup_headphone_mode(struct snd_soc_codec *codec)
ARRAY_SIZE(adau1761_mono_controls));
if (ret)
return ret;
ret = snd_soc_dapm_new_controls(&codec->dapm,
ret = snd_soc_dapm_new_controls(dapm,
adau1761_mono_dapm_widgets,
ARRAY_SIZE(adau1761_mono_dapm_widgets));
if (ret)
return ret;
ret = snd_soc_dapm_add_routes(&codec->dapm,
ret = snd_soc_dapm_add_routes(dapm,
adau1761_mono_dapm_routes,
ARRAY_SIZE(adau1761_mono_dapm_routes));
}
@ -640,6 +638,7 @@ static bool adau1761_readable_register(struct device *dev, unsigned int reg)
static int adau1761_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adau1761_platform_data *pdata = codec->dev->platform_data;
struct adau *adau = snd_soc_codec_get_drvdata(codec);
int ret;
@ -692,14 +691,12 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
return ret;
if (adau->type == ADAU1761) {
ret = snd_soc_dapm_new_controls(&codec->dapm,
adau1761_dapm_widgets,
ret = snd_soc_dapm_new_controls(dapm, adau1761_dapm_widgets,
ARRAY_SIZE(adau1761_dapm_widgets));
if (ret)
return ret;
ret = snd_soc_dapm_add_routes(&codec->dapm,
adau1761_dapm_routes,
ret = snd_soc_dapm_add_routes(dapm, adau1761_dapm_routes,
ARRAY_SIZE(adau1761_dapm_routes));
if (ret)
return ret;

View File

@ -339,7 +339,6 @@ static int adau1781_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -383,6 +382,7 @@ static int adau1781_set_input_mode(struct adau *adau, unsigned int reg,
static int adau1781_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
int ret;
@ -403,19 +403,17 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
}
if (pdata && pdata->use_dmic) {
ret = snd_soc_dapm_new_controls(&codec->dapm,
ret = snd_soc_dapm_new_controls(dapm,
adau1781_dmic_dapm_widgets,
ARRAY_SIZE(adau1781_dmic_dapm_widgets));
if (ret)
return ret;
ret = snd_soc_dapm_add_routes(&codec->dapm,
adau1781_dmic_dapm_routes,
ret = snd_soc_dapm_add_routes(dapm, adau1781_dmic_dapm_routes,
ARRAY_SIZE(adau1781_dmic_dapm_routes));
if (ret)
return ret;
} else {
ret = snd_soc_dapm_add_routes(&codec->dapm,
adau1781_adc_dapm_routes,
ret = snd_soc_dapm_add_routes(dapm, adau1781_adc_dapm_routes,
ARRAY_SIZE(adau1781_adc_dapm_routes));
if (ret)
return ret;

View File

@ -155,6 +155,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_update update;
@ -188,7 +189,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
update.reg = reg;
update.val = val;
snd_soc_dapm_mux_update_power(&codec->dapm, kcontrol,
snd_soc_dapm_mux_update_power(dapm, kcontrol,
ucontrol->value.enumerated.item[0], e, &update);
}
@ -444,8 +445,8 @@ static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec);
struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
struct snd_soc_dapm_context *dapm = &dai->codec->dapm;
switch (clk_id) {
case ADAU17X1_CLK_SRC_MCLK:
@ -804,6 +805,7 @@ EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
int adau17x1_add_widgets(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
int ret;
@ -811,14 +813,13 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
ARRAY_SIZE(adau17x1_controls));
if (ret)
return ret;
ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dapm_widgets,
ret = snd_soc_dapm_new_controls(dapm, adau17x1_dapm_widgets,
ARRAY_SIZE(adau17x1_dapm_widgets));
if (ret)
return ret;
if (adau17x1_has_dsp(adau)) {
ret = snd_soc_dapm_new_controls(&codec->dapm,
adau17x1_dsp_dapm_widgets,
ret = snd_soc_dapm_new_controls(dapm, adau17x1_dsp_dapm_widgets,
ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
if (ret)
return ret;
@ -840,21 +841,20 @@ EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
int adau17x1_add_routes(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
int ret;
ret = snd_soc_dapm_add_routes(&codec->dapm, adau17x1_dapm_routes,
ret = snd_soc_dapm_add_routes(dapm, adau17x1_dapm_routes,
ARRAY_SIZE(adau17x1_dapm_routes));
if (ret)
return ret;
if (adau17x1_has_dsp(adau)) {
ret = snd_soc_dapm_add_routes(&codec->dapm,
adau17x1_dsp_dapm_routes,
ret = snd_soc_dapm_add_routes(dapm, adau17x1_dsp_dapm_routes,
ARRAY_SIZE(adau17x1_dsp_dapm_routes));
} else {
ret = snd_soc_dapm_add_routes(&codec->dapm,
adau17x1_no_dsp_dapm_routes,
ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes,
ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
}
return ret;

View File

@ -202,7 +202,7 @@ static const struct snd_soc_dapm_route adau1977_dapm_routes[] = {
ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
#define ADAU1977_DC_SUB_SWITCH(x) \
SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \
SOC_SINGLE("ADC" #x " DC Subtraction Capture Switch", \
ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
static const struct snd_kcontrol_new adau1977_snd_controls[] = {
@ -485,7 +485,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
ret = adau1977_power_enable(adau1977);
break;
case SND_SOC_BIAS_OFF:
@ -493,12 +493,7 @@ static int adau1977_set_bias_level(struct snd_soc_codec *codec,
break;
}
if (ret)
return ret;
codec->dapm.bias_level = level;
return 0;
return ret;
}
static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
@ -853,12 +848,13 @@ static int adau1977_set_sysclk(struct snd_soc_codec *codec,
static int adau1977_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
int ret;
switch (adau1977->type) {
case ADAU1977:
ret = snd_soc_dapm_new_controls(&codec->dapm,
ret = snd_soc_dapm_new_controls(dapm,
adau1977_micbias_dapm_widgets,
ARRAY_SIZE(adau1977_micbias_dapm_widgets));
if (ret < 0)

View File

@ -539,7 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
unsigned int freq, int dir)
{
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
if (dir == SND_SOC_CLOCK_IN) {
switch (clk_id) {
@ -622,6 +622,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
unsigned int pll_ctrl1 = 0;
unsigned int pll_ctrl2 = 0;
@ -687,7 +688,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
adav80x->pll_src = source;
snd_soc_dapm_sync(&codec->dapm);
snd_soc_dapm_sync(dapm);
}
return 0;
@ -714,7 +715,6 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -801,11 +801,12 @@ static struct snd_soc_dai_driver adav80x_dais[] = {
static int adav80x_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
/* Force PLLs on for SYSCLK output */
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
snd_soc_dapm_force_enable_pin(dapm, "PLL1");
snd_soc_dapm_force_enable_pin(dapm, "PLL2");
/* Power down S/PDIF receiver, since it is currently not supported */
regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);

View File

@ -341,7 +341,6 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -412,7 +412,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
if (pdata && gpio_is_valid(pdata->gpio_power))
gpio_set_value(pdata->gpio_power, 1);
mdelay(1);
@ -439,7 +439,6 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
regcache_mark_dirty(ak4641->regmap);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -482,7 +482,6 @@ static int ak4642_set_bias_level(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -577,7 +577,6 @@ static int ak4671_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -826,7 +826,6 @@ static int alc5623_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1, 0);
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -894,7 +893,7 @@ static int alc5623_resume(struct snd_soc_codec *codec)
static int alc5623_probe(struct snd_soc_codec *codec)
{
struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
alc5623_reset(codec);

View File

@ -1000,7 +1000,6 @@ static int alc5632_set_bias_level(struct snd_soc_codec *codec,
ALC5632_PWR_MANAG_ADD1_MASK, 0);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -208,11 +208,12 @@ static const struct snd_soc_dapm_widget arizona_spkr =
int arizona_init_spk(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int ret;
ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1);
if (ret != 0)
return ret;
@ -220,8 +221,7 @@ int arizona_init_spk(struct snd_soc_codec *codec)
case WM8997:
break;
default:
ret = snd_soc_dapm_new_controls(&codec->dapm,
&arizona_spkr, 1);
ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
if (ret != 0)
return ret;
break;
@ -258,13 +258,14 @@ static const struct snd_soc_dapm_route arizona_mono_routes[] = {
int arizona_init_mono(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int i;
for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
if (arizona->pdata.out_mono[i])
snd_soc_dapm_add_routes(&codec->dapm,
snd_soc_dapm_add_routes(dapm,
&arizona_mono_routes[i], 1);
}
@ -274,6 +275,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono);
int arizona_init_gpio(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int i;
@ -281,23 +283,21 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
switch (arizona->type) {
case WM5110:
case WM8280:
snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
break;
default:
break;
}
snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
snd_soc_dapm_enable_pin(&codec->dapm,
"DRC1 Signal Activity");
snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
break;
case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
snd_soc_dapm_enable_pin(&codec->dapm,
"DRC2 Signal Activity");
snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
break;
default:
break;
@ -851,6 +851,134 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
}
EXPORT_SYMBOL_GPL(arizona_hp_ev);
static int arizona_dvfs_enable(struct snd_soc_codec *codec)
{
const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int ret;
ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
if (ret) {
dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
return ret;
}
ret = regmap_update_bits(arizona->regmap,
ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
ARIZONA_SUBSYS_MAX_FREQ,
ARIZONA_SUBSYS_MAX_FREQ);
if (ret) {
dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
return ret;
}
return 0;
}
static int arizona_dvfs_disable(struct snd_soc_codec *codec)
{
const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
int ret;
ret = regmap_update_bits(arizona->regmap,
ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
ARIZONA_SUBSYS_MAX_FREQ, 0);
if (ret) {
dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
return ret;
}
ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
if (ret) {
dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
return ret;
}
return 0;
}
int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret = 0;
mutex_lock(&priv->dvfs_lock);
if (!priv->dvfs_cached && !priv->dvfs_reqs) {
ret = arizona_dvfs_enable(codec);
if (ret)
goto err;
}
priv->dvfs_reqs |= flags;
err:
mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_up);
int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
unsigned int old_reqs;
int ret = 0;
mutex_lock(&priv->dvfs_lock);
old_reqs = priv->dvfs_reqs;
priv->dvfs_reqs &= ~flags;
if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
ret = arizona_dvfs_disable(codec);
mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_down);
int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret = 0;
mutex_lock(&priv->dvfs_lock);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (priv->dvfs_reqs)
ret = arizona_dvfs_enable(codec);
priv->dvfs_cached = false;
break;
case SND_SOC_DAPM_PRE_PMD:
/* We must ensure DVFS is disabled before the codec goes into
* suspend so that we are never in an illegal state of DVFS
* enabled without enough DCVDD
*/
priv->dvfs_cached = true;
if (priv->dvfs_reqs)
ret = arizona_dvfs_disable(codec);
break;
default:
break;
}
mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
void arizona_init_dvfs(struct arizona_priv *priv)
{
mutex_init(&priv->dvfs_lock);
}
EXPORT_SYMBOL_GPL(arizona_init_dvfs);
static unsigned int arizona_sysclk_48k_rates[] = {
6144000,
12288000,
@ -1266,7 +1394,7 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
int base = dai->driver->base;
int i, sr_val;
int i, sr_val, ret;
/*
* We will need to be more flexible than this in future,
@ -1282,6 +1410,23 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
}
sr_val = i;
switch (priv->arizona->type) {
case WM5102:
case WM8997:
if (arizona_sr_vals[sr_val] >= 88200)
ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
else
ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
if (ret) {
arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
return ret;
}
break;
default:
break;
}
switch (dai_priv->clk) {
case ARIZONA_CLK_SYSCLK:
switch (priv->arizona->type) {
@ -1474,6 +1619,7 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = dai->codec;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
struct snd_soc_dapm_route routes[2];
@ -1504,15 +1650,15 @@ static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
routes[0].source = arizona_dai_clk_str(dai_priv->clk);
routes[1].source = arizona_dai_clk_str(dai_priv->clk);
snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
routes[0].source = arizona_dai_clk_str(clk_id);
routes[1].source = arizona_dai_clk_str(clk_id);
snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
dai_priv->clk = clk_id;
return snd_soc_dapm_sync(&codec->dapm);
return snd_soc_dapm_sync(dapm);
}
static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)

View File

@ -60,6 +60,9 @@
#define ARIZONA_MAX_DAI 6
#define ARIZONA_MAX_ADSP 4
#define ARIZONA_DVFS_SR1_RQ 0x001
#define ARIZONA_DVFS_ADSP1_RQ 0x100
struct arizona;
struct wm_adsp;
@ -84,6 +87,10 @@ struct arizona_priv {
unsigned int spk_ena:2;
unsigned int spk_ena_pending:1;
unsigned int dvfs_reqs;
struct mutex dvfs_lock;
bool dvfs_cached;
};
#define ARIZONA_NUM_MIXER_INPUTS 103
@ -107,8 +114,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
arizona_mixer_tlv)
#define ARIZONA_MUX_ENUM_DECL(name, reg) \
SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \
arizona_mixer_texts, arizona_mixer_values)
SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL( \
name, reg, 0, 0xff, arizona_mixer_texts, arizona_mixer_values)
#define ARIZONA_MUX_CTL_DECL(name) \
const struct snd_kcontrol_new name##_mux = \
@ -245,6 +252,12 @@ struct arizona_fll {
char clock_ok_name[ARIZONA_FLL_NAME_LEN];
};
extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags);
extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags);
extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
extern void arizona_init_dvfs(struct arizona_priv *priv);
extern int arizona_init_fll(struct arizona *arizona, int id, int base,
int lock_irq, int ok_irq, struct arizona_fll *fll);
extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,

View File

@ -63,7 +63,7 @@ static int bt_sco_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id bt_sco_driver_ids[] = {
static const struct platform_device_id bt_sco_driver_ids[] = {
{
.name = "dfbmcs320",
},
@ -74,9 +74,18 @@ static struct platform_device_id bt_sco_driver_ids[] = {
};
MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
#if defined(CONFIG_OF)
static const struct of_device_id bt_sco_codec_of_match[] = {
{ .compatible = "delta,dfbmcs320", },
{},
};
MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match);
#endif
static struct platform_driver bt_sco_driver = {
.driver = {
.name = "bt-sco",
.of_match_table = of_match_ptr(bt_sco_codec_of_match),
},
.probe = bt_sco_probe,
.remove = bt_sco_remove,

View File

@ -92,7 +92,6 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
DAVINCI_VC_REG12_POWER_ALL_OFF);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>

View File

@ -503,7 +503,6 @@ static int cs4265_set_bias_level(struct snd_soc_codec *codec,
CS4265_PWRCTL_PDN);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -897,7 +897,7 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
CS42L52_PWRCTL1_PDN_CODEC, 0);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
regcache_cache_only(cs42l52->regmap, false);
regcache_sync(cs42l52->regmap);
}
@ -908,7 +908,6 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
regcache_cache_only(cs42l52->regmap, true);
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -956,7 +955,7 @@ static void cs42l52_beep_work(struct work_struct *work)
struct cs42l52_private *cs42l52 =
container_of(work, struct cs42l52_private, beep_work);
struct snd_soc_codec *codec = cs42l52->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
int i;
int val = 0;
int best = 0;

View File

@ -953,7 +953,7 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
CS42L56_PDN_ALL_MASK, 0);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
regcache_cache_only(cs42l56->regmap, false);
regcache_sync(cs42l56->regmap);
ret = regulator_bulk_enable(ARRAY_SIZE(cs42l56->supplies),
@ -978,7 +978,6 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec,
cs42l56->supplies);
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -1026,7 +1025,7 @@ static void cs42l56_beep_work(struct work_struct *work)
struct cs42l56_private *cs42l56 =
container_of(work, struct cs42l56_private, beep_work);
struct snd_soc_codec *codec = cs42l56->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
int i;
int val = 0;
int best = 0;

View File

@ -1208,7 +1208,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
regcache_cache_only(cs42l73->regmap, false);
regcache_sync(cs42l73->regmap);
}
@ -1228,7 +1228,6 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -380,7 +380,7 @@ EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
{
struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
switch (cs42xx8->drvdata->num_adcs) {
case 3:

View File

@ -333,7 +333,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (codec->dapm.bias_level != SND_SOC_BIAS_STANDBY)
if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_STANDBY)
break;
if (IS_ERR(cx20442->por))
err = PTR_ERR(cx20442->por);
@ -341,7 +341,7 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
err = regulator_enable(cx20442->por);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level != SND_SOC_BIAS_PREPARE)
if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_PREPARE)
break;
if (IS_ERR(cx20442->por))
err = PTR_ERR(cx20442->por);
@ -351,8 +351,6 @@ static int cx20442_set_bias_level(struct snd_soc_codec *codec,
default:
break;
}
if (!err)
codec->dapm.bias_level = level;
return err;
}

View File

@ -1374,7 +1374,7 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
/* Enable VMID reference & master bias */
snd_soc_update_bits(codec, DA7213_REFERENCES,
DA7213_VMID_EN | DA7213_BIAS_EN,
@ -1387,7 +1387,6 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
DA7213_VMID_EN | DA7213_BIAS_EN, 0);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -1432,7 +1432,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
/* Init Codec */
snd_soc_write(codec, DA732X_REG_REF1,
DA732X_VMID_FASTCHG);
@ -1502,8 +1502,6 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -1364,7 +1364,7 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
/* Enable VMID reference & master bias */
snd_soc_update_bits(codec, DA9055_REFERENCES,
DA9055_VMID_EN | DA9055_BIAS_EN,
@ -1377,7 +1377,6 @@ static int da9055_set_bias_level(struct snd_soc_codec *codec,
DA9055_VMID_EN | DA9055_BIAS_EN, 0);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -536,7 +536,7 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
snd_soc_update_bits(codec, ES8328_CONTROL1,
ES8328_CONTROL1_VMIDSEL_MASK |
ES8328_CONTROL1_ENREF,
@ -566,7 +566,6 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec,
0);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -909,8 +909,6 @@ static int isabelle_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -258,7 +258,7 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
/* The only way to clear the suspend flag is to reset the codec */
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
jz4740_codec_wakeup(regmap);
mask = JZ4740_CODEC_1_VREF_DISABLE |
@ -281,8 +281,6 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -23,11 +23,6 @@
#include <sound/soc.h>
#include <sound/tlv.h>
struct lm4857 {
struct regmap *regmap;
uint8_t mode;
};
static const struct reg_default lm4857_default_regs[] = {
{ 0x0, 0x00 },
{ 0x1, 0x00 },
@ -46,66 +41,33 @@ static const struct reg_default lm4857_default_regs[] = {
#define LM4857_WAKEUP 5
#define LM4857_EPGAIN 4
static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
static const unsigned int lm4857_mode_values[] = {
0,
6,
7,
8,
9,
};
ucontrol->value.integer.value[0] = lm4857->mode;
return 0;
}
static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
uint8_t value = ucontrol->value.integer.value[0];
lm4857->mode = value;
if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, value + 6);
return 1;
}
static int lm4857_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
switch (level) {
case SND_SOC_BIAS_ON:
regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F,
lm4857->mode + 6);
break;
case SND_SOC_BIAS_STANDBY:
regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, 0);
break;
default:
break;
}
codec->dapm.bias_level = level;
return 0;
}
static const char *lm4857_mode[] = {
static const char * const lm4857_mode_texts[] = {
"Off",
"Earpiece",
"Loudspeaker",
"Loudspeaker + Headphone",
"Headphone",
};
static SOC_ENUM_SINGLE_EXT_DECL(lm4857_mode_enum, lm4857_mode);
static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(lm4857_mode_enum,
LM4857_CTRL, 0, 0xf, lm4857_mode_texts, lm4857_mode_values);
static const struct snd_kcontrol_new lm4857_mode_ctrl =
SOC_DAPM_ENUM("Mode", lm4857_mode_enum);
static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("IN"),
SND_SOC_DAPM_DEMUX("Mode", SND_SOC_NOPM, 0, 0, &lm4857_mode_ctrl),
SND_SOC_DAPM_OUTPUT("LS"),
SND_SOC_DAPM_OUTPUT("HP"),
SND_SOC_DAPM_OUTPUT("EP"),
@ -127,24 +89,18 @@ static const struct snd_kcontrol_new lm4857_controls[] = {
LM4857_WAKEUP, 1, 0),
SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL,
LM4857_EPGAIN, 1, 0),
SOC_ENUM_EXT("Mode", lm4857_mode_enum,
lm4857_get_mode, lm4857_set_mode),
};
/* There is a demux between the input signal and the output signals.
* Currently there is no easy way to model it in ASoC and since it does not make
* much of a difference in practice simply connect the input direclty to the
* outputs. */
static const struct snd_soc_dapm_route lm4857_routes[] = {
{"LS", NULL, "IN"},
{"HP", NULL, "IN"},
{"EP", NULL, "IN"},
{ "Mode", NULL, "IN" },
{ "LS", "Loudspeaker", "Mode" },
{ "LS", "Loudspeaker + Headphone", "Mode" },
{ "HP", "Headphone", "Mode" },
{ "HP", "Loudspeaker + Headphone", "Mode" },
{ "EP", "Earpiece", "Mode" },
};
static struct snd_soc_codec_driver soc_codec_dev_lm4857 = {
.set_bias_level = lm4857_set_bias_level,
static struct snd_soc_component_driver lm4857_component_driver = {
.controls = lm4857_controls,
.num_controls = ARRAY_SIZE(lm4857_controls),
.dapm_widgets = lm4857_dapm_widgets,
@ -167,25 +123,14 @@ static const struct regmap_config lm4857_regmap_config = {
static int lm4857_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct lm4857 *lm4857;
struct regmap *regmap;
lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL);
if (!lm4857)
return -ENOMEM;
regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
i2c_set_clientdata(i2c, lm4857);
lm4857->regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
if (IS_ERR(lm4857->regmap))
return PTR_ERR(lm4857->regmap);
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
}
static int lm4857_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
return 0;
return devm_snd_soc_register_component(&i2c->dev,
&lm4857_component_driver, NULL, 0);
}
static const struct i2c_device_id lm4857_i2c_id[] = {
@ -200,7 +145,6 @@ static struct i2c_driver lm4857_i2c_driver = {
.owner = THIS_MODULE,
},
.probe = lm4857_i2c_probe,
.remove = lm4857_i2c_remove,
.id_table = lm4857_i2c_id,
};

View File

@ -1271,7 +1271,7 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
regcache_sync(lm49453->regmap);
snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
@ -1284,8 +1284,6 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -1571,7 +1571,7 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
regcache_sync(max98088->regmap);
snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
@ -1584,7 +1584,6 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
regcache_mark_dirty(max98088->regmap);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -1500,7 +1500,7 @@ static const struct snd_soc_dapm_route max98091_dapm_routes[] = {
static int max98090_add_widgets(struct snd_soc_codec *codec)
{
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
snd_soc_add_codec_controls(codec, max98090_snd_controls,
ARRAY_SIZE(max98090_snd_controls));
@ -1798,16 +1798,17 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
* away from ON. Disable the clock in that case, otherwise
* enable it.
*/
if (!IS_ERR(max98090->mclk)) {
if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
clk_disable_unprepare(max98090->mclk);
else
clk_prepare_enable(max98090->mclk);
}
if (IS_ERR(max98090->mclk))
break;
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
clk_disable_unprepare(max98090->mclk);
else
clk_prepare_enable(max98090->mclk);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
ret = regcache_sync(max98090->regmap);
if (ret != 0) {
dev_err(codec->dev,
@ -1824,7 +1825,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
regcache_mark_dirty(max98090->regmap);
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -2187,7 +2187,6 @@ static void max98090_jack_work(struct work_struct *work)
struct max98090_priv,
jack_work.work);
struct snd_soc_codec *codec = max98090->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int status = 0;
int reg;
@ -2266,8 +2265,6 @@ static void max98090_jack_work(struct work_struct *work)
snd_soc_jack_report(max98090->jack, status,
SND_JACK_HEADSET | SND_JACK_BTN_0);
snd_soc_dapm_sync(dapm);
}
static irqreturn_t max98090_interrupt(int irq, void *data)
@ -2422,6 +2419,8 @@ static int max98090_probe(struct snd_soc_codec *codec)
struct max98090_cdata *cdata;
enum max98090_type devtype;
int ret = 0;
int err;
unsigned int micbias;
dev_dbg(codec->dev, "max98090_probe\n");
@ -2506,8 +2505,17 @@ static int max98090_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, M98090_REG_BIAS_CONTROL,
M98090_VCM_MODE_MASK);
err = device_property_read_u32(codec->dev, "maxim,micbias", &micbias);
if (err) {
micbias = M98090_MBVSEL_2V8;
dev_info(codec->dev, "use default 2.8v micbias\n");
} else if (micbias < M98090_MBVSEL_2V2 || micbias > M98090_MBVSEL_2V8) {
dev_err(codec->dev, "micbias out of range 0x%x\n", micbias);
micbias = M98090_MBVSEL_2V8;
}
snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE,
M98090_MBVSEL_MASK, M98090_MBVSEL_2V8);
M98090_MBVSEL_MASK, micbias);
max98090_add_widgets(codec);

View File

@ -1650,16 +1650,17 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
* away from ON. Disable the clock in that case, otherwise
* enable it.
*/
if (!IS_ERR(max98095->mclk)) {
if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
clk_disable_unprepare(max98095->mclk);
else
clk_prepare_enable(max98095->mclk);
}
if (IS_ERR(max98095->mclk))
break;
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
clk_disable_unprepare(max98095->mclk);
else
clk_prepare_enable(max98095->mclk);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
ret = regcache_sync(max98095->regmap);
if (ret != 0) {
@ -1678,7 +1679,6 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
regcache_mark_dirty(max98095->regmap);
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -2198,7 +2198,7 @@ static int max98095_suspend(struct snd_soc_codec *codec)
if (max98095->headphone_jack || max98095->mic_jack)
max98095_jack_detect_disable(codec);
max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
@ -2208,7 +2208,7 @@ static int max98095_resume(struct snd_soc_codec *codec)
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *client = to_i2c_client(codec->dev);
max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
if (max98095->headphone_jack || max98095->mic_jack) {
max98095_jack_detect_enable(codec);
@ -2301,8 +2301,8 @@ static int max98095_probe(struct snd_soc_codec *codec)
/* register an audio interrupt */
ret = request_threaded_irq(client->irq, NULL,
max98095_report_jack,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"max98095", codec);
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
IRQF_ONESHOT, "max98095", codec);
if (ret) {
dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
goto err_access;

View File

@ -60,13 +60,12 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec)
{
struct gpio_desc *sdmode;
sdmode = devm_gpiod_get(codec->dev, "sdmode");
sdmode = devm_gpiod_get(codec->dev, "sdmode", GPIOD_OUT_LOW);
if (IS_ERR(sdmode)) {
dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n",
__func__, PTR_ERR(sdmode));
return PTR_ERR(sdmode);
}
gpiod_direction_output(sdmode, 0);
snd_soc_codec_set_drvdata(codec, sdmode);
return 0;

View File

@ -252,7 +252,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
ret = regcache_sync(max9850->regmap);
if (ret) {
dev_err(codec->dev,
@ -264,7 +264,6 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_OFF:
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -523,7 +523,7 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
/* VMID ON */
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
ML26124_VMID, ML26124_VMID);
msleep(500);
@ -536,7 +536,6 @@ static int ml26124_set_bias_level(struct snd_soc_codec *codec,
ML26124_VMID, 0);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -242,7 +242,7 @@ static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
switch (codec->dapm.bias_level) {
switch (snd_soc_codec_get_bias_level(codec)) {
case SND_SOC_BIAS_OFF:
case SND_SOC_BIAS_STANDBY:
break;
@ -270,7 +270,7 @@ static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
switch (codec->dapm.bias_level) {
switch (snd_soc_codec_get_bias_level(codec)) {
case SND_SOC_BIAS_OFF:
case SND_SOC_BIAS_STANDBY:
break;
@ -298,7 +298,7 @@ static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
switch (codec->dapm.bias_level) {
switch (snd_soc_codec_get_bias_level(codec)) {
case SND_SOC_BIAS_OFF:
case SND_SOC_BIAS_STANDBY:
break;
@ -641,8 +641,6 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -301,6 +301,7 @@ static int rt286_support_power_controls[] = {
static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
{
struct snd_soc_dapm_context *dapm;
unsigned int val, buf;
*hp = false;
@ -308,6 +309,9 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
if (!rt286->codec)
return -EINVAL;
dapm = snd_soc_codec_get_dapm(rt286->codec);
if (rt286->pdata.cbj_en) {
regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
*hp = buf & 0x80000000;
@ -316,14 +320,11 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
regmap_update_bits(rt286->regmap,
RT286_DC_GAIN, 0x200, 0x200);
snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
"HV");
snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
"VREF");
snd_soc_dapm_force_enable_pin(dapm, "HV");
snd_soc_dapm_force_enable_pin(dapm, "VREF");
/* power LDO1 */
snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
"LDO1");
snd_soc_dapm_sync(&rt286->codec->dapm);
snd_soc_dapm_force_enable_pin(dapm, "LDO1");
snd_soc_dapm_sync(dapm);
regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
msleep(50);
@ -360,11 +361,11 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
*mic = buf & 0x80000000;
}
snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV");
snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF");
snd_soc_dapm_disable_pin(dapm, "HV");
snd_soc_dapm_disable_pin(dapm, "VREF");
if (!*hp)
snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1");
snd_soc_dapm_sync(&rt286->codec->dapm);
snd_soc_dapm_disable_pin(dapm, "LDO1");
snd_soc_dapm_sync(dapm);
return 0;
}
@ -391,6 +392,7 @@ static void rt286_jack_detect_work(struct work_struct *work)
int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
rt286->jack = jack;
@ -398,7 +400,7 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
if (jack) {
/* enable IRQ */
if (rt286->jack->status & SND_JACK_HEADPHONE)
snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO1");
snd_soc_dapm_force_enable_pin(dapm, "LDO1");
regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x2);
/* Send an initial empty report */
snd_soc_jack_report(rt286->jack, rt286->jack->status,
@ -406,9 +408,9 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
} else {
/* disable IRQ */
regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x2, 0x0);
snd_soc_dapm_disable_pin(&codec->dapm, "LDO1");
snd_soc_dapm_disable_pin(dapm, "LDO1");
}
snd_soc_dapm_sync(&codec->dapm);
snd_soc_dapm_sync(dapm);
return 0;
}
@ -985,7 +987,7 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
{
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
snd_soc_write(codec,
RT286_SET_AUDIO_POWER, AC_PWRST_D0);
snd_soc_update_bits(codec,
@ -1012,7 +1014,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
default:
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -1546,7 +1546,7 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS,
RT5631_PWR_VREF | RT5631_PWR_MAIN_BIAS);
@ -1569,7 +1569,6 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
default:
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -1615,7 +1614,7 @@ static int rt5631_probe(struct snd_soc_codec *codec)
RT5631_DMIC_R_CH_LATCH_RISING);
}
codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
snd_soc_codec_init_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}

View File

@ -1870,7 +1870,7 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
{
switch (level) {
case SND_SOC_BIAS_STANDBY:
if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
if (SND_SOC_BIAS_OFF == snd_soc_codec_get_bias_level(codec)) {
snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
RT5640_PWR_VREF1 | RT5640_PWR_MB |
RT5640_PWR_BG | RT5640_PWR_VREF2,
@ -1902,7 +1902,6 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
default:
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -1935,11 +1934,12 @@ EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
static int rt5640_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
rt5640->codec = codec;
rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
@ -1951,18 +1951,18 @@ static int rt5640_probe(struct snd_soc_codec *codec)
snd_soc_add_codec_controls(codec,
rt5640_specific_snd_controls,
ARRAY_SIZE(rt5640_specific_snd_controls));
snd_soc_dapm_new_controls(&codec->dapm,
snd_soc_dapm_new_controls(dapm,
rt5640_specific_dapm_widgets,
ARRAY_SIZE(rt5640_specific_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm,
snd_soc_dapm_add_routes(dapm,
rt5640_specific_dapm_routes,
ARRAY_SIZE(rt5640_specific_dapm_routes));
break;
case RT5640_ID_5639:
snd_soc_dapm_new_controls(&codec->dapm,
snd_soc_dapm_new_controls(dapm,
rt5639_specific_dapm_widgets,
ARRAY_SIZE(rt5639_specific_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm,
snd_soc_dapm_add_routes(dapm,
rt5639_specific_dapm_routes,
ARRAY_SIZE(rt5639_specific_dapm_routes));
break;
@ -1991,7 +1991,7 @@ static int rt5640_suspend(struct snd_soc_codec *codec)
{
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
rt5640_reset(codec);
regcache_cache_only(rt5640->regmap, true);
regcache_mark_dirty(rt5640->regmap);

File diff suppressed because it is too large Load Diff

View File

@ -105,6 +105,7 @@
#define RT5645_TDM_CTRL_1 0x77
#define RT5645_TDM_CTRL_2 0x78
#define RT5645_TDM_CTRL_3 0x79
#define RT5650_TDM_CTRL_4 0x7a
/* Function - Analog */
#define RT5645_GLB_CLK 0x80
@ -942,10 +943,6 @@
#define RT5645_I2S2_SDI_I2S2 (0x1 << 6)
/* ADC/DAC Clock Control 1 (0x73) */
#define RT5645_I2S_BCLK_MS1_MASK (0x1 << 15)
#define RT5645_I2S_BCLK_MS1_SFT 15
#define RT5645_I2S_BCLK_MS1_32 (0x0 << 15)
#define RT5645_I2S_BCLK_MS1_64 (0x1 << 15)
#define RT5645_I2S_PD1_MASK (0x7 << 12)
#define RT5645_I2S_PD1_SFT 12
#define RT5645_I2S_PD1_1 (0x0 << 12)
@ -1067,13 +1064,14 @@
#define RT5645_SCLK_SRC_SFT 14
#define RT5645_SCLK_SRC_MCLK (0x0 << 14)
#define RT5645_SCLK_SRC_PLL1 (0x1 << 14)
#define RT5645_SCLK_SRC_RCCLK (0x2 << 14) /* 15MHz */
#define RT5645_PLL1_SRC_MASK (0x3 << 12)
#define RT5645_PLL1_SRC_SFT 12
#define RT5645_PLL1_SRC_MCLK (0x0 << 12)
#define RT5645_PLL1_SRC_BCLK1 (0x1 << 12)
#define RT5645_PLL1_SRC_BCLK2 (0x2 << 12)
#define RT5645_PLL1_SRC_BCLK3 (0x3 << 12)
#define RT5645_SCLK_SRC_RCCLK (0x2 << 14)
#define RT5645_PLL1_SRC_MASK (0x7 << 11)
#define RT5645_PLL1_SRC_SFT 11
#define RT5645_PLL1_SRC_MCLK (0x0 << 11)
#define RT5645_PLL1_SRC_BCLK1 (0x1 << 11)
#define RT5645_PLL1_SRC_BCLK2 (0x2 << 11)
#define RT5645_PLL1_SRC_BCLK3 (0x3 << 11)
#define RT5645_PLL1_SRC_RCCLK (0x4 << 11)
#define RT5645_PLL1_PD_MASK (0x1 << 3)
#define RT5645_PLL1_PD_SFT 3
#define RT5645_PLL1_PD_1 (0x0 << 3)
@ -2147,6 +2145,7 @@ enum {
};
enum {
RT5645_DMIC1_DISABLE,
RT5645_DMIC_DATA_IN2P,
RT5645_DMIC_DATA_GPIO6,
RT5645_DMIC_DATA_GPIO10,
@ -2154,6 +2153,7 @@ enum {
};
enum {
RT5645_DMIC2_DISABLE,
RT5645_DMIC_DATA_IN2N,
RT5645_DMIC_DATA_GPIO5,
RT5645_DMIC_DATA_GPIO11,
@ -2184,6 +2184,7 @@ struct rt5645_priv {
struct i2c_client *i2c;
struct snd_soc_jack *hp_jack;
struct snd_soc_jack *mic_jack;
struct snd_soc_jack *btn_jack;
struct delayed_work jack_detect_work;
int codec_type;
@ -2196,9 +2197,12 @@ struct rt5645_priv {
int pll_src;
int pll_in;
int pll_out;
int jack_type;
bool en_button_func;
};
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
struct snd_soc_jack *btn_jack);
#endif /* __RT5645_H__ */

View File

@ -1571,7 +1571,7 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
{
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
snd_soc_update_bits(codec, RT5651_PWR_ANLG1,
RT5651_PWR_VREF1 | RT5651_PWR_MB |
RT5651_PWR_BG | RT5651_PWR_VREF2,
@ -1604,7 +1604,6 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec,
default:
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -1625,7 +1624,7 @@ static int rt5651_probe(struct snd_soc_codec *codec)
RT5651_PWR_FV1 | RT5651_PWR_FV2,
RT5651_PWR_FV1 | RT5651_PWR_FV2);
rt5651_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}

View File

@ -416,12 +416,12 @@ static bool rt5670_readable_register(struct device *dev, unsigned int reg)
static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
{
int val;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
if (jack_insert) {
snd_soc_dapm_force_enable_pin(&codec->dapm,
"Mic Det Power");
snd_soc_dapm_sync(&codec->dapm);
snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power");
snd_soc_dapm_sync(dapm);
snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x0);
snd_soc_update_bits(codec, RT5670_CJ_CTRL2,
RT5670_CBJ_DET_MODE | RT5670_CBJ_MN_JD,
@ -447,15 +447,15 @@ static int rt5670_headset_detect(struct snd_soc_codec *codec, int jack_insert)
} else {
snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
rt5670->jack_type = SND_JACK_HEADPHONE;
snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
snd_soc_dapm_sync(&codec->dapm);
snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
snd_soc_dapm_sync(dapm);
}
} else {
snd_soc_update_bits(codec, RT5670_INT_IRQ_ST, 0x8, 0x0);
snd_soc_update_bits(codec, RT5670_GEN_CTRL3, 0x4, 0x4);
rt5670->jack_type = 0;
snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
snd_soc_dapm_sync(&codec->dapm);
snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
snd_soc_dapm_sync(dapm);
}
return rt5670->jack_type;
@ -2603,7 +2603,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) {
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
RT5670_PWR_VREF1 | RT5670_PWR_MB |
RT5670_PWR_BG | RT5670_PWR_VREF2,
@ -2647,30 +2647,30 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
default:
break;
}
codec->dapm.bias_level = level;
return 0;
}
static int rt5670_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) {
case RT5670_ID_5670:
case RT5670_ID_5671:
snd_soc_dapm_new_controls(&codec->dapm,
snd_soc_dapm_new_controls(dapm,
rt5670_specific_dapm_widgets,
ARRAY_SIZE(rt5670_specific_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm,
snd_soc_dapm_add_routes(dapm,
rt5670_specific_dapm_routes,
ARRAY_SIZE(rt5670_specific_dapm_routes));
break;
case RT5670_ID_5672:
snd_soc_dapm_new_controls(&codec->dapm,
snd_soc_dapm_new_controls(dapm,
rt5672_specific_dapm_widgets,
ARRAY_SIZE(rt5672_specific_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm,
snd_soc_dapm_add_routes(dapm,
rt5672_specific_dapm_routes,
ARRAY_SIZE(rt5672_specific_dapm_routes));
break;

View File

@ -820,7 +820,7 @@ static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol,
rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en);
return 0;
@ -1060,6 +1060,7 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
unsigned int asrc5_mask = 0, asrc5_value = 0;
unsigned int asrc6_mask = 0, asrc6_value = 0;
unsigned int asrc7_mask = 0, asrc7_value = 0;
unsigned int asrc8_mask = 0, asrc8_value = 0;
switch (clk_src) {
case RT5677_CLK_SEL_SYS:
@ -1196,10 +1197,108 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask,
asrc7_value);
/* ASRC 8 */
if (filter_mask & RT5677_I2S1_SOURCE) {
asrc8_mask |= RT5677_I2S1_CLK_SEL_MASK;
asrc8_value = (asrc8_value & ~RT5677_I2S1_CLK_SEL_MASK)
| ((clk_src - 1) << RT5677_I2S1_CLK_SEL_SFT);
}
if (filter_mask & RT5677_I2S2_SOURCE) {
asrc8_mask |= RT5677_I2S2_CLK_SEL_MASK;
asrc8_value = (asrc8_value & ~RT5677_I2S2_CLK_SEL_MASK)
| ((clk_src - 1) << RT5677_I2S2_CLK_SEL_SFT);
}
if (filter_mask & RT5677_I2S3_SOURCE) {
asrc8_mask |= RT5677_I2S3_CLK_SEL_MASK;
asrc8_value = (asrc8_value & ~RT5677_I2S3_CLK_SEL_MASK)
| ((clk_src - 1) << RT5677_I2S3_CLK_SEL_SFT);
}
if (filter_mask & RT5677_I2S4_SOURCE) {
asrc8_mask |= RT5677_I2S4_CLK_SEL_MASK;
asrc8_value = (asrc8_value & ~RT5677_I2S4_CLK_SEL_MASK)
| ((clk_src - 1) << RT5677_I2S4_CLK_SEL_SFT);
}
if (asrc8_mask)
regmap_update_bits(rt5677->regmap, RT5677_ASRC_8, asrc8_mask,
asrc8_value);
return 0;
}
EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src);
static int rt5677_dmic_use_asrc(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
unsigned int asrc_setting;
switch (source->shift) {
case 11:
regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_STO1_CLK_SEL_MASK) >>
RT5677_AD_STO1_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 10:
regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_STO2_CLK_SEL_MASK) >>
RT5677_AD_STO2_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 9:
regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_STO3_CLK_SEL_MASK) >>
RT5677_AD_STO3_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 8:
regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_STO4_CLK_SEL_MASK) >>
RT5677_AD_STO4_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 7:
regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_MONOL_CLK_SEL_MASK) >>
RT5677_AD_MONOL_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
case 6:
regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
asrc_setting = (asrc_setting & RT5677_AD_MONOR_CLK_SEL_MASK) >>
RT5677_AD_MONOR_CLK_SEL_SFT;
if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
return 1;
break;
default:
break;
}
return 0;
}
/* Digital Mixer */
static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
@ -2479,7 +2578,7 @@ static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (codec->dapm.bias_level != SND_SOC_BIAS_ON &&
if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON &&
!rt5677->is_vref_slow) {
mdelay(20);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
@ -3057,12 +3156,12 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
};
static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
{ "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
{ "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc },
{ "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc },
{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
{ "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", rt5677_dmic_use_asrc },
{ "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", rt5677_dmic_use_asrc },
{ "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", rt5677_dmic_use_asrc },
{ "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", rt5677_dmic_use_asrc },
{ "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", rt5677_dmic_use_asrc },
{ "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", rt5677_dmic_use_asrc },
{ "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
{ "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
{ "I2S3", NULL, "I2S3 ASRC", can_use_asrc},
@ -4353,7 +4452,7 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_PREPARE:
if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
rt5677_set_dsp_vad(codec, false);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
@ -4395,7 +4494,6 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
default:
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -4606,22 +4704,23 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
static int rt5677_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
int i;
rt5677->codec = codec;
if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
snd_soc_dapm_add_routes(&codec->dapm,
snd_soc_dapm_add_routes(dapm,
rt5677_dmic2_clk_2,
ARRAY_SIZE(rt5677_dmic2_clk_2));
} else { /*use dmic1 clock by default*/
snd_soc_dapm_add_routes(&codec->dapm,
snd_soc_dapm_add_routes(dapm,
rt5677_dmic2_clk_1,
ARRAY_SIZE(rt5677_dmic2_clk_1));
}
rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
@ -4667,6 +4766,8 @@ static int rt5677_remove(struct snd_soc_codec *codec)
regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
if (gpio_is_valid(rt5677->pow_ldo2))
gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
if (gpio_is_valid(rt5677->reset_pin))
gpio_set_value_cansleep(rt5677->reset_pin, 0);
return 0;
}
@ -4682,6 +4783,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
if (gpio_is_valid(rt5677->pow_ldo2))
gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
if (gpio_is_valid(rt5677->reset_pin))
gpio_set_value_cansleep(rt5677->reset_pin, 0);
}
return 0;
@ -4692,10 +4795,13 @@ static int rt5677_resume(struct snd_soc_codec *codec)
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
if (!rt5677->dsp_vad_en) {
if (gpio_is_valid(rt5677->pow_ldo2)) {
if (gpio_is_valid(rt5677->pow_ldo2))
gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
if (gpio_is_valid(rt5677->reset_pin))
gpio_set_value_cansleep(rt5677->reset_pin, 1);
if (gpio_is_valid(rt5677->pow_ldo2) ||
gpio_is_valid(rt5677->reset_pin))
msleep(10);
}
regcache_cache_only(rt5677->regmap, false);
regcache_sync(rt5677->regmap);
@ -4933,6 +5039,8 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
rt5677->pow_ldo2 = of_get_named_gpio(np,
"realtek,pow-ldo2-gpio", 0);
rt5677->reset_pin = of_get_named_gpio(np,
"realtek,reset-gpio", 0);
/*
* POW_LDO2 is optional (it may be statically tied on the board).
@ -4943,6 +5051,9 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
if (!gpio_is_valid(rt5677->pow_ldo2) &&
(rt5677->pow_ldo2 != -ENOENT))
return rt5677->pow_ldo2;
if (!gpio_is_valid(rt5677->reset_pin) &&
(rt5677->reset_pin != -ENOENT))
return rt5677->reset_pin;
of_property_read_u8_array(np, "realtek,gpio-config",
rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
@ -5044,6 +5155,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
}
} else {
rt5677->pow_ldo2 = -EINVAL;
rt5677->reset_pin = -EINVAL;
}
if (gpio_is_valid(rt5677->pow_ldo2)) {
@ -5055,6 +5167,21 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
rt5677->pow_ldo2, ret);
return ret;
}
}
if (gpio_is_valid(rt5677->reset_pin)) {
ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin,
GPIOF_OUT_INIT_HIGH,
"RT5677 RESET");
if (ret < 0) {
dev_err(&i2c->dev, "Failed to request RESET %d: %d\n",
rt5677->reset_pin, ret);
return ret;
}
}
if (gpio_is_valid(rt5677->pow_ldo2) ||
gpio_is_valid(rt5677->reset_pin)) {
/* Wait a while until I2C bus becomes available. The datasheet
* does not specify the exact we should wait but startup
* sequence mentiones at least a few milliseconds.

View File

@ -1446,6 +1446,16 @@
#define RT5677_DSP_OB_4_7_CLK_SEL_MASK (0xf << 8)
#define RT5677_DSP_OB_4_7_CLK_SEL_SFT 8
/* ASRC Control 8 (0x8a) */
#define RT5677_I2S1_CLK_SEL_MASK (0xf << 12)
#define RT5677_I2S1_CLK_SEL_SFT 12
#define RT5677_I2S2_CLK_SEL_MASK (0xf << 8)
#define RT5677_I2S2_CLK_SEL_SFT 8
#define RT5677_I2S3_CLK_SEL_MASK (0xf << 4)
#define RT5677_I2S3_CLK_SEL_SFT 4
#define RT5677_I2S4_CLK_SEL_MASK (0xf)
#define RT5677_I2S4_CLK_SEL_SFT 0
/* VAD Function Control 4 (0x9f) */
#define RT5677_VAD_SRC_MASK (0x7 << 8)
#define RT5677_VAD_SRC_SFT 8
@ -1744,6 +1754,10 @@ enum {
RT5677_AD_MONO_R_FILTER = (0x1 << 12),
RT5677_DSP_OB_0_3_FILTER = (0x1 << 13),
RT5677_DSP_OB_4_7_FILTER = (0x1 << 14),
RT5677_I2S1_SOURCE = (0x1 << 15),
RT5677_I2S2_SOURCE = (0x1 << 16),
RT5677_I2S3_SOURCE = (0x1 << 17),
RT5677_I2S4_SOURCE = (0x1 << 18),
};
struct rt5677_priv {
@ -1762,6 +1776,7 @@ struct rt5677_priv {
int pll_in;
int pll_out;
int pow_ldo2; /* POW_LDO2 pin */
int reset_pin; /* RESET pin */
enum rt5677_type type;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio_chip;

View File

@ -948,7 +948,7 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(
ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
@ -979,7 +979,6 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -1091,6 +1090,19 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg)
}
}
/*
* This precalculated table contains all (vag_val * 100 / lo_calcntrl) results
* to select an appropriate lo_vol_* in SGTL5000_CHIP_LINE_OUT_VOL
* The calculatation was done for all possible register values which
* is the array index and the following formula: 10^((idx15)/40) * 100
*/
static const u8 vol_quot_table[] = {
42, 45, 47, 50, 53, 56, 60, 63,
67, 71, 75, 79, 84, 89, 94, 100,
106, 112, 119, 126, 133, 141, 150, 158,
168, 178, 188, 200, 211, 224, 237, 251
};
/*
* sgtl5000 has 3 internal power supplies:
* 1. VAG, normally set to vdda/2
@ -1111,6 +1123,10 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
u16 ana_pwr;
u16 lreg_ctrl;
int vag;
int lo_vag;
int vol_quot;
int lo_vol;
size_t i;
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
vdda = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer);
@ -1198,23 +1214,45 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT);
/* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
vag = vddio / 2;
if (vag <= SGTL5000_LINE_OUT_GND_BASE)
vag = 0;
else if (vag >= SGTL5000_LINE_OUT_GND_BASE +
lo_vag = vddio / 2;
if (lo_vag <= SGTL5000_LINE_OUT_GND_BASE)
lo_vag = 0;
else if (lo_vag >= SGTL5000_LINE_OUT_GND_BASE +
SGTL5000_LINE_OUT_GND_STP * SGTL5000_LINE_OUT_GND_MAX)
vag = SGTL5000_LINE_OUT_GND_MAX;
lo_vag = SGTL5000_LINE_OUT_GND_MAX;
else
vag = (vag - SGTL5000_LINE_OUT_GND_BASE) /
lo_vag = (lo_vag - SGTL5000_LINE_OUT_GND_BASE) /
SGTL5000_LINE_OUT_GND_STP;
snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
SGTL5000_LINE_OUT_CURRENT_MASK |
SGTL5000_LINE_OUT_GND_MASK,
vag << SGTL5000_LINE_OUT_GND_SHIFT |
lo_vag << SGTL5000_LINE_OUT_GND_SHIFT |
SGTL5000_LINE_OUT_CURRENT_360u <<
SGTL5000_LINE_OUT_CURRENT_SHIFT);
/*
* Set lineout output level in range (0..31)
* the same value is used for right and left channel
*
* Searching for a suitable index solving this formula:
* idx = 40 * log10(vag_val / lo_cagcntrl) + 15
*/
vol_quot = (vag * 100) / lo_vag;
lo_vol = 0;
for (i = 0; i < ARRAY_SIZE(vol_quot_table); i++) {
if (vol_quot >= vol_quot_table[i])
lo_vol = i;
else
break;
}
snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_VOL,
SGTL5000_LINE_OUT_VOL_RIGHT_MASK |
SGTL5000_LINE_OUT_VOL_LEFT_MASK,
lo_vol << SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT |
lo_vol << SGTL5000_LINE_OUT_VOL_LEFT_SHIFT);
return 0;
}

View File

@ -395,7 +395,7 @@ struct snd_soc_dai_driver sirf_audio_codec_dai = {
static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
pm_runtime_enable(codec->dev);

View File

@ -194,7 +194,7 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_PREPARE:
if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
pr_debug("vaud_bias powering up pll\n");
/* power up the pll */
snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5));
@ -205,17 +205,22 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
switch (snd_soc_codec_get_bias_level(codec)) {
case SND_SOC_BIAS_OFF:
pr_debug("vaud_bias power up rail\n");
/* power up the rail */
snd_soc_write(codec, SN95031_VAUD,
BIT(2)|BIT(1)|BIT(0));
msleep(1);
} else if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
break;
case SND_SOC_BIAS_PREPARE:
/* turn off pcm */
pr_debug("vaud_bias power dn pcm\n");
snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0);
snd_soc_write(codec, SN95031_AUDPLLCTRL, 0);
break;
default:
break;
}
break;
@ -226,7 +231,6 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -510,7 +510,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
ret = ssm2518_set_power(ssm2518, true);
break;
case SND_SOC_BIAS_OFF:
@ -518,12 +518,7 @@ static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
break;
}
if (ret)
return ret;
codec->dapm.bias_level = level;
return 0;
return ret;
}
static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,

View File

@ -473,7 +473,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -524,8 +523,8 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
static int ssm2602_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
@ -549,7 +548,7 @@ static int ssm2602_codec_probe(struct snd_soc_codec *codec)
static int ssm2604_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
int ret;
ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,

View File

@ -353,7 +353,7 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
ret = ssm4567_set_power(ssm4567, true);
break;
case SND_SOC_BIAS_OFF:
@ -361,12 +361,7 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
break;
}
if (ret)
return ret;
codec->dapm.bias_level = level;
return 0;
return ret;
}
static const struct snd_soc_dai_ops ssm4567_dai_ops = {

View File

@ -819,7 +819,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
sta32x->supplies);
if (ret != 0) {
@ -854,7 +854,6 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
sta32x->supplies);
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -970,7 +969,7 @@ static int sta32x_probe(struct snd_soc_codec *codec)
if (sta32x->pdata->needs_esd_watchdog)
INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
@ -1096,16 +1095,10 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
#endif
/* GPIOs */
sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset");
if (IS_ERR(sta32x->gpiod_nreset)) {
ret = PTR_ERR(sta32x->gpiod_nreset);
if (ret != -ENOENT && ret != -ENOSYS)
return ret;
sta32x->gpiod_nreset = NULL;
} else {
gpiod_direction_output(sta32x->gpiod_nreset, 0);
}
sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(sta32x->gpiod_nreset))
return PTR_ERR(sta32x->gpiod_nreset);
/* regulators */
for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)

View File

@ -853,7 +853,7 @@ static int sta350_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(
ARRAY_SIZE(sta350->supplies),
sta350->supplies);
@ -890,7 +890,6 @@ static int sta350_set_bias_level(struct snd_soc_codec *codec,
sta350->supplies);
break;
}
codec->dapm.bias_level = level;
return 0;
}
@ -1037,7 +1036,7 @@ static int sta350_probe(struct snd_soc_codec *codec)
sta350->coef_shadow[60] = 0x400000;
sta350->coef_shadow[61] = 0x400000;
sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
@ -1218,8 +1217,8 @@ static int sta350_i2c_probe(struct i2c_client *i2c,
if (IS_ERR(sta350->gpiod_nreset))
return PTR_ERR(sta350->gpiod_nreset);
sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down",
GPIOD_OUT_LOW);
sta350->gpiod_power_down = devm_gpiod_get_optional(dev, "power-down",
GPIOD_OUT_LOW);
if (IS_ERR(sta350->gpiod_power_down))
return PTR_ERR(sta350->gpiod_power_down);

View File

@ -165,7 +165,7 @@ static int sta529_set_bias_level(struct snd_soc_codec *codec, enum
FFX_CLK_ENB);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
regcache_sync(sta529->regmap);
snd_soc_update_bits(codec, STA529_FFXCFG0,
POWER_CNTLMSAK, POWER_STDBY);
@ -179,12 +179,6 @@ static int sta529_set_bias_level(struct snd_soc_codec *codec, enum
break;
}
/*
* store the label for powers down audio subsystem for suspend.This is
* used by soc core layer
*/
codec->dapm.bias_level = level;
return 0;
}

View File

@ -236,7 +236,6 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
break;
}
codec->dapm.bias_level = level;
return 0;
}

View File

@ -34,6 +34,7 @@
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/tas2552-plat.h>
#include <dt-bindings/sound/tas2552.h>
#include "tas2552.h"
@ -45,7 +46,7 @@ static struct reg_default tas2552_reg_defs[] = {
{TAS2552_PDM_CFG, 0x01},
{TAS2552_PGA_GAIN, 0x00},
{TAS2552_BOOST_PT_CTRL, 0x0f},
{TAS2552_RESERVED_0D, 0x00},
{TAS2552_RESERVED_0D, 0xbe},
{TAS2552_LIMIT_RATE_HYS, 0x08},
{TAS2552_CFG_2, 0xef},
{TAS2552_SER_CTRL_1, 0x00},
@ -75,20 +76,45 @@ struct tas2552_data {
struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES];
struct gpio_desc *enable_gpio;
unsigned char regs[TAS2552_VBAT_DATA];
unsigned int mclk;
unsigned int pll_clkin;
unsigned int pdm_clk;
unsigned int dai_fmt;
unsigned int tdm_delay;
};
static int tas2552_post_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
snd_soc_write(codec, TAS2552_RESERVED_0D, 0xc0);
snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5),
(1 << 5));
snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 0);
snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS, 0);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS,
TAS2552_SWS);
snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 1);
snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0);
snd_soc_write(codec, TAS2552_RESERVED_0D, 0xbe);
break;
}
return 0;
}
/* Input mux controls */
static const char *tas2552_input_texts[] = {
"Digital", "Analog"
};
static const char * const tas2552_input_texts[] = {
"Digital", "Analog" };
static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7,
tas2552_input_texts);
static const struct snd_kcontrol_new tas2552_input_mux_control[] = {
SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum)
};
static const struct snd_kcontrol_new tas2552_input_mux_control =
SOC_DAPM_ENUM("Route", tas2552_input_mux_enum);
static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
{
@ -96,12 +122,13 @@ static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
/* MUX Controls */
SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0,
tas2552_input_mux_control),
&tas2552_input_mux_control),
SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
SND_SOC_DAPM_POST("Post Event", tas2552_post_event),
SND_SOC_DAPM_OUTPUT("OUT")
};
@ -118,15 +145,16 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = {
#ifdef CONFIG_PM
static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
{
u8 cfg1_reg;
u8 cfg1_reg = 0;
if (!tas_data->codec)
return;
if (sw_shutdown)
cfg1_reg = 0;
else
cfg1_reg = TAS2552_SWS_MASK;
cfg1_reg = TAS2552_SWS;
snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1,
TAS2552_SWS_MASK, cfg1_reg);
snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, TAS2552_SWS,
cfg1_reg);
}
#endif
@ -138,15 +166,92 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
int sample_rate, pll_clk;
int d;
int cpf;
u8 p, j;
u8 ser_ctrl1_reg, wclk_rate;
if (!tas2552->mclk)
switch (params_width(params)) {
case 16:
ser_ctrl1_reg = TAS2552_WORDLENGTH_16BIT;
cpf = 32 + tas2552->tdm_delay;
break;
case 20:
ser_ctrl1_reg = TAS2552_WORDLENGTH_20BIT;
cpf = 64 + tas2552->tdm_delay;
break;
case 24:
ser_ctrl1_reg = TAS2552_WORDLENGTH_24BIT;
cpf = 64 + tas2552->tdm_delay;
break;
case 32:
ser_ctrl1_reg = TAS2552_WORDLENGTH_32BIT;
cpf = 64 + tas2552->tdm_delay;
break;
default:
dev_err(codec->dev, "Not supported sample size: %d\n",
params_width(params));
return -EINVAL;
}
if (cpf <= 32)
ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_32;
else if (cpf <= 64)
ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_64;
else if (cpf <= 128)
ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_128;
else
ser_ctrl1_reg |= TAS2552_CLKSPERFRAME_256;
snd_soc_update_bits(codec, TAS2552_SER_CTRL_1,
TAS2552_WORDLENGTH_MASK | TAS2552_CLKSPERFRAME_MASK,
ser_ctrl1_reg);
switch (params_rate(params)) {
case 8000:
wclk_rate = TAS2552_WCLK_FREQ_8KHZ;
break;
case 11025:
case 12000:
wclk_rate = TAS2552_WCLK_FREQ_11_12KHZ;
break;
case 16000:
wclk_rate = TAS2552_WCLK_FREQ_16KHZ;
break;
case 22050:
case 24000:
wclk_rate = TAS2552_WCLK_FREQ_22_24KHZ;
break;
case 32000:
wclk_rate = TAS2552_WCLK_FREQ_32KHZ;
break;
case 44100:
case 48000:
wclk_rate = TAS2552_WCLK_FREQ_44_48KHZ;
break;
case 88200:
case 96000:
wclk_rate = TAS2552_WCLK_FREQ_88_96KHZ;
break;
case 176400:
case 192000:
wclk_rate = TAS2552_WCLK_FREQ_176_192KHZ;
break;
default:
dev_err(codec->dev, "Not supported sample rate: %d\n",
params_rate(params));
return -EINVAL;
}
snd_soc_update_bits(codec, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK,
wclk_rate);
if (!tas2552->pll_clkin)
return -EINVAL;
snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
if (tas2552->mclk == TAS2552_245MHZ_CLK ||
tas2552->mclk == TAS2552_225MHZ_CLK) {
if (tas2552->pll_clkin == TAS2552_245MHZ_CLK ||
tas2552->pll_clkin == TAS2552_225MHZ_CLK) {
/* By pass the PLL configuration */
snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
TAS2552_PLL_BYPASS_MASK,
@ -170,8 +275,8 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
j = (pll_clk * 2 * (1 << p)) / tas2552->mclk;
d = (pll_clk * 2 * (1 << p)) % tas2552->mclk;
j = (pll_clk * 2 * (1 << p)) / tas2552->pll_clkin;
d = (pll_clk * 2 * (1 << p)) % tas2552->pll_clkin;
snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
TAS2552_PLL_J_MASK, j);
@ -185,56 +290,74 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
return 0;
}
#define TAS2552_DAI_FMT_MASK (TAS2552_BCLKDIR | \
TAS2552_WCLKDIR | \
TAS2552_DATAFORMAT_MASK)
static int tas2552_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
int delay = 0;
/* TDM slot selection only valid in DSP_A/_B mode */
if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_A)
delay += (tas2552->tdm_delay + 1);
else if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_B)
delay += tas2552->tdm_delay;
/* Configure data delay */
snd_soc_write(codec, TAS2552_SER_CTRL_2, delay);
return 0;
}
static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
u8 serial_format;
u8 serial_control_mask;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
serial_format = 0x00;
break;
case SND_SOC_DAIFMT_CBS_CFM:
serial_format = TAS2552_WORD_CLK_MASK;
serial_format = TAS2552_WCLKDIR;
break;
case SND_SOC_DAIFMT_CBM_CFS:
serial_format = TAS2552_BIT_CLK_MASK;
serial_format = TAS2552_BCLKDIR;
break;
case SND_SOC_DAIFMT_CBM_CFM:
serial_format = (TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK);
serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR);
break;
default:
dev_vdbg(codec->dev, "DAI Format master is not found\n");
return -EINVAL;
}
serial_control_mask = TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
serial_format &= TAS2552_DAIFMT_I2S_MASK;
switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
SND_SOC_DAIFMT_INV_MASK)) {
case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
break;
case SND_SOC_DAIFMT_DSP_A:
serial_format |= TAS2552_DAIFMT_DSP;
case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
serial_format |= TAS2552_DATAFORMAT_DSP;
break;
case SND_SOC_DAIFMT_RIGHT_J:
serial_format |= TAS2552_DAIFMT_RIGHT_J;
case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF):
serial_format |= TAS2552_DATAFORMAT_RIGHT_J;
break;
case SND_SOC_DAIFMT_LEFT_J:
serial_format |= TAS2552_DAIFMT_LEFT_J;
case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
serial_format |= TAS2552_DATAFORMAT_LEFT_J;
break;
default:
dev_vdbg(codec->dev, "DAI Format is not found\n");
return -EINVAL;
}
tas2552->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
if (fmt & SND_SOC_DAIFMT_FORMAT_MASK)
serial_control_mask |= TAS2552_DATA_FORMAT_MASK;
snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, serial_control_mask,
serial_format);
snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, TAS2552_DAI_FMT_MASK,
serial_format);
return 0;
}
@ -243,23 +366,75 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
{
struct snd_soc_codec *codec = dai->codec;
struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
u8 reg, mask, val;
tas2552->mclk = freq;
switch (clk_id) {
case TAS2552_PLL_CLKIN_MCLK:
case TAS2552_PLL_CLKIN_BCLK:
case TAS2552_PLL_CLKIN_IVCLKIN:
case TAS2552_PLL_CLKIN_1_8_FIXED:
mask = TAS2552_PLL_SRC_MASK;
val = (clk_id << 3) & mask; /* bit 4:5 in the register */
reg = TAS2552_CFG_1;
tas2552->pll_clkin = freq;
break;
case TAS2552_PDM_CLK_PLL:
case TAS2552_PDM_CLK_IVCLKIN:
case TAS2552_PDM_CLK_BCLK:
case TAS2552_PDM_CLK_MCLK:
mask = TAS2552_PDM_CLK_SEL_MASK;
val = (clk_id >> 1) & mask; /* bit 0:1 in the register */
reg = TAS2552_PDM_CFG;
tas2552->pdm_clk = freq;
break;
default:
dev_err(codec->dev, "Invalid clk id: %d\n", clk_id);
return -EINVAL;
}
snd_soc_update_bits(codec, reg, mask, val);
return 0;
}
static int tas2552_set_dai_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width)
{
struct snd_soc_codec *codec = dai->codec;
struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
unsigned int lsb;
if (unlikely(!tx_mask)) {
dev_err(codec->dev, "tx masks need to be non 0\n");
return -EINVAL;
}
/* TDM based on DSP mode requires slots to be adjacent */
lsb = __ffs(tx_mask);
if ((lsb + 1) != __fls(tx_mask)) {
dev_err(codec->dev, "Invalid mask, slots must be adjacent\n");
return -EINVAL;
}
tas2552->tdm_delay = lsb * slot_width;
/* DOUT in high-impedance on inactive bit clocks */
snd_soc_update_bits(codec, TAS2552_DOUT,
TAS2552_SDOUT_TRISTATE, TAS2552_SDOUT_TRISTATE);
return 0;
}
static int tas2552_mute(struct snd_soc_dai *dai, int mute)
{
u8 cfg1_reg;
u8 cfg1_reg = 0;
struct snd_soc_codec *codec = dai->codec;
if (mute)
cfg1_reg = TAS2552_MUTE_MASK;
else
cfg1_reg = ~TAS2552_MUTE_MASK;
cfg1_reg |= TAS2552_MUTE;
snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK, cfg1_reg);
snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, cfg1_reg);
return 0;
}
@ -269,7 +444,7 @@ static int tas2552_runtime_suspend(struct device *dev)
{
struct tas2552_data *tas2552 = dev_get_drvdata(dev);
tas2552_sw_shutdown(tas2552, 0);
tas2552_sw_shutdown(tas2552, 1);
regcache_cache_only(tas2552->regmap, true);
regcache_mark_dirty(tas2552->regmap);
@ -287,7 +462,7 @@ static int tas2552_runtime_resume(struct device *dev)
if (tas2552->enable_gpio)
gpiod_set_value(tas2552->enable_gpio, 1);
tas2552_sw_shutdown(tas2552, 1);
tas2552_sw_shutdown(tas2552, 0);
regcache_cache_only(tas2552->regmap, false);
regcache_sync(tas2552->regmap);
@ -303,8 +478,10 @@ static const struct dev_pm_ops tas2552_pm = {
static struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
.hw_params = tas2552_hw_params,
.prepare = tas2552_prepare,
.set_sysclk = tas2552_set_dai_sysclk,
.set_fmt = tas2552_set_dai_fmt,
.set_tdm_slot = tas2552_set_dai_tdm_slot,
.digital_mute = tas2552_mute,
};
@ -330,16 +507,11 @@ static struct snd_soc_dai_driver tas2552_dai[] = {
/*
* DAC digital volumes. From -7 to 24 dB in 1 dB steps
*/
static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24);
static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 0);
static const struct snd_kcontrol_new tas2552_snd_controls[] = {
SOC_SINGLE_TLV("Speaker Driver Playback Volume",
TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv),
SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM, 0, 1, 0),
};
static const struct reg_default tas2552_init_regs[] = {
{ TAS2552_RESERVED_0D, 0xc0 },
TAS2552_PGA_GAIN, 0, 0x1f, 0, dac_tlv),
};
static int tas2552_codec_probe(struct snd_soc_codec *codec)
@ -368,31 +540,19 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
goto probe_fail;
}
snd_soc_write(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK |
TAS2552_PLL_SRC_BCLK);
snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE);
snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
TAS2552_DIN_SRC_SEL_AVG_L_R | TAS2552_88_96KHZ);
TAS2552_DIN_SRC_SEL_AVG_L_R);
snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I);
snd_soc_write(codec, TAS2552_OUTPUT_DATA, TAS2552_PDM_DATA_V_I | 0x8);
snd_soc_write(codec, TAS2552_PDM_CFG, TAS2552_PDM_BCLK_SEL);
snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 |
TAS2552_APT_THRESH_2_1_7);
ret = regmap_register_patch(tas2552->regmap, tas2552_init_regs,
ARRAY_SIZE(tas2552_init_regs));
if (ret != 0) {
dev_err(codec->dev, "Failed to write init registers: %d\n",
ret);
goto patch_fail;
}
snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN |
TAS2552_APT_EN | TAS2552_LIM_EN);
return 0;
patch_fail:
pm_runtime_put(codec->dev);
probe_fail:
if (tas2552->enable_gpio)
gpiod_set_value(tas2552->enable_gpio, 0);
@ -454,6 +614,8 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
.remove = tas2552_codec_remove,
.suspend = tas2552_suspend,
.resume = tas2552_resume,
.ignore_pmdown_time = true,
.controls = tas2552_snd_controls,
.num_controls = ARRAY_SIZE(tas2552_snd_controls),
.dapm_widgets = tas2552_dapm_widgets,
@ -486,8 +648,12 @@ static int tas2552_probe(struct i2c_client *client,
return -ENOMEM;
data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(data->enable_gpio))
return PTR_ERR(data->enable_gpio);
if (IS_ERR(data->enable_gpio)) {
if (PTR_ERR(data->enable_gpio) == -EPROBE_DEFER)
return -EPROBE_DEFER;
data->enable_gpio = NULL;;
}
data->tas2552_client = client;
data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);

View File

@ -45,10 +45,14 @@
#define TAS2552_MAX_REG 0x20
/* CFG1 Register Masks */
#define TAS2552_MUTE_MASK (1 << 2)
#define TAS2552_SWS_MASK (1 << 1)
#define TAS2552_WCLK_MASK 0x07
#define TAS2552_CLASSD_EN_MASK (1 << 7)
#define TAS2552_DEV_RESET (1 << 0)
#define TAS2552_SWS (1 << 1)
#define TAS2552_MUTE (1 << 2)
#define TAS2552_PLL_SRC_MCLK (0x0 << 4)
#define TAS2552_PLL_SRC_BCLK (0x1 << 4)
#define TAS2552_PLL_SRC_IVCLKIN (0x2 << 4)
#define TAS2552_PLL_SRC_1_8_FIXED (0x3 << 4)
#define TAS2552_PLL_SRC_MASK TAS2552_PLL_SRC_1_8_FIXED
/* CFG2 Register Masks */
#define TAS2552_CLASSD_EN (1 << 7)
@ -59,38 +63,44 @@
#define TAS2552_IVSENSE_EN (1 << 1)
/* CFG3 Register Masks */
#define TAS2552_WORD_CLK_MASK (1 << 7)
#define TAS2552_BIT_CLK_MASK (1 << 6)
#define TAS2552_DATA_FORMAT_MASK (0x11 << 2)
#define TAS2552_DAIFMT_I2S_MASK 0xf3
#define TAS2552_DAIFMT_DSP (1 << 3)
#define TAS2552_DAIFMT_RIGHT_J (1 << 4)
#define TAS2552_DAIFMT_LEFT_J (0x11 << 3)
#define TAS2552_PLL_SRC_MCLK 0x00
#define TAS2552_PLL_SRC_BCLK (1 << 3)
#define TAS2552_PLL_SRC_IVCLKIN (1 << 4)
#define TAS2552_PLL_SRC_1_8_FIXED (0x11 << 3)
#define TAS2552_DIN_SRC_SEL_MUTED 0x00
#define TAS2552_DIN_SRC_SEL_LEFT (1 << 4)
#define TAS2552_DIN_SRC_SEL_RIGHT (1 << 5)
#define TAS2552_DIN_SRC_SEL_AVG_L_R (0x11 << 4)
#define TAS2552_WCLK_FREQ_8KHZ (0x0 << 0)
#define TAS2552_WCLK_FREQ_11_12KHZ (0x1 << 0)
#define TAS2552_WCLK_FREQ_16KHZ (0x2 << 0)
#define TAS2552_WCLK_FREQ_22_24KHZ (0x3 << 0)
#define TAS2552_WCLK_FREQ_32KHZ (0x4 << 0)
#define TAS2552_WCLK_FREQ_44_48KHZ (0x5 << 0)
#define TAS2552_WCLK_FREQ_88_96KHZ (0x6 << 0)
#define TAS2552_WCLK_FREQ_176_192KHZ (0x7 << 0)
#define TAS2552_WCLK_FREQ_MASK TAS2552_WCLK_FREQ_176_192KHZ
#define TAS2552_DIN_SRC_SEL_MUTED (0x0 << 3)
#define TAS2552_DIN_SRC_SEL_LEFT (0x1 << 3)
#define TAS2552_DIN_SRC_SEL_RIGHT (0x2 << 3)
#define TAS2552_DIN_SRC_SEL_AVG_L_R (0x3 << 3)
#define TAS2552_PDM_IN_SEL (1 << 5)
#define TAS2552_I2S_OUT_SEL (1 << 6)
#define TAS2552_ANALOG_IN_SEL (1 << 7)
#define TAS2552_ANALOG_IN_SEL (1 << 7)
/* CFG3 WCLK Dividers */
#define TAS2552_8KHZ 0x00
#define TAS2552_11_12KHZ (1 << 1)
#define TAS2552_16KHZ (1 << 2)
#define TAS2552_22_24KHZ (1 << 3)
#define TAS2552_32KHZ (1 << 4)
#define TAS2552_44_48KHZ (1 << 5)
#define TAS2552_88_96KHZ (1 << 6)
#define TAS2552_176_192KHZ (1 << 7)
/* DOUT Register Masks */
#define TAS2552_SDOUT_TRISTATE (1 << 2)
/* Serial Interface Control Register Masks */
#define TAS2552_WORDLENGTH_16BIT (0x0 << 0)
#define TAS2552_WORDLENGTH_20BIT (0x1 << 0)
#define TAS2552_WORDLENGTH_24BIT (0x2 << 0)
#define TAS2552_WORDLENGTH_32BIT (0x3 << 0)
#define TAS2552_WORDLENGTH_MASK TAS2552_WORDLENGTH_32BIT
#define TAS2552_DATAFORMAT_I2S (0x0 << 2)
#define TAS2552_DATAFORMAT_DSP (0x1 << 2)
#define TAS2552_DATAFORMAT_RIGHT_J (0x2 << 2)
#define TAS2552_DATAFORMAT_LEFT_J (0x3 << 2)
#define TAS2552_DATAFORMAT_MASK TAS2552_DATAFORMAT_LEFT_J
#define TAS2552_CLKSPERFRAME_32 (0x0 << 4)
#define TAS2552_CLKSPERFRAME_64 (0x1 << 4)
#define TAS2552_CLKSPERFRAME_128 (0x2 << 4)
#define TAS2552_CLKSPERFRAME_256 (0x3 << 4)
#define TAS2552_CLKSPERFRAME_MASK TAS2552_CLKSPERFRAME_256
#define TAS2552_BCLKDIR (1 << 6)
#define TAS2552_WCLKDIR (1 << 7)
/* OUTPUT_DATA register */
#define TAS2552_PDM_DATA_I 0x00
@ -99,12 +109,12 @@
#define TAS2552_PDM_DATA_V_I (0x11 << 6)
/* PDM CFG Register */
#define TAS2552_PDM_DATA_ES_RISE 0x4
#define TAS2552_PDM_PLL_CLK_SEL 0x00
#define TAS2552_PDM_IV_CLK_SEL (1 << 1)
#define TAS2552_PDM_BCLK_SEL (1 << 2)
#define TAS2552_PDM_MCLK_SEL (1 << 3)
#define TAS2552_PDM_CLK_SEL_PLL (0x0 << 0)
#define TAS2552_PDM_CLK_SEL_IVCLKIN (0x1 << 0)
#define TAS2552_PDM_CLK_SEL_BCLK (0x2 << 0)
#define TAS2552_PDM_CLK_SEL_MCLK (0x3 << 0)
#define TAS2552_PDM_CLK_SEL_MASK TAS2552_PDM_CLK_SEL_MCLK
#define TAS2552_PDM_DATA_ES (1 << 2)
/* Boost pass-through register */
#define TAS2552_APT_DELAY_50 0x00

Some files were not shown because too many files have changed in this diff Show More