summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/88pm860x-codec.c3
-rw-r--r--sound/soc/codecs/Kconfig12
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ab8500-codec.c20
-rw-r--r--sound/soc/codecs/ac97.c8
-rw-r--r--sound/soc/codecs/ad1836.c2
-rw-r--r--sound/soc/codecs/adau1373.c1
-rw-r--r--sound/soc/codecs/adau1701.c126
-rw-r--r--sound/soc/codecs/adau1761.c27
-rw-r--r--sound/soc/codecs/adau1781.c10
-rw-r--r--sound/soc/codecs/adau17x1.c20
-rw-r--r--sound/soc/codecs/adau1977.c14
-rw-r--r--sound/soc/codecs/adav80x.c11
-rw-r--r--sound/soc/codecs/ak4535.c1
-rw-r--r--sound/soc/codecs/ak4641.c3
-rw-r--r--sound/soc/codecs/ak4642.c1
-rw-r--r--sound/soc/codecs/ak4671.c1
-rw-r--r--sound/soc/codecs/alc5623.c3
-rw-r--r--sound/soc/codecs/alc5632.c1
-rw-r--r--sound/soc/codecs/arizona.c174
-rw-r--r--sound/soc/codecs/arizona.h17
-rw-r--r--sound/soc/codecs/bt-sco.c11
-rw-r--r--sound/soc/codecs/cq93vc.c1
-rw-r--r--sound/soc/codecs/cs35l32.c1
-rw-r--r--sound/soc/codecs/cs4265.c1
-rw-r--r--sound/soc/codecs/cs42l52.c5
-rw-r--r--sound/soc/codecs/cs42l56.c5
-rw-r--r--sound/soc/codecs/cs42l73.c3
-rw-r--r--sound/soc/codecs/cs42xx8.c2
-rw-r--r--sound/soc/codecs/cx20442.c6
-rw-r--r--sound/soc/codecs/da7213.c3
-rw-r--r--sound/soc/codecs/da732x.c4
-rw-r--r--sound/soc/codecs/da9055.c3
-rw-r--r--sound/soc/codecs/es8328.c3
-rw-r--r--sound/soc/codecs/isabelle.c2
-rw-r--r--sound/soc/codecs/jz4740.c4
-rw-r--r--sound/soc/codecs/lm4857.c114
-rw-r--r--sound/soc/codecs/lm49453.c4
-rw-r--r--sound/soc/codecs/max98088.c3
-rw-r--r--sound/soc/codecs/max98090.c34
-rw-r--r--sound/soc/codecs/max98095.c24
-rw-r--r--sound/soc/codecs/max98357a.c3
-rw-r--r--sound/soc/codecs/max9850.c3
-rw-r--r--sound/soc/codecs/ml26124.c3
-rw-r--r--sound/soc/codecs/pcm512x.c8
-rw-r--r--sound/soc/codecs/rt286.c33
-rw-r--r--sound/soc/codecs/rt5631.c5
-rw-r--r--sound/soc/codecs/rt5640.c16
-rw-r--r--sound/soc/codecs/rt5645.c1081
-rw-r--r--sound/soc/codecs/rt5645.h30
-rw-r--r--sound/soc/codecs/rt5651.c5
-rw-r--r--sound/soc/codecs/rt5670.c26
-rw-r--r--sound/soc/codecs/rt5677.c157
-rw-r--r--sound/soc/codecs/rt5677.h15
-rw-r--r--sound/soc/codecs/sgtl5000.c56
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c2
-rw-r--r--sound/soc/codecs/sn95031.c12
-rw-r--r--sound/soc/codecs/ssm2518.c9
-rw-r--r--sound/soc/codecs/ssm2602.c5
-rw-r--r--sound/soc/codecs/ssm4567.c9
-rw-r--r--sound/soc/codecs/sta32x.c19
-rw-r--r--sound/soc/codecs/sta350.c9
-rw-r--r--sound/soc/codecs/sta529.c8
-rw-r--r--sound/soc/codecs/stac9766.c1
-rw-r--r--sound/soc/codecs/tas2552.c312
-rw-r--r--sound/soc/codecs/tas2552.h90
-rw-r--r--sound/soc/codecs/tas571x.c514
-rw-r--r--sound/soc/codecs/tas571x.h33
-rw-r--r--sound/soc/codecs/tlv320aic23.c1
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c11
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c1
-rw-r--r--sound/soc/codecs/tlv320aic3x.c10
-rw-r--r--sound/soc/codecs/tlv320dac33.c5
-rw-r--r--sound/soc/codecs/ts3a227e.c15
-rw-r--r--sound/soc/codecs/twl4030.c3
-rw-r--r--sound/soc/codecs/twl6040.c9
-rw-r--r--sound/soc/codecs/uda134x.c4
-rw-r--r--sound/soc/codecs/uda1380.c6
-rw-r--r--sound/soc/codecs/wm0010.c6
-rw-r--r--sound/soc/codecs/wm1250-ev1.c2
-rw-r--r--sound/soc/codecs/wm5100.c12
-rw-r--r--sound/soc/codecs/wm5102.c60
-rw-r--r--sound/soc/codecs/wm5110.c9
-rw-r--r--sound/soc/codecs/wm8350.c3
-rw-r--r--sound/soc/codecs/wm8400.c3
-rw-r--r--sound/soc/codecs/wm8510.c3
-rw-r--r--sound/soc/codecs/wm8523.c3
-rw-r--r--sound/soc/codecs/wm8580.c3
-rw-r--r--sound/soc/codecs/wm8711.c3
-rw-r--r--sound/soc/codecs/wm8728.c3
-rw-r--r--sound/soc/codecs/wm8731.c8
-rw-r--r--sound/soc/codecs/wm8737.c5
-rw-r--r--sound/soc/codecs/wm8741.c129
-rw-r--r--sound/soc/codecs/wm8741.h10
-rw-r--r--sound/soc/codecs/wm8750.c3
-rw-r--r--sound/soc/codecs/wm8753.c3
-rw-r--r--sound/soc/codecs/wm8770.c3
-rw-r--r--sound/soc/codecs/wm8776.c3
-rw-r--r--sound/soc/codecs/wm8804.c2
-rw-r--r--sound/soc/codecs/wm8900.c9
-rw-r--r--sound/soc/codecs/wm8903.c4
-rw-r--r--sound/soc/codecs/wm8904.c5
-rw-r--r--sound/soc/codecs/wm8940.c6
-rw-r--r--sound/soc/codecs/wm8955.c5
-rw-r--r--sound/soc/codecs/wm8960.c125
-rw-r--r--sound/soc/codecs/wm8961.c6
-rw-r--r--sound/soc/codecs/wm8962.c21
-rw-r--r--sound/soc/codecs/wm8971.c3
-rw-r--r--sound/soc/codecs/wm8974.c3
-rw-r--r--sound/soc/codecs/wm8978.c7
-rw-r--r--sound/soc/codecs/wm8983.c3
-rw-r--r--sound/soc/codecs/wm8985.c3
-rw-r--r--sound/soc/codecs/wm8988.c3
-rw-r--r--sound/soc/codecs/wm8990.c5
-rw-r--r--sound/soc/codecs/wm8991.c3
-rw-r--r--sound/soc/codecs/wm8993.c12
-rw-r--r--sound/soc/codecs/wm8994.c68
-rw-r--r--sound/soc/codecs/wm8995.c6
-rw-r--r--sound/soc/codecs/wm8996.c23
-rw-r--r--sound/soc/codecs/wm8997.c16
-rw-r--r--sound/soc/codecs/wm9081.c4
-rw-r--r--sound/soc/codecs/wm9090.c6
-rw-r--r--sound/soc/codecs/wm9712.c3
-rw-r--r--sound/soc/codecs/wm9713.c3
-rw-r--r--sound/soc/codecs/wm_adsp.c1210
-rw-r--r--sound/soc/codecs/wm_adsp.h19
-rw-r--r--sound/soc/codecs/wm_hubs.c4
-rw-r--r--sound/soc/codecs/wmfw.h44
128 files changed, 3615 insertions, 1509 deletions
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index f62da48eda9a..38b3dad9d48a 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -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;
}
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 061c46587628..9b36011a814e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -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
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index abe2d7edf65c..3dcf5ac85e89 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -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
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 88ca9cb0ce79..c7d243db010a 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -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);
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index d0ac723eee32..5b3224c63943 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -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,
};
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 685998dd086e..95f0bec26a1b 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -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;
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 783dcb57043a..a43160254929 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -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;
}
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index d4e219b6b98f..ff7f846e3b76 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -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;
}
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index a1baeee160f4..2f12477e539e 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -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;
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
index 35581f43fa6d..fde9068550a6 100644
--- a/sound/soc/codecs/adau1781.c
+++ b/sound/soc/codecs/adau1781.c
@@ -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;
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index fa2e690e51c8..fcf05b254ecd 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -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;
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index 7ad8e156e2df..9bdd15f408c1 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -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)
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 4373ada95648..36d842570745 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -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);
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 9130d916f2f4..8670861e5bec 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -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;
}
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 81b54a270bd8..2d0ff4595ea0 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -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;
}
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 13585e88f597..7c0f6552c229 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -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;
}
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 2a58b1dccd2f..0e59063aeb6f 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -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;
}
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index 0e357996864b..0fc24e0d518c 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -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);
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index db3283abbe18..607a63b9705f 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -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;
}
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index eff4b4d512b7..88f6df21ad95 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -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)
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 11ff899b0272..84e119a56515 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -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,
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index e7238b8904bc..b084ad113e96 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -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,
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index d6dedd4eab29..1c895a53001d 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -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;
}
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index 60598b230341..8f40025b7e7c 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -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>
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index cac48ddf3ba6..d7ec4756e45b 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -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;
}
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 1589e7a881d8..4de52c9957ac 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -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;
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index cbc654fe48c7..1e11ba45a79f 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -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;
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 8ecedba79606..b7853b9d3a60 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -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;
}
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index 670ebfe12903..e1d46862e81f 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -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:
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 0f334bc1b63c..d6f4abbbf8a7 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -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;
}
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 9ec577f0edb4..238e48a3a4fe 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -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;
}
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 911c26c705fc..207523686bd5 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -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;
}
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index ad19cc56702b..66bb446473b8 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -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;
}
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index c5f35a07e8e4..6a091016e0fc 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -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;
}
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index 3a89ce66d51d..ebd90283c960 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -909,8 +909,6 @@ static int isabelle_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 933f4476d76c..9363fdbca9cd 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -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;
}
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index a924bb9d7886..99ffc49aa779 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -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);
-
- 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 unsigned int lm4857_mode_values[] = {
+ 0,
+ 6,
+ 7,
+ 8,
+ 9,
+};
-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;
-
- lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL);
- if (!lm4857)
- return -ENOMEM;
-
- 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);
+ struct regmap *regmap;
- return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
-}
+ regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
-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,
};
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index c4dfde9bdf1c..6600aa0a33dc 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -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;
}
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 805b3f8cd39d..d0f45348bfbb 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -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;
}
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 3e33ef2acf3c..679f0a0f7039 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -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);
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 8fba0c3db798..9a46d3dcf703 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -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;
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index bf3e933ee895..3a2fda08a893 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -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;
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index 10f8e47ce2c2..481d58f1cb3f 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -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;
}
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 711f55039522..62dda2488f14 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -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;
}
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index e12764d15431..de16429f0a43 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -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;
}
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 0fcda35a3a93..c6cca0639e0d 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -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;
}
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 2c10d77727af..058167c80d71 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -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;
}
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 178e55d4d481..f40752a6c242 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -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);
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index c82301484156..d5f0f5680d3b 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -18,7 +18,9 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
+#include <linux/dmi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -415,9 +417,9 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
}
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
-static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
@@ -432,30 +434,6 @@ static unsigned int bst_tlv[] = {
8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
};
-static const char * const rt5645_tdm_data_swap_select[] = {
- "L/R", "R/L", "L/L", "R/R"
-};
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum,
- RT5645_TDM_CTRL_1, 6, rt5645_tdm_data_swap_select);
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum,
- RT5645_TDM_CTRL_1, 4, rt5645_tdm_data_swap_select);
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum,
- RT5645_TDM_CTRL_1, 2, rt5645_tdm_data_swap_select);
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot6_7_enum,
- RT5645_TDM_CTRL_1, 0, rt5645_tdm_data_swap_select);
-
-static const char * const rt5645_tdm_adc_data_select[] = {
- "1/2/R", "2/1/R", "R/1/2", "R/2/1"
-};
-
-static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_sel_enum,
- RT5645_TDM_CTRL_1, 8,
- rt5645_tdm_adc_data_select);
-
static const struct snd_kcontrol_new rt5645_snd_controls[] = {
/* Speaker Output Volume */
SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL,
@@ -481,9 +459,9 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
SOC_DOUBLE("DAC2 Playback Switch", RT5645_DAC_CTRL,
RT5645_M_DAC_L2_VOL_SFT, RT5645_M_DAC_R2_VOL_SFT, 1, 1),
SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5645_DAC1_DIG_VOL,
- RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv),
+ RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv),
SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5645_DAC2_DIG_VOL,
- RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 175, 0, dac_vol_tlv),
+ RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 87, 0, dac_vol_tlv),
/* IN1/IN2 Control */
SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1,
@@ -499,11 +477,11 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
SOC_DOUBLE("ADC Capture Switch", RT5645_STO1_ADC_DIG_VOL,
RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
SOC_DOUBLE_TLV("ADC Capture Volume", RT5645_STO1_ADC_DIG_VOL,
- RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv),
+ RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv),
SOC_DOUBLE("Mono ADC Capture Switch", RT5645_MONO_ADC_DIG_VOL,
RT5645_L_MUTE_SFT, RT5645_R_MUTE_SFT, 1, 1),
SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5645_MONO_ADC_DIG_VOL,
- RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 127, 0, adc_vol_tlv),
+ RT5645_L_VOL_SFT + 1, RT5645_R_VOL_SFT + 1, 63, 0, adc_vol_tlv),
/* ADC Boost Volume Control */
SOC_DOUBLE_TLV("STO1 ADC Boost Gain", RT5645_ADC_BST_VOL1,
@@ -516,17 +494,6 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
/* I2S2 function select */
SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT,
1, 1),
-
- /* TDM */
- SOC_ENUM("TDM Adc Slot0 1 Data", rt5645_tdm_adc_slot0_1_enum),
- SOC_ENUM("TDM Adc Slot2 3 Data", rt5645_tdm_adc_slot2_3_enum),
- SOC_ENUM("TDM Adc Slot4 5 Data", rt5645_tdm_adc_slot4_5_enum),
- SOC_ENUM("TDM Adc Slot6 7 Data", rt5645_tdm_adc_slot6_7_enum),
- SOC_ENUM("TDM IF1 ADC DATA Sel", rt5645_tdm_adc_sel_enum),
- SOC_SINGLE("TDM IF1_DAC1_L Sel", RT5645_TDM_CTRL_3, 12, 7, 0),
- SOC_SINGLE("TDM IF1_DAC1_R Sel", RT5645_TDM_CTRL_3, 8, 7, 0),
- SOC_SINGLE("TDM IF1_DAC2_L Sel", RT5645_TDM_CTRL_3, 4, 7, 0),
- SOC_SINGLE("TDM IF1_DAC2_R Sel", RT5645_TDM_CTRL_3, 0, 7, 0),
};
/**
@@ -1093,7 +1060,8 @@ static const struct snd_kcontrol_new rt5645_mono_adc_r2_mux =
/* MX-77 [9:8] */
static const char * const rt5645_if1_adc_in_src[] = {
- "IF_ADC1", "IF_ADC2", "VAD_ADC"
+ "IF_ADC1/IF_ADC2/VAD_ADC", "IF_ADC2/IF_ADC1/VAD_ADC",
+ "VAD_ADC/IF_ADC1/IF_ADC2", "VAD_ADC/IF_ADC2/IF_ADC1"
};
static SOC_ENUM_SINGLE_DECL(
@@ -1103,6 +1071,140 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
+/* MX-78 [4:0] */
+static const char * const rt5650_if1_adc_in_src[] = {
+ "IF_ADC1/IF_ADC2/DAC_REF/Null",
+ "IF_ADC1/IF_ADC2/Null/DAC_REF",
+ "IF_ADC1/DAC_REF/IF_ADC2/Null",
+ "IF_ADC1/DAC_REF/Null/IF_ADC2",
+ "IF_ADC1/Null/DAC_REF/IF_ADC2",
+ "IF_ADC1/Null/IF_ADC2/DAC_REF",
+
+ "IF_ADC2/IF_ADC1/DAC_REF/Null",
+ "IF_ADC2/IF_ADC1/Null/DAC_REF",
+ "IF_ADC2/DAC_REF/IF_ADC1/Null",
+ "IF_ADC2/DAC_REF/Null/IF_ADC1",
+ "IF_ADC2/Null/DAC_REF/IF_ADC1",
+ "IF_ADC2/Null/IF_ADC1/DAC_REF",
+
+ "DAC_REF/IF_ADC1/IF_ADC2/Null",
+ "DAC_REF/IF_ADC1/Null/IF_ADC2",
+ "DAC_REF/IF_ADC2/IF_ADC1/Null",
+ "DAC_REF/IF_ADC2/Null/IF_ADC1",
+ "DAC_REF/Null/IF_ADC1/IF_ADC2",
+ "DAC_REF/Null/IF_ADC2/IF_ADC1",
+
+ "Null/IF_ADC1/IF_ADC2/DAC_REF",
+ "Null/IF_ADC1/DAC_REF/IF_ADC2",
+ "Null/IF_ADC2/IF_ADC1/DAC_REF",
+ "Null/IF_ADC2/DAC_REF/IF_ADC1",
+ "Null/DAC_REF/IF_ADC1/IF_ADC2",
+ "Null/DAC_REF/IF_ADC2/IF_ADC1",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5650_if1_adc_in_enum, RT5645_TDM_CTRL_2,
+ 0, rt5650_if1_adc_in_src);
+
+static const struct snd_kcontrol_new rt5650_if1_adc_in_mux =
+ SOC_DAPM_ENUM("IF1 ADC IN source", rt5650_if1_adc_in_enum);
+
+/* MX-78 [15:14][13:12][11:10] */
+static const char * const rt5645_tdm_adc_swap_select[] = {
+ "L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot0_1_enum,
+ RT5645_TDM_CTRL_2, 14, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc1_in_mux =
+ SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5650_tdm_adc_slot0_1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot2_3_enum,
+ RT5645_TDM_CTRL_2, 12, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc2_in_mux =
+ SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5650_tdm_adc_slot2_3_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_adc_slot4_5_enum,
+ RT5645_TDM_CTRL_2, 10, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_adc3_in_mux =
+ SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5650_tdm_adc_slot4_5_enum);
+
+/* MX-77 [7:6][5:4][3:2] */
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot0_1_enum,
+ RT5645_TDM_CTRL_1, 6, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc1_in_mux =
+ SOC_DAPM_ENUM("IF1 ADC1 IN source", rt5645_tdm_adc_slot0_1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot2_3_enum,
+ RT5645_TDM_CTRL_1, 4, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc2_in_mux =
+ SOC_DAPM_ENUM("IF1 ADC2 IN source", rt5645_tdm_adc_slot2_3_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_adc_slot4_5_enum,
+ RT5645_TDM_CTRL_1, 2, rt5645_tdm_adc_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_adc3_in_mux =
+ SOC_DAPM_ENUM("IF1 ADC3 IN source", rt5645_tdm_adc_slot4_5_enum);
+
+/* MX-79 [14:12][10:8][6:4][2:0] */
+static const char * const rt5645_tdm_dac_swap_select[] = {
+ "Slot0", "Slot1", "Slot2", "Slot3"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac0_enum,
+ RT5645_TDM_CTRL_3, 12, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac0_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC0 source", rt5645_tdm_dac0_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac1_enum,
+ RT5645_TDM_CTRL_3, 8, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac1_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC1 source", rt5645_tdm_dac1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac2_enum,
+ RT5645_TDM_CTRL_3, 4, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac2_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC2 source", rt5645_tdm_dac2_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5645_tdm_dac3_enum,
+ RT5645_TDM_CTRL_3, 0, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5645_if1_dac3_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC3 source", rt5645_tdm_dac3_enum);
+
+/* MX-7a [14:12][10:8][6:4][2:0] */
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac0_enum,
+ RT5650_TDM_CTRL_4, 12, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac0_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC0 source", rt5650_tdm_dac0_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac1_enum,
+ RT5650_TDM_CTRL_4, 8, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac1_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC1 source", rt5650_tdm_dac1_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac2_enum,
+ RT5650_TDM_CTRL_4, 4, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac2_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC2 source", rt5650_tdm_dac2_enum);
+
+static SOC_ENUM_SINGLE_DECL(rt5650_tdm_dac3_enum,
+ RT5650_TDM_CTRL_4, 0, rt5645_tdm_dac_swap_select);
+
+static const struct snd_kcontrol_new rt5650_if1_dac3_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC3 source", rt5650_tdm_dac3_enum);
+
/* MX-2d [3] [2] */
static const char * const rt5650_a_dac1_src[] = {
"DAC1", "Stereo DAC Mixer"
@@ -1227,52 +1329,79 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
if (on) {
if (hp_amp_power_count <= 0) {
- /* depop parameters */
- snd_soc_update_bits(codec, RT5645_DEPOP_M2,
- RT5645_DEPOP_MASK, RT5645_DEPOP_MAN);
- snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
- regmap_write(rt5645->regmap, RT5645_PR_BASE +
- RT5645_HP_DCC_INT1, 0x9f01);
- mdelay(150);
- /* headphone amp power on */
- snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
- RT5645_PWR_FV1 | RT5645_PWR_FV2 , 0);
- snd_soc_update_bits(codec, RT5645_PWR_VOL,
- RT5645_PWR_HV_L | RT5645_PWR_HV_R,
- RT5645_PWR_HV_L | RT5645_PWR_HV_R);
- snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
- RT5645_PWR_HP_L | RT5645_PWR_HP_R |
- RT5645_PWR_HA,
- RT5645_PWR_HP_L | RT5645_PWR_HP_R |
- RT5645_PWR_HA);
- mdelay(5);
- snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
- RT5645_PWR_FV1 | RT5645_PWR_FV2,
- RT5645_PWR_FV1 | RT5645_PWR_FV2);
-
- snd_soc_update_bits(codec, RT5645_DEPOP_M1,
- RT5645_HP_CO_MASK | RT5645_HP_SG_MASK,
- RT5645_HP_CO_EN | RT5645_HP_SG_EN);
- regmap_write(rt5645->regmap, RT5645_PR_BASE +
- 0x14, 0x1aaa);
- regmap_write(rt5645->regmap, RT5645_PR_BASE +
- 0x24, 0x0430);
+ if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+ snd_soc_write(codec, RT5645_CHARGE_PUMP,
+ 0x0e06);
+ snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ 0x3e, 0x7400);
+ snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ RT5645_MAMP_INT_REG2, 0xfc00);
+ snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+ } else {
+ /* depop parameters */
+ snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+ RT5645_DEPOP_MASK, RT5645_DEPOP_MAN);
+ snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ RT5645_HP_DCC_INT1, 0x9f01);
+ mdelay(150);
+ /* headphone amp power on */
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2, 0);
+ snd_soc_update_bits(codec, RT5645_PWR_VOL,
+ RT5645_PWR_HV_L | RT5645_PWR_HV_R,
+ RT5645_PWR_HV_L | RT5645_PWR_HV_R);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+ RT5645_PWR_HA,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+ RT5645_PWR_HA);
+ mdelay(5);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2);
+
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_HP_CO_MASK | RT5645_HP_SG_MASK,
+ RT5645_HP_CO_EN | RT5645_HP_SG_EN);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ 0x14, 0x1aaa);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ 0x24, 0x0430);
+ }
}
hp_amp_power_count++;
} else {
hp_amp_power_count--;
if (hp_amp_power_count <= 0) {
- snd_soc_update_bits(codec, RT5645_DEPOP_M1,
- RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
- RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
- RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
- /* headphone amp power down */
- snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000);
- snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
- RT5645_PWR_HP_L | RT5645_PWR_HP_R |
- RT5645_PWR_HA, 0);
- snd_soc_update_bits(codec, RT5645_DEPOP_M2,
- RT5645_DEPOP_MASK, 0);
+ if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ 0x3e, 0x7400);
+ snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ RT5645_MAMP_INT_REG2, 0xfc00);
+ snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+ msleep(100);
+ snd_soc_write(codec, RT5645_DEPOP_M1, 0x0001);
+
+ } else {
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_HP_SG_MASK |
+ RT5645_HP_L_SMT_MASK |
+ RT5645_HP_R_SMT_MASK,
+ RT5645_HP_SG_DIS |
+ RT5645_HP_L_SMT_DIS |
+ RT5645_HP_R_SMT_DIS);
+ /* headphone amp power down */
+ snd_soc_write(codec, RT5645_DEPOP_M1, 0x0000);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R |
+ RT5645_PWR_HA, 0);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M2,
+ RT5645_DEPOP_MASK, 0);
+ }
}
}
}
@@ -1287,56 +1416,52 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
hp_amp_power(codec, 1);
/* headphone unmute sequence */
- if (rt5645->codec_type == CODEC_TYPE_RT5650) {
- snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
- } else {
+ if (rt5645->codec_type == CODEC_TYPE_RT5645) {
snd_soc_update_bits(codec, RT5645_DEPOP_M3,
RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
RT5645_CP_FQ3_MASK,
(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ RT5645_MAMP_INT_REG2, 0xfc00);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_RSTN_MASK, RT5645_RSTN_EN);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK |
+ RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS |
+ RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+ msleep(40);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
+ RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
+ RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
}
- regmap_write(rt5645->regmap,
- RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
- snd_soc_update_bits(codec, RT5645_DEPOP_M1,
- RT5645_SMT_TRIG_MASK, RT5645_SMT_TRIG_EN);
- snd_soc_update_bits(codec, RT5645_DEPOP_M1,
- RT5645_RSTN_MASK, RT5645_RSTN_EN);
- snd_soc_update_bits(codec, RT5645_DEPOP_M1,
- RT5645_RSTN_MASK | RT5645_HP_L_SMT_MASK |
- RT5645_HP_R_SMT_MASK, RT5645_RSTN_DIS |
- RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
- msleep(40);
- snd_soc_update_bits(codec, RT5645_DEPOP_M1,
- RT5645_HP_SG_MASK | RT5645_HP_L_SMT_MASK |
- RT5645_HP_R_SMT_MASK, RT5645_HP_SG_DIS |
- RT5645_HP_L_SMT_DIS | RT5645_HP_R_SMT_DIS);
break;
case SND_SOC_DAPM_PRE_PMD:
/* headphone mute sequence */
- if (rt5645->codec_type == CODEC_TYPE_RT5650) {
- snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
- } else {
+ if (rt5645->codec_type == CODEC_TYPE_RT5645) {
snd_soc_update_bits(codec, RT5645_DEPOP_M3,
RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
RT5645_CP_FQ3_MASK,
(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+ regmap_write(rt5645->regmap, RT5645_PR_BASE +
+ RT5645_MAMP_INT_REG2, 0xfc00);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_HP_SG_MASK, RT5645_HP_SG_EN);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_RSTP_MASK, RT5645_RSTP_EN);
+ snd_soc_update_bits(codec, RT5645_DEPOP_M1,
+ RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK |
+ RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS |
+ RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
+ msleep(30);
}
- regmap_write(rt5645->regmap,
- RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
- snd_soc_update_bits(codec, RT5645_DEPOP_M1,
- RT5645_HP_SG_MASK, RT5645_HP_SG_EN);
- snd_soc_update_bits(codec, RT5645_DEPOP_M1,
- RT5645_RSTP_MASK, RT5645_RSTP_EN);
- snd_soc_update_bits(codec, RT5645_DEPOP_M1,
- RT5645_RSTP_MASK | RT5645_HP_L_SMT_MASK |
- RT5645_HP_R_SMT_MASK, RT5645_RSTP_DIS |
- RT5645_HP_L_SMT_EN | RT5645_HP_R_SMT_EN);
- msleep(30);
hp_amp_power(codec, 0);
break;
@@ -1571,20 +1696,50 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
/* IF1 2 Mux */
- SND_SOC_DAPM_MUX("IF1 ADC Mux", SND_SOC_NOPM,
+ SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_if1_adc1_in_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_if1_adc2_in_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
+ 0, 0, &rt5645_if1_adc3_in_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM,
0, 0, &rt5645_if1_adc_in_mux),
+
+ SND_SOC_DAPM_MUX("RT5650 IF1 ADC1 Swap Mux", SND_SOC_NOPM,
+ 0, 0, &rt5650_if1_adc1_in_mux),
+ SND_SOC_DAPM_MUX("RT5650 IF1 ADC2 Swap Mux", SND_SOC_NOPM,
+ 0, 0, &rt5650_if1_adc2_in_mux),
+ SND_SOC_DAPM_MUX("RT5650 IF1 ADC3 Swap Mux", SND_SOC_NOPM,
+ 0, 0, &rt5650_if1_adc3_in_mux),
+ SND_SOC_DAPM_MUX("RT5650 IF1 ADC Mux", SND_SOC_NOPM,
+ 0, 0, &rt5650_if1_adc_in_mux),
+
SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM,
0, 0, &rt5645_if2_adc_in_mux),
/* Digital Interface */
SND_SOC_DAPM_SUPPLY("I2S1", RT5645_PWR_DIG1,
RT5645_PWR_I2S1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC0", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_if1_dac0_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_if1_dac1_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_if1_dac2_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5645_if1_dac3_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5650_if1_dac0_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5650 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5650_if1_dac1_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5650_if1_dac2_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("RT5650 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5650_if1_dac3_tdm_sel_mux),
SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -1848,42 +2003,32 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
{ "IF_ADC2", NULL, "Mono ADC MIXR" },
{ "VAD_ADC", NULL, "VAD ADC Mux" },
- { "IF1 ADC Mux", "IF_ADC1", "IF_ADC1" },
- { "IF1 ADC Mux", "IF_ADC2", "IF_ADC2" },
- { "IF1 ADC Mux", "VAD_ADC", "VAD_ADC" },
-
{ "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" },
{ "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" },
{ "IF2 ADC Mux", "VAD_ADC", "VAD_ADC" },
{ "IF1 ADC", NULL, "I2S1" },
- { "IF1 ADC", NULL, "IF1 ADC Mux" },
{ "IF2 ADC", NULL, "I2S2" },
{ "IF2 ADC", NULL, "IF2 ADC Mux" },
- { "AIF1TX", NULL, "IF1 ADC" },
- { "AIF1TX", NULL, "IF2 ADC" },
{ "AIF2TX", NULL, "IF2 ADC" },
+ { "IF1 DAC0", NULL, "AIF1RX" },
{ "IF1 DAC1", NULL, "AIF1RX" },
{ "IF1 DAC2", NULL, "AIF1RX" },
+ { "IF1 DAC3", NULL, "AIF1RX" },
{ "IF2 DAC", NULL, "AIF2RX" },
+ { "IF1 DAC0", NULL, "I2S1" },
{ "IF1 DAC1", NULL, "I2S1" },
{ "IF1 DAC2", NULL, "I2S1" },
+ { "IF1 DAC3", NULL, "I2S1" },
{ "IF2 DAC", NULL, "I2S2" },
- { "IF1 DAC2 L", NULL, "IF1 DAC2" },
- { "IF1 DAC2 R", NULL, "IF1 DAC2" },
- { "IF1 DAC1 L", NULL, "IF1 DAC1" },
- { "IF1 DAC1 R", NULL, "IF1 DAC1" },
{ "IF2 DAC L", NULL, "IF2 DAC" },
{ "IF2 DAC R", NULL, "IF2 DAC" },
- { "DAC1 L Mux", "IF1 DAC", "IF1 DAC1 L" },
{ "DAC1 L Mux", "IF2 DAC", "IF2 DAC L" },
-
- { "DAC1 R Mux", "IF1 DAC", "IF1 DAC1 R" },
{ "DAC1 R Mux", "IF2 DAC", "IF2 DAC R" },
{ "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" },
@@ -1893,14 +2038,12 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
{ "DAC1 MIXR", "DAC1 Switch", "DAC1 R Mux" },
{ "DAC1 MIXR", NULL, "dac stereo1 filter" },
- { "DAC L2 Mux", "IF1 DAC", "IF1 DAC2 L" },
{ "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" },
{ "DAC L2 Mux", "Mono ADC", "Mono ADC MIXL" },
{ "DAC L2 Mux", "VAD_ADC", "VAD_ADC" },
{ "DAC L2 Volume", NULL, "DAC L2 Mux" },
{ "DAC L2 Volume", NULL, "dac mono left filter" },
- { "DAC R2 Mux", "IF1 DAC", "IF1 DAC2 R" },
{ "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" },
{ "DAC R2 Mux", "Mono ADC", "Mono ADC MIXR" },
{ "DAC R2 Mux", "Haptic", "Haptic Generator" },
@@ -2038,6 +2181,80 @@ static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = {
{ "DAC R1", NULL, "A DAC1 R Mux" },
{ "DAC L2", NULL, "A DAC2 L Mux" },
{ "DAC R2", NULL, "A DAC2 R Mux" },
+
+ { "RT5650 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" },
+ { "RT5650 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" },
+ { "RT5650 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" },
+ { "RT5650 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" },
+
+ { "RT5650 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" },
+ { "RT5650 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" },
+ { "RT5650 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" },
+ { "RT5650 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" },
+
+ { "RT5650 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" },
+ { "RT5650 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" },
+ { "RT5650 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" },
+ { "RT5650 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" },
+
+ { "IF1 ADC", NULL, "RT5650 IF1 ADC1 Swap Mux" },
+ { "IF1 ADC", NULL, "RT5650 IF1 ADC2 Swap Mux" },
+ { "IF1 ADC", NULL, "RT5650 IF1 ADC3 Swap Mux" },
+
+ { "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/DAC_REF/Null", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC1/IF_ADC2/Null/DAC_REF", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/IF_ADC2/Null", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC1/DAC_REF/Null/IF_ADC2", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC1/Null/DAC_REF/IF_ADC2", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC1/Null/IF_ADC2/DAC_REF", "IF1 ADC" },
+
+ { "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/DAC_REF/Null", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC2/IF_ADC1/Null/DAC_REF", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/IF_ADC1/Null", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC2/DAC_REF/Null/IF_ADC1", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC2/Null/DAC_REF/IF_ADC1", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "IF_ADC2/Null/IF_ADC1/DAC_REF", "IF1 ADC" },
+
+ { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/IF_ADC2/Null", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC1/Null/IF_ADC2", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/IF_ADC1/Null", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "DAC_REF/IF_ADC2/Null/IF_ADC1", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC1/IF_ADC2", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "DAC_REF/Null/IF_ADC2/IF_ADC1", "IF1 ADC" },
+
+ { "RT5650 IF1 ADC Mux", "Null/IF_ADC1/IF_ADC2/DAC_REF", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "Null/IF_ADC1/DAC_REF/IF_ADC2", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "Null/IF_ADC2/IF_ADC1/DAC_REF", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "Null/IF_ADC2/DAC_REF/IF_ADC1", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC1/IF_ADC2", "IF1 ADC" },
+ { "RT5650 IF1 ADC Mux", "Null/DAC_REF/IF_ADC2/IF_ADC1", "IF1 ADC" },
+ { "AIF1TX", NULL, "RT5650 IF1 ADC Mux" },
+
+ { "RT5650 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" },
+ { "RT5650 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" },
+ { "RT5650 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" },
+ { "RT5650 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" },
+
+ { "RT5650 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" },
+ { "RT5650 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" },
+ { "RT5650 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" },
+ { "RT5650 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" },
+
+ { "RT5650 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" },
+ { "RT5650 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" },
+ { "RT5650 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" },
+ { "RT5650 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" },
+
+ { "RT5650 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" },
+ { "RT5650 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" },
+ { "RT5650 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" },
+ { "RT5650 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" },
+
+ { "DAC1 L Mux", "IF1 DAC", "RT5650 IF1 DAC1 L Mux" },
+ { "DAC1 R Mux", "IF1 DAC", "RT5650 IF1 DAC1 R Mux" },
+
+ { "DAC L2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 L Mux" },
+ { "DAC R2 Mux", "IF1 DAC", "RT5650 IF1 DAC2 R Mux" },
};
static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
@@ -2045,6 +2262,57 @@ static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
{ "DAC R1", NULL, "Stereo DAC MIXR" },
{ "DAC L2", NULL, "Mono DAC MIXL" },
{ "DAC R2", NULL, "Mono DAC MIXR" },
+
+ { "RT5645 IF1 ADC1 Swap Mux", "L/R", "IF_ADC1" },
+ { "RT5645 IF1 ADC1 Swap Mux", "R/L", "IF_ADC1" },
+ { "RT5645 IF1 ADC1 Swap Mux", "L/L", "IF_ADC1" },
+ { "RT5645 IF1 ADC1 Swap Mux", "R/R", "IF_ADC1" },
+
+ { "RT5645 IF1 ADC2 Swap Mux", "L/R", "IF_ADC2" },
+ { "RT5645 IF1 ADC2 Swap Mux", "R/L", "IF_ADC2" },
+ { "RT5645 IF1 ADC2 Swap Mux", "L/L", "IF_ADC2" },
+ { "RT5645 IF1 ADC2 Swap Mux", "R/R", "IF_ADC2" },
+
+ { "RT5645 IF1 ADC3 Swap Mux", "L/R", "VAD_ADC" },
+ { "RT5645 IF1 ADC3 Swap Mux", "R/L", "VAD_ADC" },
+ { "RT5645 IF1 ADC3 Swap Mux", "L/L", "VAD_ADC" },
+ { "RT5645 IF1 ADC3 Swap Mux", "R/R", "VAD_ADC" },
+
+ { "IF1 ADC", NULL, "RT5645 IF1 ADC1 Swap Mux" },
+ { "IF1 ADC", NULL, "RT5645 IF1 ADC2 Swap Mux" },
+ { "IF1 ADC", NULL, "RT5645 IF1 ADC3 Swap Mux" },
+
+ { "RT5645 IF1 ADC Mux", "IF_ADC1/IF_ADC2/VAD_ADC", "IF1 ADC" },
+ { "RT5645 IF1 ADC Mux", "IF_ADC2/IF_ADC1/VAD_ADC", "IF1 ADC" },
+ { "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC1/IF_ADC2", "IF1 ADC" },
+ { "RT5645 IF1 ADC Mux", "VAD_ADC/IF_ADC2/IF_ADC1", "IF1 ADC" },
+ { "AIF1TX", NULL, "RT5645 IF1 ADC Mux" },
+
+ { "RT5645 IF1 DAC1 L Mux", "Slot0", "IF1 DAC0" },
+ { "RT5645 IF1 DAC1 L Mux", "Slot1", "IF1 DAC1" },
+ { "RT5645 IF1 DAC1 L Mux", "Slot2", "IF1 DAC2" },
+ { "RT5645 IF1 DAC1 L Mux", "Slot3", "IF1 DAC3" },
+
+ { "RT5645 IF1 DAC1 R Mux", "Slot0", "IF1 DAC0" },
+ { "RT5645 IF1 DAC1 R Mux", "Slot1", "IF1 DAC1" },
+ { "RT5645 IF1 DAC1 R Mux", "Slot2", "IF1 DAC2" },
+ { "RT5645 IF1 DAC1 R Mux", "Slot3", "IF1 DAC3" },
+
+ { "RT5645 IF1 DAC2 L Mux", "Slot0", "IF1 DAC0" },
+ { "RT5645 IF1 DAC2 L Mux", "Slot1", "IF1 DAC1" },
+ { "RT5645 IF1 DAC2 L Mux", "Slot2", "IF1 DAC2" },
+ { "RT5645 IF1 DAC2 L Mux", "Slot3", "IF1 DAC3" },
+
+ { "RT5645 IF1 DAC2 R Mux", "Slot0", "IF1 DAC0" },
+ { "RT5645 IF1 DAC2 R Mux", "Slot1", "IF1 DAC1" },
+ { "RT5645 IF1 DAC2 R Mux", "Slot2", "IF1 DAC2" },
+ { "RT5645 IF1 DAC2 R Mux", "Slot3", "IF1 DAC3" },
+
+ { "DAC1 L Mux", "IF1 DAC", "RT5645 IF1 DAC1 L Mux" },
+ { "DAC1 R Mux", "IF1 DAC", "RT5645 IF1 DAC1 R Mux" },
+
+ { "DAC L2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 L Mux" },
+ { "DAC R2 Mux", "IF1 DAC", "RT5645 IF1 DAC2 R Mux" },
};
static int rt5645_hw_params(struct snd_pcm_substream *substream,
@@ -2102,9 +2370,8 @@ static int rt5645_hw_params(struct snd_pcm_substream *substream,
switch (dai->id) {
case RT5645_AIF1:
- mask_clk = RT5645_I2S_BCLK_MS1_MASK | RT5645_I2S_PD1_MASK;
- val_clk = bclk_ms << RT5645_I2S_BCLK_MS1_SFT |
- pre_div << RT5645_I2S_PD1_SFT;
+ mask_clk = RT5645_I2S_PD1_MASK;
+ val_clk = pre_div << RT5645_I2S_PD1_SFT;
snd_soc_update_bits(codec, RT5645_I2S1_SDP,
(0x3 << dl_sft), (val_len << dl_sft));
snd_soc_update_bits(codec, RT5645_ADDA_CLK1, mask_clk, val_clk);
@@ -2369,6 +2636,8 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
static int rt5645_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
@@ -2399,8 +2668,9 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_OFF:
snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
- snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
- RT5645_DIG_GATE_CTRL, 0);
+ if (!rt5645->en_button_func)
+ snd_soc_update_bits(codec, RT5645_GEN_CTRL1,
+ RT5645_DIG_GATE_CTRL, 0);
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
RT5645_PWR_VREF1 | RT5645_PWR_MB |
RT5645_PWR_BG | RT5645_PWR_VREF2 |
@@ -2410,72 +2680,222 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
default:
break;
}
- codec->dapm.bias_level = level;
return 0;
}
-static int rt5645_jack_detect(struct snd_soc_codec *codec)
+static int rt5650_calibration(struct rt5645_priv *rt5645)
{
- struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
- int gpio_state, jack_type = 0;
- unsigned int val;
+ int val, i;
+ int ret = -1;
- if (!gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
- dev_err(codec->dev, "invalid gpio\n");
- return -EINVAL;
+ regcache_cache_bypass(rt5645->regmap, true);
+ regmap_write(rt5645->regmap, RT5645_RESET, 0);
+ regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0800);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_CHOP_DAC_ADC,
+ 0x3600);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x25, 0x7000);
+ regmap_write(rt5645->regmap, RT5645_I2S1_SDP, 0x8008);
+ /* headset type */
+ regmap_write(rt5645->regmap, RT5645_GEN_CTRL1, 0x2061);
+ regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006);
+ regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0x2012);
+ regmap_write(rt5645->regmap, RT5645_PWR_MIXER, 0x0002);
+ regmap_write(rt5645->regmap, RT5645_PWR_VOL, 0x0020);
+ regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0);
+ regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006);
+ regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x1827);
+ regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x0827);
+ msleep(400);
+ /* Inline command */
+ regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0001);
+ regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000);
+ regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008);
+ /* Calbration */
+ regmap_write(rt5645->regmap, RT5645_GLB_CLK, 0x8000);
+ regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000);
+ regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000);
+ regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008);
+ regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x8800);
+ regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0xe8fa);
+ regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x8c04);
+ regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x3100);
+ regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
+ regmap_write(rt5645->regmap, RT5645_BASS_BACK, 0x8a13);
+ regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0820);
+ regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x000d);
+ /* Power on and Calbration */
+ regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_HP_DCC_INT1,
+ 0x9f01);
+ msleep(200);
+ for (i = 0; i < 5; i++) {
+ regmap_read(rt5645->regmap, RT5645_PR_BASE + 0x7a, &val);
+ if (val != 0 && val != 0x3f3f) {
+ ret = 0;
+ break;
+ }
+ msleep(50);
}
- gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
+ pr_debug("%s: PR-7A = 0x%x\n", __func__, val);
+
+ /* mute */
+ regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x3e, 0x7400);
+ regmap_write(rt5645->regmap, RT5645_DEPOP_M3, 0x0737);
+ regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2,
+ 0xfc00);
+ regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x1140);
+ regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000);
+ regmap_write(rt5645->regmap, RT5645_GEN_CTRL2, 0x4020);
+ regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x0006);
+ regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x0000);
+ msleep(350);
+
+ regcache_cache_bypass(rt5645->regmap, false);
+
+ return ret;
+}
- dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio,
- gpio_state);
+static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
+ bool enable)
+{
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
- if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) ||
- (!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) {
- snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1");
- snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2");
- snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
- snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power");
- snd_soc_dapm_sync(&codec->dapm);
+ if (enable) {
+ snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+ "ADC L power");
+ snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+ "ADC R power");
+ snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+ "LDO2");
+ snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm,
+ "Mic Det Power");
+ snd_soc_dapm_sync_unlocked(&codec->dapm);
+ snd_soc_update_bits(codec,
+ RT5645_INT_IRQ_ST, 0x8, 0x8);
+ snd_soc_update_bits(codec,
+ RT5650_4BTN_IL_CMD2, 0x8000, 0x8000);
+ snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
+ pr_debug("%s read %x = %x\n", __func__, RT5650_4BTN_IL_CMD1,
+ snd_soc_read(codec, RT5650_4BTN_IL_CMD1));
+ } else {
+ snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0);
+ snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0);
+ snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+ "ADC L power");
+ snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+ "ADC R power");
+ if (rt5645->pdata.jd_mode == 0)
+ snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+ "LDO2");
+ snd_soc_dapm_disable_pin_unlocked(&codec->dapm,
+ "Mic Det Power");
+ snd_soc_dapm_sync_unlocked(&codec->dapm);
+ }
+}
- snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006);
- snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0);
+static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
+{
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val;
- snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
- RT5645_CBJ_MN_JD, 0);
- snd_soc_update_bits(codec, RT5645_IN1_CTRL2,
- RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD);
+ if (jack_insert) {
+ regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006);
+
+ if (codec->component.card->instantiated) {
+ /* for jack type detect */
+ snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+ snd_soc_dapm_force_enable_pin(&codec->dapm,
+ "Mic Det Power");
+ snd_soc_dapm_sync(&codec->dapm);
+ } else {
+ /* Power up necessary bits for JD if dapm is
+ not ready yet */
+ regmap_update_bits(rt5645->regmap, RT5645_PWR_ANLG1,
+ RT5645_PWR_MB | RT5645_PWR_VREF2,
+ RT5645_PWR_MB | RT5645_PWR_VREF2);
+ regmap_update_bits(rt5645->regmap, RT5645_PWR_MIXER,
+ RT5645_PWR_LDO2, RT5645_PWR_LDO2);
+ regmap_update_bits(rt5645->regmap, RT5645_PWR_VOL,
+ RT5645_PWR_MIC_DET, RT5645_PWR_MIC_DET);
+ }
- msleep(400);
- val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7;
+ regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0);
+ regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006);
+ regmap_update_bits(rt5645->regmap,
+ RT5645_IN1_CTRL2, 0x1000, 0x1000);
+ msleep(100);
+ regmap_update_bits(rt5645->regmap,
+ RT5645_IN1_CTRL2, 0x1000, 0x0000);
+
+ msleep(450);
+ regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val);
+ val &= 0x7;
dev_dbg(codec->dev, "val = %d\n", val);
- if (val == 1 || val == 2)
- jack_type = SND_JACK_HEADSET;
- else
- jack_type = SND_JACK_HEADPHONE;
+ if (val == 1 || val == 2) {
+ rt5645->jack_type = SND_JACK_HEADSET;
+ if (rt5645->en_button_func) {
+ rt5645_enable_push_button_irq(codec, true);
+ }
+ } else {
+ if (codec->component.card->instantiated) {
+ snd_soc_dapm_disable_pin(&codec->dapm,
+ "Mic Det Power");
+ snd_soc_dapm_sync(&codec->dapm);
+ } else
+ regmap_update_bits(rt5645->regmap,
+ RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0);
+ rt5645->jack_type = SND_JACK_HEADPHONE;
+ }
- snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
- snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
- if (rt5645->pdata.jd_mode == 0)
- snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
- snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
- snd_soc_dapm_sync(&codec->dapm);
+ } else { /* jack out */
+ rt5645->jack_type = 0;
+ if (rt5645->en_button_func)
+ rt5645_enable_push_button_irq(codec, false);
+ else {
+ if (codec->component.card->instantiated) {
+ if (rt5645->pdata.jd_mode == 0)
+ snd_soc_dapm_disable_pin(&codec->dapm,
+ "LDO2");
+ snd_soc_dapm_disable_pin(&codec->dapm,
+ "Mic Det Power");
+ snd_soc_dapm_sync(&codec->dapm);
+ } else {
+ if (rt5645->pdata.jd_mode == 0)
+ regmap_update_bits(rt5645->regmap,
+ RT5645_PWR_MIXER,
+ RT5645_PWR_LDO2, 0);
+ regmap_update_bits(rt5645->regmap,
+ RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0);
+ }
+ }
}
- snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE);
- snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE);
- return 0;
+ return rt5645->jack_type;
}
+static int rt5645_irq_detection(struct rt5645_priv *rt5645);
+static irqreturn_t rt5645_irq(int irq, void *data);
+
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)
{
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
rt5645->hp_jack = hp_jack;
rt5645->mic_jack = mic_jack;
- rt5645_jack_detect(codec);
+ rt5645->btn_jack = btn_jack;
+ if (rt5645->btn_jack && rt5645->codec_type == CODEC_TYPE_RT5650) {
+ rt5645->en_button_func = true;
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
+ regmap_update_bits(rt5645->regmap, RT5645_DEPOP_M1,
+ RT5645_HP_CB_MASK, RT5645_HP_CB_PU);
+ regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL1,
+ RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL);
+ }
+ rt5645_irq(0, rt5645);
return 0;
}
@@ -2486,7 +2906,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
struct rt5645_priv *rt5645 =
container_of(work, struct rt5645_priv, jack_detect_work.work);
- rt5645_jack_detect(rt5645->codec);
+ rt5645_irq_detection(rt5645);
}
static irqreturn_t rt5645_irq(int irq, void *data)
@@ -2499,6 +2919,126 @@ static irqreturn_t rt5645_irq(int irq, void *data)
return IRQ_HANDLED;
}
+static int rt5645_button_detect(struct snd_soc_codec *codec)
+{
+ int btn_type, val;
+
+ val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1);
+ pr_debug("val=0x%x\n", val);
+ btn_type = val & 0xfff0;
+ snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val);
+
+ return btn_type;
+}
+
+static int rt5645_irq_detection(struct rt5645_priv *rt5645)
+{
+ int val, btn_type, gpio_state = 0, report = 0;
+
+ switch (rt5645->pdata.jd_mode) {
+ case 0: /* Not using rt5645 JD */
+ if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
+ gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
+ dev_dbg(rt5645->codec->dev, "gpio = %d(%d)\n",
+ rt5645->pdata.hp_det_gpio, gpio_state);
+ }
+ if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) ||
+ (!rt5645->pdata.gpio_hp_det_active_high &&
+ !gpio_state)) {
+ report = rt5645_jack_detect(rt5645->codec, 1);
+ } else {
+ report = rt5645_jack_detect(rt5645->codec, 0);
+ }
+ snd_soc_jack_report(rt5645->hp_jack,
+ report, SND_JACK_HEADPHONE);
+ snd_soc_jack_report(rt5645->mic_jack,
+ report, SND_JACK_MICROPHONE);
+ return report;
+ case 1: /* 2 port */
+ val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070;
+ break;
+ default: /* 1 port */
+ val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0020;
+ break;
+
+ }
+
+ switch (val) {
+ /* jack in */
+ case 0x30: /* 2 port */
+ case 0x0: /* 1 port or 2 port */
+ if (rt5645->jack_type == 0) {
+ report = rt5645_jack_detect(rt5645->codec, 1);
+ /* for push button and jack out */
+ break;
+ }
+ btn_type = 0;
+ if (snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x4) {
+ /* button pressed */
+ report = SND_JACK_HEADSET;
+ btn_type = rt5645_button_detect(rt5645->codec);
+ /* rt5650 can report three kinds of button behavior,
+ one click, double click and hold. However,
+ currently we will report button pressed/released
+ event. So all the three button behaviors are
+ treated as button pressed. */
+ switch (btn_type) {
+ case 0x8000:
+ case 0x4000:
+ case 0x2000:
+ report |= SND_JACK_BTN_0;
+ break;
+ case 0x1000:
+ case 0x0800:
+ case 0x0400:
+ report |= SND_JACK_BTN_1;
+ break;
+ case 0x0200:
+ case 0x0100:
+ case 0x0080:
+ report |= SND_JACK_BTN_2;
+ break;
+ case 0x0040:
+ case 0x0020:
+ case 0x0010:
+ report |= SND_JACK_BTN_3;
+ break;
+ case 0x0000: /* unpressed */
+ break;
+ default:
+ dev_err(rt5645->codec->dev,
+ "Unexpected button code 0x%04x\n",
+ btn_type);
+ break;
+ }
+ }
+ if (btn_type == 0)/* button release */
+ report = rt5645->jack_type;
+
+ break;
+ /* jack out */
+ case 0x70: /* 2 port */
+ case 0x10: /* 2 port */
+ case 0x20: /* 1 port */
+ report = 0;
+ snd_soc_update_bits(rt5645->codec,
+ RT5645_INT_IRQ_ST, 0x1, 0x0);
+ rt5645_jack_detect(rt5645->codec, 0);
+ break;
+ default:
+ break;
+ }
+
+ snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
+ snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE);
+ if (rt5645->en_button_func)
+ snd_soc_jack_report(rt5645->btn_jack,
+ report, SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ return report;
+}
+
static int rt5645_probe(struct snd_soc_codec *codec)
{
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
@@ -2521,12 +3061,10 @@ static int rt5645_probe(struct snd_soc_codec *codec)
break;
}
- rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
/* for JD function */
- if (rt5645->pdata.en_jd_func) {
+ if (rt5645->pdata.jd_mode) {
snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power");
snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
snd_soc_dapm_sync(&codec->dapm);
@@ -2666,6 +3204,32 @@ static struct acpi_device_id rt5645_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
#endif
+static struct rt5645_platform_data *rt5645_pdata;
+
+static struct rt5645_platform_data strago_platform_data = {
+ .dmic1_data_pin = RT5645_DMIC1_DISABLE,
+ .dmic2_data_pin = RT5645_DMIC_DATA_IN2P,
+ .jd_mode = 3,
+};
+
+static int strago_quirk_cb(const struct dmi_system_id *id)
+{
+ rt5645_pdata = &strago_platform_data;
+
+ return 1;
+}
+
+static struct dmi_system_id dmi_platform_intel_braswell[] = {
+ {
+ .ident = "Intel Strago",
+ .callback = strago_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Strago"),
+ },
+ },
+ { }
+};
+
static int rt5645_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -2673,6 +3237,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
struct rt5645_priv *rt5645;
int ret;
unsigned int val;
+ struct gpio_desc *gpiod;
rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv),
GFP_KERNEL);
@@ -2682,8 +3247,23 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
rt5645->i2c = i2c;
i2c_set_clientdata(i2c, rt5645);
- if (pdata)
+ if (pdata) {
rt5645->pdata = *pdata;
+ } else {
+ if (dmi_check_system(dmi_platform_intel_braswell)) {
+ rt5645->pdata = *rt5645_pdata;
+ gpiod = devm_gpiod_get_index(&i2c->dev, "rt5645", 0);
+
+ if (IS_ERR(gpiod) || gpiod_direction_input(gpiod)) {
+ rt5645->pdata.hp_det_gpio = -1;
+ dev_err(&i2c->dev, "failed to initialize gpiod\n");
+ } else {
+ rt5645->pdata.hp_det_gpio = desc_to_gpio(gpiod);
+ rt5645->pdata.gpio_hp_det_active_high
+ = !gpiod_is_active_low(gpiod);
+ }
+ }
+ }
rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap);
if (IS_ERR(rt5645->regmap)) {
@@ -2709,6 +3289,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
return -ENODEV;
}
+ if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+ ret = rt5650_calibration(rt5645);
+
+ if (ret < 0)
+ pr_err("calibration failed!\n");
+ }
+
regmap_write(rt5645->regmap, RT5645_RESET, 0);
ret = regmap_register_patch(rt5645->regmap, init_list,
@@ -2728,84 +3315,76 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
RT5645_IN_DF2, RT5645_IN_DF2);
- if (rt5645->pdata.dmic_en) {
+ if (rt5645->pdata.dmic1_data_pin || rt5645->pdata.dmic2_data_pin) {
regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
RT5645_GP2_PIN_MASK, RT5645_GP2_PIN_DMIC1_SCL);
+ }
+ switch (rt5645->pdata.dmic1_data_pin) {
+ case RT5645_DMIC_DATA_IN2N:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N);
+ break;
- switch (rt5645->pdata.dmic1_data_pin) {
- case RT5645_DMIC_DATA_IN2N:
- regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
- RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_IN2N);
- break;
-
- case RT5645_DMIC_DATA_GPIO5:
- regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
- RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
- regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
- RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA);
- break;
-
- case RT5645_DMIC_DATA_GPIO11:
- regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
- RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11);
- regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
- RT5645_GP11_PIN_MASK,
- RT5645_GP11_PIN_DMIC1_SDA);
- break;
+ case RT5645_DMIC_DATA_GPIO5:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO5);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP5_PIN_MASK, RT5645_GP5_PIN_DMIC1_SDA);
+ break;
- default:
- break;
- }
+ case RT5645_DMIC_DATA_GPIO11:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_1_DP_MASK, RT5645_DMIC_1_DP_GPIO11);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP11_PIN_MASK,
+ RT5645_GP11_PIN_DMIC1_SDA);
+ break;
- switch (rt5645->pdata.dmic2_data_pin) {
- case RT5645_DMIC_DATA_IN2P:
- regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
- RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P);
- break;
+ default:
+ break;
+ }
- case RT5645_DMIC_DATA_GPIO6:
- regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
- RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6);
- regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
- RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA);
- break;
+ switch (rt5645->pdata.dmic2_data_pin) {
+ case RT5645_DMIC_DATA_IN2P:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_IN2P);
+ break;
- case RT5645_DMIC_DATA_GPIO10:
- regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
- RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10);
- regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
- RT5645_GP10_PIN_MASK,
- RT5645_GP10_PIN_DMIC2_SDA);
- break;
+ case RT5645_DMIC_DATA_GPIO6:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO6);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP6_PIN_MASK, RT5645_GP6_PIN_DMIC2_SDA);
+ break;
- case RT5645_DMIC_DATA_GPIO12:
- regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
- RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
- regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
- RT5645_GP12_PIN_MASK,
- RT5645_GP12_PIN_DMIC2_SDA);
- break;
+ case RT5645_DMIC_DATA_GPIO10:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO10);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP10_PIN_MASK,
+ RT5645_GP10_PIN_DMIC2_SDA);
+ break;
- default:
- break;
- }
+ case RT5645_DMIC_DATA_GPIO12:
+ regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
+ RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP12_PIN_MASK,
+ RT5645_GP12_PIN_DMIC2_SDA);
+ break;
+ default:
+ break;
}
- if (rt5645->pdata.en_jd_func) {
+ if (rt5645->pdata.jd_mode) {
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
- RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU,
- RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU);
+ RT5645_IRQ_CLK_GATE_CTRL,
+ RT5645_IRQ_CLK_GATE_CTRL);
regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
- RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
- regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3,
- RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL,
- RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL);
+ RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
- RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
- }
-
- if (rt5645->pdata.jd_mode) {
+ RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN);
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index db78e9462876..9ec4e899795d 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -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__ */
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 9f4c7be6d798..a3506e193abc 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -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;
}
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index cc7f84a150a7..840dd6d0003a 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -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;
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 169aa471ffbd..31d969ac1192 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -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.
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index 9dceb41d18ea..7eca38a23255 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -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;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 3593a1496056..e673f6ceb521 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -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;
}
@@ -1092,6 +1091,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^((idx−15)/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
* 2. charge pump, set to different value
@@ -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;
}
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
index 0a8e43c98a07..29cb44256044 100644
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -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);
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index 7947c0ebb1ed..3a7de0159f24 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -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;
}
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 67ea55adb307..f30de7639bb9 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -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,
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 314eaece1b7d..69a773aeb13d 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -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,
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index a984485108cd..938d2cb6d78b 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -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 = {
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 007a0e3bc273..60eff36260cb 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -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++)
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index 669e3228241e..bd819a3f205a 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -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);
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index b0f436d10125..4f70378b2cfb 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -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;
}
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 7f939aec5a7f..ed4cca7f6779 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -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;
}
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index dfb4ff5cc9ea..891e2c529df3 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -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;
-/* Input mux controls */
-static const char *tas2552_input_texts[] = {
- "Digital", "Analog"
+ 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 * 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;
+
+ 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;
- tas2552->mclk = freq;
+ /* 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);
diff --git a/sound/soc/codecs/tas2552.h b/sound/soc/codecs/tas2552.h
index 6cea8f31bf88..bbb820495516 100644
--- a/sound/soc/codecs/tas2552.h
+++ b/sound/soc/codecs/tas2552.h
@@ -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)
-
-/* 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)
+#define TAS2552_ANALOG_IN_SEL (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
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
new file mode 100644
index 000000000000..85bcc374c8e8
--- /dev/null
+++ b/sound/soc/codecs/tas571x.c
@@ -0,0 +1,514 @@
+/*
+ * TAS571x amplifier audio driver
+ *
+ * Copyright (C) 2015 Google, Inc.
+ * Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/stddef.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "tas571x.h"
+
+#define TAS571X_MAX_SUPPLIES 6
+
+struct tas571x_chip {
+ const char *const *supply_names;
+ int num_supply_names;
+ const struct snd_kcontrol_new *controls;
+ int num_controls;
+ const struct regmap_config *regmap_config;
+ int vol_reg_size;
+};
+
+struct tas571x_private {
+ const struct tas571x_chip *chip;
+ struct regmap *regmap;
+ struct regulator_bulk_data supplies[TAS571X_MAX_SUPPLIES];
+ struct clk *mclk;
+ unsigned int format;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *pdn_gpio;
+ struct snd_soc_codec_driver codec_driver;
+};
+
+static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
+{
+ switch (reg) {
+ case TAS571X_MVOL_REG:
+ case TAS571X_CH1_VOL_REG:
+ case TAS571X_CH2_VOL_REG:
+ return priv->chip->vol_reg_size;
+ default:
+ return 1;
+ }
+}
+
+static int tas571x_reg_write(void *context, unsigned int reg,
+ unsigned int value)
+{
+ struct i2c_client *client = context;
+ struct tas571x_private *priv = i2c_get_clientdata(client);
+ unsigned int i, size;
+ uint8_t buf[5];
+ int ret;
+
+ size = tas571x_register_size(priv, reg);
+ buf[0] = reg;
+
+ for (i = size; i >= 1; --i) {
+ buf[i] = value;
+ value >>= 8;
+ }
+
+ ret = i2c_master_send(client, buf, size + 1);
+ if (ret == size + 1)
+ return 0;
+ else if (ret < 0)
+ return ret;
+ else
+ return -EIO;
+}
+
+static int tas571x_reg_read(void *context, unsigned int reg,
+ unsigned int *value)
+{
+ struct i2c_client *client = context;
+ struct tas571x_private *priv = i2c_get_clientdata(client);
+ uint8_t send_buf, recv_buf[4];
+ struct i2c_msg msgs[2];
+ unsigned int size;
+ unsigned int i;
+ int ret;
+
+ size = tas571x_register_size(priv, reg);
+ send_buf = reg;
+
+ msgs[0].addr = client->addr;
+ msgs[0].len = sizeof(send_buf);
+ msgs[0].buf = &send_buf;
+ msgs[0].flags = 0;
+
+ msgs[1].addr = client->addr;
+ msgs[1].len = size;
+ msgs[1].buf = recv_buf;
+ msgs[1].flags = I2C_M_RD;
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return ret;
+ else if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *value = 0;
+
+ for (i = 0; i < size; i++) {
+ *value <<= 8;
+ *value |= recv_buf[i];
+ }
+
+ return 0;
+}
+
+static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
+{
+ struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+
+ priv->format = format;
+
+ return 0;
+}
+
+static int tas571x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
+ u32 val;
+
+ switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ val = 0x00;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ val = 0x03;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ val = 0x06;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (params_width(params) >= 24)
+ val += 2;
+ else if (params_width(params) >= 20)
+ val += 1;
+
+ return regmap_update_bits(priv->regmap, TAS571X_SDI_REG,
+ TAS571X_SDI_FMT_MASK, val);
+}
+
+static int tas571x_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct tas571x_private *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ if (!IS_ERR(priv->mclk)) {
+ ret = clk_prepare_enable(priv->mclk);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to enable master clock: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ gpiod_set_value(priv->pdn_gpio, 0);
+ usleep_range(5000, 6000);
+
+ regcache_cache_only(priv->regmap, false);
+ ret = regcache_sync(priv->regmap);
+ if (ret)
+ return ret;
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ regcache_cache_only(priv->regmap, true);
+ gpiod_set_value(priv->pdn_gpio, 1);
+
+ if (!IS_ERR(priv->mclk))
+ clk_disable_unprepare(priv->mclk);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops tas571x_dai_ops = {
+ .set_fmt = tas571x_set_dai_fmt,
+ .hw_params = tas571x_hw_params,
+};
+
+static const char *const tas5711_supply_names[] = {
+ "AVDD",
+ "DVDD",
+ "PVDD_A",
+ "PVDD_B",
+ "PVDD_C",
+ "PVDD_D",
+};
+
+static const DECLARE_TLV_DB_SCALE(tas5711_volume_tlv, -10350, 50, 1);
+
+static const struct snd_kcontrol_new tas5711_controls[] = {
+ SOC_SINGLE_TLV("Master Volume",
+ TAS571X_MVOL_REG,
+ 0, 0xff, 1, tas5711_volume_tlv),
+ SOC_DOUBLE_R_TLV("Speaker Volume",
+ TAS571X_CH1_VOL_REG,
+ TAS571X_CH2_VOL_REG,
+ 0, 0xff, 1, tas5711_volume_tlv),
+ SOC_DOUBLE("Speaker Switch",
+ TAS571X_SOFT_MUTE_REG,
+ TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+ 1, 1),
+};
+
+static const struct reg_default tas5711_reg_defaults[] = {
+ { 0x04, 0x05 },
+ { 0x05, 0x40 },
+ { 0x06, 0x00 },
+ { 0x07, 0xff },
+ { 0x08, 0x30 },
+ { 0x09, 0x30 },
+ { 0x1b, 0x82 },
+};
+
+static const struct regmap_config tas5711_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .max_register = 0xff,
+ .reg_read = tas571x_reg_read,
+ .reg_write = tas571x_reg_write,
+ .reg_defaults = tas5711_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tas5711_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct tas571x_chip tas5711_chip = {
+ .supply_names = tas5711_supply_names,
+ .num_supply_names = ARRAY_SIZE(tas5711_supply_names),
+ .controls = tas5711_controls,
+ .num_controls = ARRAY_SIZE(tas5711_controls),
+ .regmap_config = &tas5711_regmap_config,
+ .vol_reg_size = 1,
+};
+
+static const char *const tas5717_supply_names[] = {
+ "AVDD",
+ "DVDD",
+ "HPVDD",
+ "PVDD_AB",
+ "PVDD_CD",
+};
+
+static const DECLARE_TLV_DB_SCALE(tas5717_volume_tlv, -10375, 25, 0);
+
+static const struct snd_kcontrol_new tas5717_controls[] = {
+ /* MVOL LSB is ignored - see comments in tas571x_i2c_probe() */
+ SOC_SINGLE_TLV("Master Volume",
+ TAS571X_MVOL_REG, 1, 0x1ff, 1,
+ tas5717_volume_tlv),
+ SOC_DOUBLE_R_TLV("Speaker Volume",
+ TAS571X_CH1_VOL_REG, TAS571X_CH2_VOL_REG,
+ 1, 0x1ff, 1, tas5717_volume_tlv),
+ SOC_DOUBLE("Speaker Switch",
+ TAS571X_SOFT_MUTE_REG,
+ TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+ 1, 1),
+};
+
+static const struct reg_default tas5717_reg_defaults[] = {
+ { 0x04, 0x05 },
+ { 0x05, 0x40 },
+ { 0x06, 0x00 },
+ { 0x07, 0x03ff },
+ { 0x08, 0x00c0 },
+ { 0x09, 0x00c0 },
+ { 0x1b, 0x82 },
+};
+
+static const struct regmap_config tas5717_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .max_register = 0xff,
+ .reg_read = tas571x_reg_read,
+ .reg_write = tas571x_reg_write,
+ .reg_defaults = tas5717_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tas5717_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+};
+
+/* This entry is reused for tas5719 as the software interface is identical. */
+static const struct tas571x_chip tas5717_chip = {
+ .supply_names = tas5717_supply_names,
+ .num_supply_names = ARRAY_SIZE(tas5717_supply_names),
+ .controls = tas5717_controls,
+ .num_controls = ARRAY_SIZE(tas5717_controls),
+ .regmap_config = &tas5717_regmap_config,
+ .vol_reg_size = 2,
+};
+
+static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_OUTPUT("OUT_A"),
+ SND_SOC_DAPM_OUTPUT("OUT_B"),
+ SND_SOC_DAPM_OUTPUT("OUT_C"),
+ SND_SOC_DAPM_OUTPUT("OUT_D"),
+};
+
+static const struct snd_soc_dapm_route tas571x_dapm_routes[] = {
+ { "DACL", NULL, "Playback" },
+ { "DACR", NULL, "Playback" },
+
+ { "OUT_A", NULL, "DACL" },
+ { "OUT_B", NULL, "DACL" },
+ { "OUT_C", NULL, "DACR" },
+ { "OUT_D", NULL, "DACR" },
+};
+
+static const struct snd_soc_codec_driver tas571x_codec = {
+ .set_bias_level = tas571x_set_bias_level,
+ .idle_bias_off = true,
+
+ .dapm_widgets = tas571x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tas571x_dapm_widgets),
+ .dapm_routes = tas571x_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes),
+};
+
+static struct snd_soc_dai_driver tas571x_dai = {
+ .name = "tas571x-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &tas571x_dai_ops,
+};
+
+static const struct of_device_id tas571x_of_match[];
+
+static int tas571x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tas571x_private *priv;
+ struct device *dev = &client->dev;
+ const struct of_device_id *of_id;
+ int i, ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ i2c_set_clientdata(client, priv);
+
+ of_id = of_match_device(tas571x_of_match, dev);
+ if (!of_id) {
+ dev_err(dev, "Unknown device type\n");
+ return -EINVAL;
+ }
+ priv->chip = of_id->data;
+
+ priv->mclk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) {
+ dev_err(dev, "Failed to request mclk: %ld\n",
+ PTR_ERR(priv->mclk));
+ return PTR_ERR(priv->mclk);
+ }
+
+ BUG_ON(priv->chip->num_supply_names > TAS571X_MAX_SUPPLIES);
+ for (i = 0; i < priv->chip->num_supply_names; i++)
+ priv->supplies[i].supply = priv->chip->supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, priv->chip->num_supply_names,
+ priv->supplies);
+ if (ret) {
+ dev_err(dev, "Failed to get supplies: %d\n", ret);
+ return ret;
+ }
+ ret = regulator_bulk_enable(priv->chip->num_supply_names,
+ priv->supplies);
+ if (ret) {
+ dev_err(dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ priv->regmap = devm_regmap_init(dev, NULL, client,
+ priv->chip->regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ priv->pdn_gpio = devm_gpiod_get_optional(dev, "pdn", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->pdn_gpio)) {
+ dev_err(dev, "error requesting pdn_gpio: %ld\n",
+ PTR_ERR(priv->pdn_gpio));
+ return PTR_ERR(priv->pdn_gpio);
+ }
+
+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset_gpio)) {
+ dev_err(dev, "error requesting reset_gpio: %ld\n",
+ PTR_ERR(priv->reset_gpio));
+ return PTR_ERR(priv->reset_gpio);
+ } else if (priv->reset_gpio) {
+ /* pulse the active low reset line for ~100us */
+ usleep_range(100, 200);
+ gpiod_set_value(priv->reset_gpio, 0);
+ usleep_range(12000, 20000);
+ }
+
+ ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(priv->regmap, TAS571X_SYS_CTRL_2_REG,
+ TAS571X_SYS_CTRL_2_SDN_MASK, 0);
+ if (ret)
+ return ret;
+
+ memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver));
+ priv->codec_driver.controls = priv->chip->controls;
+ priv->codec_driver.num_controls = priv->chip->num_controls;
+
+ if (priv->chip->vol_reg_size == 2) {
+ /*
+ * The master volume defaults to 0x3ff (mute), but we ignore
+ * (zero) the LSB because the hardware step size is 0.125 dB
+ * and TLV_DB_SCALE_ITEM has a resolution of 0.01 dB.
+ */
+ ret = regmap_update_bits(priv->regmap, TAS571X_MVOL_REG, 1, 0);
+ if (ret)
+ return ret;
+ }
+
+ regcache_cache_only(priv->regmap, true);
+ gpiod_set_value(priv->pdn_gpio, 1);
+
+ return snd_soc_register_codec(&client->dev, &priv->codec_driver,
+ &tas571x_dai, 1);
+}
+
+static int tas571x_i2c_remove(struct i2c_client *client)
+{
+ struct tas571x_private *priv = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+ regulator_bulk_disable(priv->chip->num_supply_names, priv->supplies);
+
+ return 0;
+}
+
+static const struct of_device_id tas571x_of_match[] = {
+ { .compatible = "ti,tas5711", .data = &tas5711_chip, },
+ { .compatible = "ti,tas5717", .data = &tas5717_chip, },
+ { .compatible = "ti,tas5719", .data = &tas5717_chip, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tas571x_of_match);
+
+static const struct i2c_device_id tas571x_i2c_id[] = {
+ { "tas5711", 0 },
+ { "tas5717", 0 },
+ { "tas5719", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id);
+
+static struct i2c_driver tas571x_i2c_driver = {
+ .driver = {
+ .name = "tas571x",
+ .of_match_table = of_match_ptr(tas571x_of_match),
+ },
+ .probe = tas571x_i2c_probe,
+ .remove = tas571x_i2c_remove,
+ .id_table = tas571x_i2c_id,
+};
+module_i2c_driver(tas571x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TAS571x driver");
+MODULE_AUTHOR("Kevin Cernekee <cernekee@chromium.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h
new file mode 100644
index 000000000000..0aee471232cd
--- /dev/null
+++ b/sound/soc/codecs/tas571x.h
@@ -0,0 +1,33 @@
+/*
+ * TAS571x amplifier audio driver
+ *
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _TAS571X_H
+#define _TAS571X_H
+
+/* device registers */
+#define TAS571X_SDI_REG 0x04
+#define TAS571X_SDI_FMT_MASK 0x0f
+
+#define TAS571X_SYS_CTRL_2_REG 0x05
+#define TAS571X_SYS_CTRL_2_SDN_MASK 0x40
+
+#define TAS571X_SOFT_MUTE_REG 0x06
+#define TAS571X_SOFT_MUTE_CH1_SHIFT 0
+#define TAS571X_SOFT_MUTE_CH2_SHIFT 1
+#define TAS571X_SOFT_MUTE_CH3_SHIFT 2
+
+#define TAS571X_MVOL_REG 0x07
+#define TAS571X_CH1_VOL_REG 0x08
+#define TAS571X_CH2_VOL_REG 0x09
+
+#define TAS571X_OSC_TRIM_REG 0x1b
+
+#endif /* _TAS571X_H */
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index cc17e7e5126e..cd8c02b6e4de 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -506,7 +506,6 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, TLV320AIC23_PWR, 0x1ff);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index c86dd9aae157..c4c960f592a1 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -646,7 +646,7 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec)
static int aic31xx_add_widgets(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);
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
int ret = 0;
@@ -1027,17 +1027,17 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__,
- codec->dapm.bias_level, level);
+ snd_soc_codec_get_bias_level(codec), level);
switch (level) {
case SND_SOC_BIAS_ON:
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)
aic31xx_clk_on(codec);
break;
case SND_SOC_BIAS_STANDBY:
- switch (codec->dapm.bias_level) {
+ switch (snd_soc_codec_get_bias_level(codec)) {
case SND_SOC_BIAS_OFF:
aic31xx_power_on(codec);
break;
@@ -1049,11 +1049,10 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
}
break;
case SND_SOC_BIAS_OFF:
- if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
aic31xx_power_off(codec);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 015467ed606b..ad6cb90e5f9b 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -564,7 +564,6 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_OFF:
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 51c4713ac6e3..a7cf19b53fb2 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -147,6 +147,7 @@ static int snd_soc_dapm_put_volsw_aic3x(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 soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
@@ -179,7 +180,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
update.mask = mask;
update.val = val;
- snd_soc_dapm_mixer_update_power(&codec->dapm, kcontrol, connect,
+ snd_soc_dapm_mixer_update_power(dapm, kcontrol, connect,
&update);
}
@@ -979,7 +980,7 @@ static const struct snd_soc_dapm_route intercon_3007[] = {
static int aic3x_add_widgets(struct snd_soc_codec *codec)
{
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
switch (aic3x->model) {
case AIC3X_MODEL_3X:
@@ -1384,7 +1385,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
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 &&
aic3x->master) {
/* enable pll */
snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
@@ -1394,7 +1395,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (!aic3x->power)
aic3x_set_power(codec, 1);
- if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE &&
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE &&
aic3x->master) {
/* disable pll */
snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
@@ -1406,7 +1407,6 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
aic3x_set_power(codec, 0);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 4e3e607dec13..d67a311f0e75 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -633,7 +633,7 @@ static int dac33_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) {
/* Coming from OFF, switch on the codec */
ret = dac33_hard_power(codec, 1);
if (ret != 0)
@@ -644,14 +644,13 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_OFF:
/* Do not power off, when the codec is already off */
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
return 0;
ret = dac33_hard_power(codec, 0);
if (ret != 0)
return ret;
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index 9fd80ac1897f..12232d7db4c5 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -254,12 +254,13 @@ static const struct regmap_config ts3a227e_regmap_config = {
.num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults),
};
-static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np)
+static int ts3a227e_parse_device_property(struct ts3a227e *ts3a227e,
+ struct device *dev)
{
u32 micbias;
int err;
- err = of_property_read_u32(np, "ti,micbias", &micbias);
+ err = device_property_read_u32(dev, "ti,micbias", &micbias);
if (!err) {
regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3,
MICBIAS_SETTING_MASK,
@@ -287,12 +288,10 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
if (IS_ERR(ts3a227e->regmap))
return PTR_ERR(ts3a227e->regmap);
- if (dev->of_node) {
- ret = ts3a227e_parse_dt(ts3a227e, dev->of_node);
- if (ret) {
- dev_err(dev, "Failed to parse device tree: %d\n", ret);
- return ret;
- }
+ ret = ts3a227e_parse_device_property(ts3a227e, dev);
+ if (ret) {
+ dev_err(dev, "Failed to parse device property: %d\n", ret);
+ return ret;
}
ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt,
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index d04693e9cf9f..90f5f04eca2d 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -1588,14 +1588,13 @@ static int twl4030_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)
twl4030_codec_enable(codec, 1);
break;
case SND_SOC_BIAS_OFF:
twl4030_codec_enable(codec, 0);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index aeec27b6f1af..4cad8929d262 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -533,7 +533,7 @@ static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
int twl6040_get_dl1_gain(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);
if (snd_soc_dapm_get_pin_status(dapm, "EP"))
return -1; /* -1dB */
@@ -853,8 +853,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
@@ -1123,14 +1121,15 @@ static int twl6040_probe(struct snd_soc_codec *codec)
mutex_init(&priv->mutex);
ret = request_threaded_irq(priv->plug_irq, NULL,
- twl6040_audio_handler, IRQF_NO_SUSPEND,
+ twl6040_audio_handler,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
"twl6040_irq_plug", codec);
if (ret) {
dev_err(codec->dev, "PLUG IRQ request failed: %d\n", ret);
return ret;
}
- twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
twl6040_init_chip(codec);
return 0;
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index f883308c00de..913edf283239 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -350,7 +350,6 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
pd->power(0);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
@@ -478,6 +477,7 @@ static struct snd_soc_dai_driver uda134x_dai = {
static int uda134x_soc_probe(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct uda134x_priv *uda134x;
struct uda134x_platform_data *pd = codec->component.card->dev->platform_data;
const struct snd_soc_dapm_widget *widgets;
@@ -526,7 +526,7 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
num_widgets = ARRAY_SIZE(uda1340_dapm_widgets);
}
- ret = snd_soc_dapm_new_controls(&codec->dapm, widgets, num_widgets);
+ ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
if (ret) {
printk(KERN_ERR "%s failed to register dapm controls: %d",
__func__, ret);
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index c3c33bd0df1c..6e159f59d219 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -590,9 +590,6 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
int reg;
struct uda1380_platform_data *pdata = codec->dev->platform_data;
- if (codec->dapm.bias_level == level)
- return 0;
-
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
@@ -600,7 +597,7 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
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 (gpio_is_valid(pdata->gpio_power)) {
gpio_set_value(pdata->gpio_power, 1);
mdelay(1);
@@ -623,7 +620,6 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
set_bit(reg - 0x10, &uda1380_cache_dirty);
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index f37989ec7cba..6560a66b3f35 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -751,13 +751,13 @@ static int wm0010_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
- if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE)
wm0010_boot(codec);
break;
case SND_SOC_BIAS_PREPARE:
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) {
mutex_lock(&wm0010->lock);
wm0010_halt(codec);
mutex_unlock(&wm0010->lock);
@@ -767,8 +767,6 @@ static int wm0010_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index 8011f75fb6cb..048f00568260 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -61,8 +61,6 @@ static int wm1250_ev1_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 96740379b711..4c10cd88c1af 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2101,7 +2101,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100)
int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
{
struct wm5100_priv *wm5100 = 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 (jack) {
wm5100->jack = jack;
@@ -2336,6 +2336,7 @@ static void wm5100_free_gpio(struct i2c_client *i2c)
static int wm5100_probe(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct i2c_client *i2c = to_i2c_client(codec->dev);
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int ret, i;
@@ -2353,8 +2354,7 @@ static int wm5100_probe(struct snd_soc_codec *codec)
/* TODO: check if we're symmetric */
if (i2c->irq)
- snd_soc_dapm_new_controls(&codec->dapm,
- wm5100_dapm_widgets_noirq,
+ snd_soc_dapm_new_controls(dapm, wm5100_dapm_widgets_noirq,
ARRAY_SIZE(wm5100_dapm_widgets_noirq));
if (wm5100->pdata.hp_pol) {
@@ -2570,11 +2570,13 @@ static int wm5100_i2c_probe(struct i2c_client *i2c,
if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
ret = request_threaded_irq(i2c->irq, NULL,
- wm5100_edge_irq, irq_flags,
+ wm5100_edge_irq,
+ irq_flags | IRQF_ONESHOT,
"wm5100", wm5100);
else
ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
- irq_flags, "wm5100",
+ irq_flags | IRQF_ONESHOT,
+ "wm5100",
wm5100);
if (ret != 0) {
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index d476221dba51..d8959e31853d 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -605,12 +605,56 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
regmap_write_async(regmap, patch[i].reg,
patch[i].def);
break;
+ case SND_SOC_DAPM_PRE_PMD:
+ break;
+ default:
+ return 0;
+ }
+
+ return arizona_dvfs_sysclk_ev(w, kcontrol, event);
+}
+
+static int wm5102_adsp_power_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 *arizona = dev_get_drvdata(codec->dev->parent);
+ unsigned int v;
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &v);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to read SYSCLK state: %d\n", ret);
+ return -EIO;
+ }
+
+ v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
+
+ if (v >= 3) {
+ ret = arizona_dvfs_up(codec, ARIZONA_DVFS_ADSP1_RQ);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to raise DVFS: %d\n", ret);
+ return ret;
+ }
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ ret = arizona_dvfs_down(codec, ARIZONA_DVFS_ADSP1_RQ);
+ if (ret)
+ dev_warn(codec->dev,
+ "Failed to lower DVFS: %d\n", ret);
+ break;
default:
break;
}
- return 0;
+ return wm_adsp2_early_event(w, kcontrol, event);
}
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
@@ -1036,7 +1080,8 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
- 0, wm5102_sysclk_ev, SND_SOC_DAPM_POST_PMU),
+ 0, wm5102_sysclk_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
@@ -1367,7 +1412,7 @@ ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
-WM_ADSP2("DSP1", 0),
+WM_ADSP2_E("DSP1", 0, wm5102_adsp_power_ev),
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
@@ -1827,6 +1872,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
static int wm5102_codec_probe(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret;
@@ -1837,9 +1883,9 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
arizona_init_spk(codec);
arizona_init_gpio(codec);
- snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
- priv->core.arizona->dapm = &codec->dapm;
+ priv->core.arizona->dapm = dapm;
return 0;
}
@@ -1909,6 +1955,8 @@ static int wm5102_probe(struct platform_device *pdev)
wm5102->core.arizona = arizona;
wm5102->core.num_inputs = 6;
+ arizona_init_dvfs(&wm5102->core);
+
wm5102->core.adsp[0].part = "wm5102";
wm5102->core.adsp[0].num = 1;
wm5102->core.adsp[0].type = WMFW_ADSP2;
@@ -1918,7 +1966,7 @@ static int wm5102_probe(struct platform_device *pdev)
wm5102->core.adsp[0].mem = wm5102_dsp1_regions;
wm5102->core.adsp[0].num_mems = ARRAY_SIZE(wm5102_dsp1_regions);
- ret = wm_adsp2_init(&wm5102->core.adsp[0], true);
+ ret = wm_adsp2_init(&wm5102->core.adsp[0]);
if (ret != 0)
return ret;
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 3ee6cfd0578b..14a7739d6c09 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -1598,10 +1598,11 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
static int wm5110_codec_probe(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
int ret;
- priv->core.arizona->dapm = &codec->dapm;
+ priv->core.arizona->dapm = dapm;
arizona_init_spk(codec);
arizona_init_gpio(codec);
@@ -1611,9 +1612,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
if (ret != 0)
return ret;
- snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
-
- priv->core.arizona->dapm = &codec->dapm;
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
return 0;
}
@@ -1697,7 +1696,7 @@ static int wm5110_probe(struct platform_device *pdev)
wm5110->core.adsp[i].num_mems
= ARRAY_SIZE(wm5110_dsp1_regions);
- ret = wm_adsp2_init(&wm5110->core.adsp[i], false);
+ ret = wm_adsp2_init(&wm5110->core.adsp[i]);
if (ret != 0)
return ret;
}
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index c65e5a75fc1a..41c62c1e62db 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1102,7 +1102,7 @@ static int wm8350_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(priv->supplies),
priv->supplies);
if (ret != 0)
@@ -1235,7 +1235,6 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
priv->supplies);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index b0d84e552fca..d7555085e7f4 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -1145,7 +1145,7 @@ static int wm8400_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(power),
&power[0]);
if (ret != 0) {
@@ -1232,7 +1232,6 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 8736ad094b24..dac5beb4d023 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -519,7 +519,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
regcache_sync(wm8510->regmap);
/* Initial cap charge at VMID 5k */
@@ -538,7 +538,6 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index b1cc94f5fc4b..8c5b9df3e542 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -308,7 +308,7 @@ static int wm8523_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(wm8523->supplies),
wm8523->supplies);
if (ret != 0) {
@@ -344,7 +344,6 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
wm8523->supplies);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 0a887c5ec83a..759a7928ac3e 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -795,7 +795,7 @@ static int wm8580_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) {
/* Power up and get individual control of the DACs */
snd_soc_update_bits(codec, WM8580_PWRDN1,
WM8580_PWRDN1_PWDN |
@@ -812,7 +812,6 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 121e46d53779..cc8251f09f8a 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -310,7 +310,7 @@ static int wm8711_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)
regcache_sync(wm8711->regmap);
snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
@@ -320,7 +320,6 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8711_PWR, 0xffff);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 55c7fb4fc786..f1a173e6ec33 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -170,7 +170,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
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) {
/* Power everything up... */
reg = snd_soc_read(codec, WM8728_DACCTL);
snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
@@ -185,7 +185,6 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 2245b6a32f3d..915ea11ad4b6 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -387,6 +387,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
switch (clk_id) {
@@ -421,7 +422,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
wm8731->sysclk = freq;
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_sync(dapm);
return 0;
}
@@ -501,7 +502,7 @@ static int wm8731_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(wm8731->supplies),
wm8731->supplies);
if (ret != 0)
@@ -523,7 +524,6 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
regcache_mark_dirty(wm8731->regmap);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
@@ -599,7 +599,7 @@ static int wm8731_probe(struct snd_soc_codec *codec)
goto err_regulator_enable;
}
- wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */
snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0);
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 51171e457fa4..6ad606fd8b69 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -469,7 +469,7 @@ static int wm8737_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(wm8737->supplies),
wm8737->supplies);
if (ret != 0) {
@@ -512,7 +512,6 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
@@ -562,7 +561,7 @@ static int wm8737_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
WM8737_RVU);
- wm8737_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(wm8737->supplies), wm8737->supplies);
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 9e71c768966f..09ff01f2fc1e 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -41,6 +41,7 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
/* codec private data */
struct wm8741_priv {
+ struct wm8741_platform_data pdata;
struct regmap *regmap;
struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
unsigned int sysclk;
@@ -87,13 +88,27 @@ static int wm8741_reset(struct snd_soc_codec *codec)
static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0);
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0);
-static const struct snd_kcontrol_new wm8741_snd_controls[] = {
+static const struct snd_kcontrol_new wm8741_snd_controls_stereo[] = {
SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine),
SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv),
};
+static const struct snd_kcontrol_new wm8741_snd_controls_mono_left[] = {
+SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
+ 1, 255, 1, dac_tlv_fine),
+SOC_SINGLE_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
+ 0, 511, 1, dac_tlv),
+};
+
+static const struct snd_kcontrol_new wm8741_snd_controls_mono_right[] = {
+SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACRLSB_ATTENUATION,
+ 1, 255, 1, dac_tlv_fine),
+SOC_SINGLE_TLV("Playback Volume", WM8741_DACRMSB_ATTENUATION,
+ 0, 511, 1, dac_tlv),
+};
+
static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0),
@@ -398,7 +413,7 @@ static struct snd_soc_dai_driver wm8741_dai = {
.name = "wm8741",
.playback = {
.stream_name = "Playback",
- .channels_min = 2, /* Mono modes not yet supported */
+ .channels_min = 2,
.channels_max = 2,
.rates = WM8741_RATES,
.formats = WM8741_FORMATS,
@@ -416,6 +431,65 @@ static int wm8741_resume(struct snd_soc_codec *codec)
#define wm8741_resume NULL
#endif
+static int wm8741_configure(struct snd_soc_codec *codec)
+{
+ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+
+ /* Configure differential mode */
+ switch (wm8741->pdata.diff_mode) {
+ case WM8741_DIFF_MODE_STEREO:
+ case WM8741_DIFF_MODE_STEREO_REVERSED:
+ case WM8741_DIFF_MODE_MONO_LEFT:
+ case WM8741_DIFF_MODE_MONO_RIGHT:
+ snd_soc_update_bits(codec, WM8741_MODE_CONTROL_2,
+ WM8741_DIFF_MASK,
+ wm8741->pdata.diff_mode << WM8741_DIFF_SHIFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Change some default settings - latch VU */
+ snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION,
+ WM8741_UPDATELL, WM8741_UPDATELL);
+ snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION,
+ WM8741_UPDATELM, WM8741_UPDATELM);
+ snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
+ WM8741_UPDATERL, WM8741_UPDATERL);
+ snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
+ WM8741_UPDATERM, WM8741_UPDATERM);
+
+ return 0;
+}
+
+static int wm8741_add_controls(struct snd_soc_codec *codec)
+{
+ struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
+
+ switch (wm8741->pdata.diff_mode) {
+ case WM8741_DIFF_MODE_STEREO:
+ case WM8741_DIFF_MODE_STEREO_REVERSED:
+ snd_soc_add_codec_controls(codec,
+ wm8741_snd_controls_stereo,
+ ARRAY_SIZE(wm8741_snd_controls_stereo));
+ break;
+ case WM8741_DIFF_MODE_MONO_LEFT:
+ snd_soc_add_codec_controls(codec,
+ wm8741_snd_controls_mono_left,
+ ARRAY_SIZE(wm8741_snd_controls_mono_left));
+ break;
+ case WM8741_DIFF_MODE_MONO_RIGHT:
+ snd_soc_add_codec_controls(codec,
+ wm8741_snd_controls_mono_right,
+ ARRAY_SIZE(wm8741_snd_controls_mono_right));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int wm8741_probe(struct snd_soc_codec *codec)
{
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
@@ -434,15 +508,17 @@ static int wm8741_probe(struct snd_soc_codec *codec)
goto err_enable;
}
- /* Change some default settings - latch VU */
- snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION,
- WM8741_UPDATELL, WM8741_UPDATELL);
- snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION,
- WM8741_UPDATELM, WM8741_UPDATELM);
- snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
- WM8741_UPDATERL, WM8741_UPDATERL);
- snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
- WM8741_UPDATERM, WM8741_UPDATERM);
+ ret = wm8741_configure(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to change default settings\n");
+ goto err_enable;
+ }
+
+ ret = wm8741_add_controls(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to add controls\n");
+ goto err_enable;
+ }
dev_dbg(codec->dev, "Successful registration\n");
return ret;
@@ -467,8 +543,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
.remove = wm8741_remove,
.resume = wm8741_resume,
- .controls = wm8741_snd_controls,
- .num_controls = ARRAY_SIZE(wm8741_snd_controls),
.dapm_widgets = wm8741_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets),
.dapm_routes = wm8741_dapm_routes,
@@ -493,6 +567,23 @@ static const struct regmap_config wm8741_regmap = {
.readable_reg = wm8741_readable,
};
+static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
+{
+ const struct wm8741_platform_data *pdata = dev_get_platdata(dev);
+ u32 diff_mode;
+
+ if (dev->of_node) {
+ if (of_property_read_u32(dev->of_node, "diff-mode", &diff_mode)
+ >= 0)
+ wm8741->pdata.diff_mode = diff_mode;
+ } else {
+ if (pdata != NULL)
+ memcpy(&wm8741->pdata, pdata, sizeof(wm8741->pdata));
+ }
+
+ return 0;
+}
+
#if IS_ENABLED(CONFIG_I2C)
static int wm8741_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
@@ -522,6 +613,12 @@ static int wm8741_i2c_probe(struct i2c_client *i2c,
return ret;
}
+ ret = wm8741_set_pdata(&i2c->dev, wm8741);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to set pdata: %d\n", ret);
+ return ret;
+ }
+
i2c_set_clientdata(i2c, wm8741);
ret = snd_soc_register_codec(&i2c->dev,
@@ -582,6 +679,12 @@ static int wm8741_spi_probe(struct spi_device *spi)
return ret;
}
+ ret = wm8741_set_pdata(&spi->dev, wm8741);
+ if (ret != 0) {
+ dev_err(&spi->dev, "Failed to set pdata: %d\n", ret);
+ return ret;
+ }
+
spi_set_drvdata(spi, wm8741);
ret = snd_soc_register_codec(&spi->dev,
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h
index 56c1b1d4a681..c8835f65f342 100644
--- a/sound/soc/codecs/wm8741.h
+++ b/sound/soc/codecs/wm8741.h
@@ -194,6 +194,12 @@
#define WM8741_DITHER_SHIFT 0 /* DITHER - [1:0] */
#define WM8741_DITHER_WIDTH 2 /* DITHER - [1:0] */
+/* DIFF field values */
+#define WM8741_DIFF_MODE_STEREO 0 /* stereo normal */
+#define WM8741_DIFF_MODE_STEREO_REVERSED 2 /* stereo reversed */
+#define WM8741_DIFF_MODE_MONO_LEFT 1 /* mono left */
+#define WM8741_DIFF_MODE_MONO_RIGHT 3 /* mono right */
+
/*
* R32 (0x20) - ADDITONAL_CONTROL_1
*/
@@ -208,4 +214,8 @@
#define WM8741_SYSCLK 0
+struct wm8741_platform_data {
+ u32 diff_mode; /* Differential Output Mode */
+};
+
#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index eb0a1644ba11..56d89b0865fa 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -634,7 +634,7 @@ static int wm8750_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) {
snd_soc_cache_sync(codec);
/* Set VMID to 5k */
@@ -651,7 +651,6 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8750_PWR1, 0x0001);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index c50a5959345f..feb2997a377a 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1352,7 +1352,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
flush_delayed_work(&wm8753->charge_work);
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) {
/* set vmid to 5k for quick power up */
snd_soc_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
schedule_delayed_work(&wm8753->charge_work,
@@ -1367,7 +1367,6 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8753_PWR1, 0x0001);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index 53e977da2f86..66c1f151071d 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -510,7 +510,7 @@ static int wm8770_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(wm8770->supplies),
wm8770->supplies);
if (ret) {
@@ -534,7 +534,6 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index c13050b77931..ece9b4456767 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -344,7 +344,7 @@ static int wm8776_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) {
regcache_sync(wm8776->regmap);
/* Disable the global powerdown; DAPM does the rest */
@@ -357,7 +357,6 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 1e403f67cf16..c195c2e8af07 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -162,7 +162,7 @@ static int txsrc_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 = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val = ucontrol->value.enumerated.item[0] << e->shift_l;
unsigned int mask = 1 << e->shift_l;
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index fdb765600a10..f3759ec5a863 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -1049,7 +1049,7 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
/* Charge capacitors if initial power up */
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
/* STARTUP_BIAS_ENA on */
snd_soc_write(codec, WM8900_REG_POWER1,
WM8900_REG_POWER1_STARTUP_BIAS_ENA);
@@ -1117,7 +1117,6 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
WM8900_REG_POWER2_SYSCLK_ENA);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
@@ -1138,7 +1137,7 @@ static int wm8900_suspend(struct snd_soc_codec *codec)
wm8900->fll_out = fll_out;
wm8900->fll_in = fll_in;
- wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
@@ -1156,7 +1155,7 @@ static int wm8900_resume(struct snd_soc_codec *codec)
return ret;
}
- wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Restart the FLL? */
if (wm8900->fll_out) {
@@ -1189,7 +1188,7 @@ static int wm8900_probe(struct snd_soc_codec *codec)
wm8900_reset(codec);
/* Turn the chip on */
- wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the volume update bits */
snd_soc_update_bits(codec, WM8900_REG_LINVOL, 0x100, 0x100);
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 04b04f8e147c..b5322c1544fb 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1105,7 +1105,7 @@ static int wm8903_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, WM8903_BIAS_CONTROL_0,
WM8903_POBCTRL | WM8903_ISEL_MASK |
WM8903_STARTUP_BIAS_ENA |
@@ -1200,8 +1200,6 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 215e93c1ddf0..265a4a58a2d1 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -1168,7 +1168,7 @@ static const struct snd_soc_dapm_route wm8912_intercon[] = {
static int wm8904_add_widgets(struct snd_soc_codec *codec)
{
struct wm8904_priv *wm8904 = 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_dapm_new_controls(dapm, wm8904_core_dapm_widgets,
ARRAY_SIZE(wm8904_core_dapm_widgets));
@@ -1852,7 +1852,7 @@ static int wm8904_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(wm8904->supplies),
wm8904->supplies);
if (ret != 0) {
@@ -1907,7 +1907,6 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
clk_disable_unprepare(wm8904->mclk);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index e4142b4309eb..98ef0ba5c2a4 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -492,7 +492,7 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
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(wm8940->regmap);
if (ret < 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
@@ -510,8 +510,6 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return ret;
}
@@ -707,7 +705,7 @@ static int wm8940_probe(struct snd_soc_codec *codec)
return ret;
}
- wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
if (ret < 0)
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 03e04bf6c5ba..2d591c24704b 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -785,7 +785,7 @@ static int wm8955_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(wm8955->supplies),
wm8955->supplies);
if (ret != 0) {
@@ -838,7 +838,6 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
wm8955->supplies);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
@@ -929,7 +928,7 @@ static int wm8955_probe(struct snd_soc_codec *codec)
WM8955_DMEN, WM8955_DMEN);
}
- wm8955_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(wm8955->supplies), wm8955->supplies);
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 8d7f63253440..94c5c4681ce5 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -127,6 +127,8 @@ struct wm8960_priv {
struct snd_soc_dapm_widget *out3;
bool deemph;
int playback_fs;
+ int bclk;
+ int sysclk;
struct wm8960_data pdata;
};
@@ -445,7 +447,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
{
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
struct wm8960_data *pdata = &wm8960->pdata;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct snd_soc_dapm_widget *w;
snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets,
@@ -476,7 +478,7 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
* and save the result.
*/
list_for_each_entry(w, &codec->component.card->widgets, list) {
- if (w->dapm != &codec->dapm)
+ if (w->dapm != dapm)
continue;
if (strcmp(w->name, "LOUT1 PGA") == 0)
wm8960->lout1 = w;
@@ -563,6 +565,72 @@ static struct {
{ 8000, 5 },
};
+/* Multiply 256 for internal 256 div */
+static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 };
+
+/* Multiply 10 to eliminate decimials */
+static const int bclk_divs[] = {
+ 10, 15, 20, 30, 40, 55, 60, 80, 110,
+ 120, 160, 220, 240, 320, 320, 320
+};
+
+static void wm8960_configure_clocking(struct snd_soc_codec *codec,
+ bool tx, int lrclk)
+{
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ u16 iface1 = snd_soc_read(codec, WM8960_IFACE1);
+ u16 iface2 = snd_soc_read(codec, WM8960_IFACE2);
+ u32 sysclk;
+ int i, j;
+
+ if (!(iface1 & (1<<6))) {
+ dev_dbg(codec->dev,
+ "Codec is slave mode, no need to configure clock\n");
+ return;
+ }
+
+ if (!wm8960->sysclk) {
+ dev_dbg(codec->dev, "No SYSCLK configured\n");
+ return;
+ }
+
+ if (!wm8960->bclk || !lrclk) {
+ dev_dbg(codec->dev, "No audio clocks configured\n");
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) {
+ if (wm8960->sysclk == lrclk * dac_divs[i]) {
+ for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) {
+ sysclk = wm8960->bclk * bclk_divs[j] / 10;
+ if (wm8960->sysclk == sysclk)
+ break;
+ }
+ if(j != ARRAY_SIZE(bclk_divs))
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(dac_divs)) {
+ dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk);
+ return;
+ }
+
+ /*
+ * configure frame clock. If ADCLRC configure as GPIO pin, DACLRC
+ * pin is used as a frame clock for ADCs and DACs.
+ */
+ if (iface2 & (1<<6))
+ snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
+ else if (tx)
+ snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
+ else if (!tx)
+ snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6);
+
+ /* configure bit clock */
+ snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j);
+}
+
static int wm8960_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -570,8 +638,13 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
int i;
+ wm8960->bclk = snd_soc_params_to_bclk(params);
+ if (params_channels(params) == 1)
+ wm8960->bclk *= 2;
+
/* bit size */
switch (params_width(params)) {
case 16:
@@ -582,6 +655,12 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
case 24:
iface |= 0x0008;
break;
+ case 32:
+ /* right justify mode does not support 32 word length */
+ if ((iface & 0x3) != 0) {
+ iface |= 0x000c;
+ break;
+ }
default:
dev_err(codec->dev, "unsupported width %d\n",
params_width(params));
@@ -602,6 +681,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
/* set iface */
snd_soc_write(codec, WM8960_IFACE1, iface);
+
+ wm8960_configure_clocking(codec, tx, params_rate(params));
+
return 0;
}
@@ -627,7 +709,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_PREPARE:
- switch (codec->dapm.bias_level) {
+ switch (snd_soc_codec_get_bias_level(codec)) {
case SND_SOC_BIAS_STANDBY:
if (!IS_ERR(wm8960->mclk)) {
ret = clk_prepare_enable(wm8960->mclk);
@@ -655,7 +737,7 @@ static int wm8960_set_bias_level_out3(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(wm8960->regmap);
/* Enable anti-pop features */
@@ -691,8 +773,6 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
@@ -707,7 +787,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_PREPARE:
- switch (codec->dapm.bias_level) {
+ switch (snd_soc_codec_get_bias_level(codec)) {
case SND_SOC_BIAS_STANDBY:
/* Enable anti pop mode */
snd_soc_update_bits(codec, WM8960_APOP1,
@@ -778,7 +858,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
- switch (codec->dapm.bias_level) {
+ switch (snd_soc_codec_get_bias_level(codec)) {
case SND_SOC_BIAS_PREPARE:
/* Disable HP discharge */
snd_soc_update_bits(codec, WM8960_APOP2,
@@ -802,8 +882,6 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
@@ -950,11 +1028,35 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec,
return wm8960->set_bias_level(codec, level);
}
+static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+ switch (clk_id) {
+ case WM8960_SYSCLK_MCLK:
+ snd_soc_update_bits(codec, WM8960_CLOCK1,
+ 0x1, WM8960_SYSCLK_MCLK);
+ break;
+ case WM8960_SYSCLK_PLL:
+ snd_soc_update_bits(codec, WM8960_CLOCK1,
+ 0x1, WM8960_SYSCLK_PLL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ wm8960->sysclk = freq;
+
+ return 0;
+}
+
#define WM8960_RATES SNDRV_PCM_RATE_8000_48000
#define WM8960_FORMATS \
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops wm8960_dai_ops = {
.hw_params = wm8960_hw_params,
@@ -962,6 +1064,7 @@ static const struct snd_soc_dai_ops wm8960_dai_ops = {
.set_fmt = wm8960_set_dai_fmt,
.set_clkdiv = wm8960_set_dai_clkdiv,
.set_pll = wm8960_set_dai_pll,
+ .set_sysclk = wm8960_set_dai_sysclk,
};
static struct snd_soc_dai_driver wm8960_dai = {
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 95e2c1bfc809..a057662632ff 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -758,7 +758,7 @@ static int wm8961_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) {
/* Enable bias generation */
reg = snd_soc_read(codec, WM8961_ANTI_POP);
reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN;
@@ -773,7 +773,7 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
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) {
/* VREF off */
reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
reg &= ~WM8961_VREF;
@@ -795,8 +795,6 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 118b0034ba23..c5748fd4f296 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2361,7 +2361,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
{
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
struct wm8962_pdata *pdata = &wm8962->pdata;
- 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, wm8962_snd_controls,
ARRAY_SIZE(wm8962_snd_controls));
@@ -2446,13 +2446,13 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
* So we here provisionally enable it and then disable it afterward
* if current bias_level hasn't reached SND_SOC_BIAS_ON.
*/
- if (codec->dapm.bias_level != SND_SOC_BIAS_ON)
+ if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON)
snd_soc_update_bits(codec, WM8962_CLOCKING2,
WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA);
dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
- if (codec->dapm.bias_level != SND_SOC_BIAS_ON)
+ if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON)
snd_soc_update_bits(codec, WM8962_CLOCKING2,
WM8962_SYSCLK_ENA_MASK, 0);
@@ -2510,9 +2510,6 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
static int wm8962_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- if (level == codec->dapm.bias_level)
- return 0;
-
switch (level) {
case SND_SOC_BIAS_ON:
break;
@@ -2530,7 +2527,7 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
WM8962_VMID_SEL_MASK, 0x100);
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
msleep(100);
break;
@@ -2538,7 +2535,6 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
@@ -2614,7 +2610,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
dev_dbg(codec->dev, "hw_params set BCLK %dHz LRCLK %dHz\n",
wm8962->bclk, wm8962->lrclk);
- if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON)
wm8962_configure_bclk(codec);
return 0;
@@ -3118,7 +3114,7 @@ static irqreturn_t wm8962_irq(int irq, void *data)
int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
{
struct wm8962_priv *wm8962 = 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 irq_mask, enable;
wm8962->jack = jack;
@@ -3164,7 +3160,7 @@ static void wm8962_beep_work(struct work_struct *work)
struct wm8962_priv *wm8962 =
container_of(work, struct wm8962_priv, beep_work);
struct snd_soc_codec *codec = wm8962->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
int i;
int reg = 0;
int best = 0;
@@ -3415,6 +3411,7 @@ static void wm8962_free_gpio(struct snd_soc_codec *codec)
static int wm8962_probe(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
int ret;
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
int i;
@@ -3462,7 +3459,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
}
if (!dmicclk || !dmicdat) {
dev_dbg(codec->dev, "DMIC not in use, disabling\n");
- snd_soc_dapm_nc_pin(&codec->dapm, "DMICDAT");
+ snd_soc_dapm_nc_pin(dapm, "DMICDAT");
}
if (dmicclk != dmicdat)
dev_warn(codec->dev, "DMIC GPIOs partially configured\n");
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index f9cbabdc6238..b51184c4e816 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -577,7 +577,7 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
flush_delayed_work(&wm8971->charge_work);
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_cache_sync(codec);
/* charge output caps - set vmid to 5k for quick power up */
snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x01c0);
@@ -594,7 +594,6 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8971_PWR1, 0x0001);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index ff0e4646b934..33b16a7ba82e 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -514,7 +514,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
regcache_sync(dev_get_regmap(codec->dev, NULL));
/* Initial cap charge at VMID 5k */
@@ -533,7 +533,6 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index cf7032911721..cfc8cdf49970 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -868,7 +868,7 @@ static int wm8978_set_bias_level(struct snd_soc_codec *codec,
/* bit 3: enable bias, bit 2: enable I/O tie off buffer */
power1 |= 0xc;
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
/* Initial cap charge at VMID 5k */
snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1,
power1 | 0x3);
@@ -888,7 +888,6 @@ static int wm8978_set_bias_level(struct snd_soc_codec *codec,
dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1);
- codec->dapm.bias_level = level;
return 0;
}
@@ -928,7 +927,7 @@ static int wm8978_suspend(struct snd_soc_codec *codec)
{
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
- wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
/* Also switch PLL off */
snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
@@ -944,7 +943,7 @@ static int wm8978_resume(struct snd_soc_codec *codec)
/* Sync reg_cache with the hardware */
regcache_sync(wm8978->regmap);
- wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
if (wm8978->f_pllout)
/* Switch PLL on */
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 5d1cf08a72b8..2fdd2c6cc09d 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -915,7 +915,7 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec,
1 << WM8983_VMIDSEL_SHIFT);
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(wm8983->regmap);
if (ret < 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
@@ -963,7 +963,6 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 0b3b54c9971d..8a85f5004d41 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -897,7 +897,7 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
1 << WM8985_VMIDSEL_SHIFT);
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(wm8985->supplies),
wm8985->supplies);
if (ret) {
@@ -957,7 +957,6 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 24968aa8618a..f13a995af277 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -738,7 +738,7 @@ static int wm8988_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(wm8988->regmap);
/* VREF, VMID=2x5k */
@@ -756,7 +756,6 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8988_PWR1, 0x0000);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index c93bffcb3cfb..1993fd2a6f15 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1124,7 +1124,7 @@ static int wm8990_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 = regcache_sync(wm8990->regmap);
if (ret < 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
@@ -1227,7 +1227,6 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
@@ -1281,7 +1280,7 @@ static int wm8990_probe(struct snd_soc_codec *codec)
wm8990_reset(codec);
/* charge output caps */
- wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
snd_soc_update_bits(codec, WM8990_AUDIO_INTERFACE_4,
WM8990_ALRCGPIO1, WM8990_ALRCGPIO1);
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 49df0dc607e6..44a677720828 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -1131,7 +1131,7 @@ static int wm8991_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(wm8991->regmap);
/* Enable all output discharge bits */
snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
@@ -1224,7 +1224,6 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 2e70a270eb28..8a8db8605dc2 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -992,7 +992,7 @@ static int wm8993_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(wm8993->supplies),
wm8993->supplies);
if (ret != 0)
@@ -1065,8 +1065,6 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
@@ -1485,7 +1483,7 @@ static struct snd_soc_dai_driver wm8993_dai = {
static int wm8993_probe(struct snd_soc_codec *codec)
{
struct wm8993_priv *wm8993 = 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);
wm8993->hubs_data.hp_startup_mode = 1;
wm8993->hubs_data.dcs_codes_l = -2;
@@ -1539,7 +1537,7 @@ static int wm8993_probe(struct snd_soc_codec *codec)
* VMID as an output and can disable it.
*/
if (wm8993->pdata.lineout1_diff && wm8993->pdata.lineout2_diff)
- codec->dapm.idle_bias_off = 1;
+ dapm->idle_bias_off = 1;
return 0;
@@ -1563,7 +1561,7 @@ static int wm8993_suspend(struct snd_soc_codec *codec)
wm8993->fll_fout = fll_fout;
wm8993->fll_fref = fll_fref;
- wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
@@ -1573,7 +1571,7 @@ static int wm8993_resume(struct snd_soc_codec *codec)
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
int ret;
- wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Restart the FLL? */
if (wm8993->fll_fout) {
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index a1c04dab6684..962e1d31a629 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -212,6 +212,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
static int configure_clock(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int change, new;
@@ -239,7 +240,7 @@ static int configure_clock(struct snd_soc_codec *codec)
change = snd_soc_update_bits(codec, WM8994_CLOCKING_1,
WM8994_SYSCLK_SRC, new);
if (change)
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_sync(dapm);
wm8958_micd_set_rate(codec);
@@ -2492,12 +2493,12 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
break;
}
- if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
active_reference(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) {
switch (control->type) {
case WM8958:
if (control->revision == 0) {
@@ -2521,7 +2522,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
WM8994_LINEOUT2_DISCH);
}
- if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE)
active_dereference(codec);
/* MICBIAS into bypass mode on newer devices */
@@ -2541,20 +2542,18 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_OFF:
- if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
wm8994->cur_fw = NULL;
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)
{
struct wm8994_priv *wm8994 = 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 (mode) {
case WM8994_VMID_NORMAL:
@@ -3163,7 +3162,7 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec)
i + 1, ret);
}
- wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
@@ -3356,6 +3355,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
int micbias)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994_micdet *micdet;
struct wm8994 *control = wm8994->wm8994;
@@ -3370,20 +3370,16 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
case 1:
micdet = &wm8994->micdet[0];
if (jack)
- ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
- "MICBIAS1");
+ ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
else
- ret = snd_soc_dapm_disable_pin(&codec->dapm,
- "MICBIAS1");
+ ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
break;
case 2:
micdet = &wm8994->micdet[1];
if (jack)
- ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
- "MICBIAS1");
+ ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
else
- ret = snd_soc_dapm_disable_pin(&codec->dapm,
- "MICBIAS1");
+ ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
break;
default:
dev_warn(codec->dev, "Invalid MICBIAS %d\n", micbias);
@@ -3415,7 +3411,7 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK,
WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB);
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_sync(dapm);
return 0;
}
@@ -3505,6 +3501,7 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
/* Should be called with accdet_lock held */
static void wm1811_micd_stop(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (!wm8994->jackdet)
@@ -3515,8 +3512,7 @@ static void wm1811_micd_stop(struct snd_soc_codec *codec)
wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK);
if (wm8994->wm8994->pdata.jd_ext_cap)
- snd_soc_dapm_disable_pin(&codec->dapm,
- "MICBIAS2");
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
}
static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
@@ -3625,14 +3621,14 @@ static void wm1811_mic_work(struct work_struct *work)
mic_work.work);
struct wm8994 *control = wm8994->wm8994;
struct snd_soc_codec *codec = wm8994->hubs.codec;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
pm_runtime_get_sync(codec->dev);
/* If required for an external cap force MICBIAS on */
if (control->pdata.jd_ext_cap) {
- snd_soc_dapm_force_enable_pin(&codec->dapm,
- "MICBIAS2");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2");
+ snd_soc_dapm_sync(dapm);
}
mutex_lock(&wm8994->accdet_lock);
@@ -3664,6 +3660,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
struct wm8994_priv *wm8994 = data;
struct wm8994 *control = wm8994->wm8994;
struct snd_soc_codec *codec = wm8994->hubs.codec;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
int reg, delay;
bool present;
@@ -3724,7 +3721,7 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
/* Turn off MICBIAS if it was on for an external cap */
if (control->pdata.jd_ext_cap && !present)
- snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
if (present)
snd_soc_jack_report(wm8994->micdet[0].jack,
@@ -3770,6 +3767,7 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
wm1811_micdet_cb det_cb, void *det_cb_data,
wm1811_mic_id_cb id_cb, void *id_cb_data)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
u16 micd_lvl_sel;
@@ -3783,8 +3781,8 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
}
if (jack) {
- snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_force_enable_pin(dapm, "CLK_SYS");
+ snd_soc_dapm_sync(dapm);
wm8994->micdet[0].jack = jack;
@@ -3819,7 +3817,7 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
snd_soc_update_bits(codec, WM8958_MIC_DETECT_2,
WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel);
- WARN_ON(codec->dapm.bias_level > SND_SOC_BIAS_STANDBY);
+ WARN_ON(snd_soc_codec_get_bias_level(codec) > SND_SOC_BIAS_STANDBY);
/*
* If we can use jack detection start off with that,
@@ -3846,8 +3844,8 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, 0);
wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_NONE);
- snd_soc_dapm_disable_pin(&codec->dapm, "CLK_SYS");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_disable_pin(dapm, "CLK_SYS");
+ snd_soc_dapm_sync(dapm);
}
return 0;
@@ -3985,9 +3983,9 @@ static irqreturn_t wm8994_temp_shut(int irq, void *data)
static int wm8994_codec_probe(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8994 *control = dev_get_drvdata(codec->dev->parent);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
unsigned int reg;
int ret, i;
@@ -4018,7 +4016,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994->micdet_irq = control->pdata.micdet_irq;
/* By default use idle_bias_off, will override for WM8994 */
- codec->dapm.idle_bias_off = 1;
+ dapm->idle_bias_off = 1;
/* Set revision-specific configuration */
switch (control->type) {
@@ -4026,7 +4024,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
/* Single ended line outputs should have VMID on. */
if (!control->pdata.lineout1_diff ||
!control->pdata.lineout2_diff)
- codec->dapm.idle_bias_off = 0;
+ dapm->idle_bias_off = 0;
switch (control->revision) {
case 2:
@@ -4086,7 +4084,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
if (wm8994->micdet_irq)
ret = request_threaded_irq(wm8994->micdet_irq, NULL,
wm8994_mic_irq,
- IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT,
"Mic1 detect",
wm8994);
else
@@ -4134,7 +4133,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
if (wm8994->micdet_irq) {
ret = request_threaded_irq(wm8994->micdet_irq, NULL,
wm8958_mic_irq,
- IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT,
"Mic detect",
wm8994);
if (ret != 0)
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 66103c2b012e..687c4dd7ec99 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -721,6 +721,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
static int configure_clock(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8995_priv *wm8995;
int change, new;
@@ -751,7 +752,7 @@ static int configure_clock(struct snd_soc_codec *codec)
if (!change)
return 0;
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_sync(dapm);
return 0;
}
@@ -1965,7 +1966,7 @@ static int wm8995_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(wm8995->supplies),
wm8995->supplies);
if (ret)
@@ -1990,7 +1991,6 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
return 0;
}
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 308748a022c5..3dd063f682b2 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -1590,7 +1590,7 @@ static int wm8996_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(wm8996->supplies),
wm8996->supplies);
if (ret != 0) {
@@ -1628,8 +1628,6 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
@@ -2247,7 +2245,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
wm8996_polarity_fn polarity_cb)
{
struct wm8996_priv *wm8996 = 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);
wm8996->jack = jack;
wm8996->detecting = true;
@@ -2292,6 +2290,7 @@ EXPORT_SYMBOL_GPL(wm8996_detect);
static void wm8996_hpdet_irq(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
int val, reg, report;
@@ -2345,12 +2344,14 @@ out:
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA,
WM8996_MICD_ENA);
- snd_soc_dapm_disable_pin(&codec->dapm, "Bandgap");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_disable_pin(dapm, "Bandgap");
+ snd_soc_dapm_sync(dapm);
}
static void wm8996_hpdet_start(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
/* Unclamp the output, we can't measure while we're shorting it */
snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1,
WM8996_HPOUT1L_RMV_SHORT |
@@ -2359,8 +2360,8 @@ static void wm8996_hpdet_start(struct snd_soc_codec *codec)
WM8996_HPOUT1R_RMV_SHORT);
/* We need bandgap for HPDET */
- snd_soc_dapm_force_enable_pin(&codec->dapm, "Bandgap");
- snd_soc_dapm_sync(&codec->dapm);
+ snd_soc_dapm_force_enable_pin(dapm, "Bandgap");
+ snd_soc_dapm_sync(dapm);
/* Go into headphone detect left mode */
snd_soc_update_bits(codec, WM8996_MIC_DETECT_1, WM8996_MICD_ENA, 0);
@@ -2646,10 +2647,12 @@ static int wm8996_probe(struct snd_soc_codec *codec)
if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
ret = request_threaded_irq(i2c->irq, NULL,
wm8996_edge_irq,
- irq_flags, "wm8996", codec);
+ irq_flags | IRQF_ONESHOT,
+ "wm8996", codec);
else
ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq,
- irq_flags, "wm8996", codec);
+ irq_flags | IRQF_ONESHOT,
+ "wm8996", codec);
if (ret == 0) {
/* Unmask the interrupt */
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index e7c81baefe66..4134dc7e1243 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -106,11 +106,13 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
regmap_write_async(regmap, patch[i].reg,
patch[i].def);
break;
- default:
+ case SND_SOC_DAPM_PRE_PMD:
break;
+ default:
+ return 0;
}
- return 0;
+ return arizona_dvfs_sysclk_ev(w, kcontrol, event);
}
static const char *wm8997_osr_text[] = {
@@ -409,7 +411,8 @@ static const struct snd_kcontrol_new wm8997_aec_loopback_mux =
static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
- 0, wm8997_sysclk_ev, SND_SOC_DAPM_POST_PMU),
+ 0, wm8997_sysclk_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
@@ -1055,13 +1058,14 @@ static struct snd_soc_dai_driver wm8997_dai[] = {
static int wm8997_codec_probe(struct snd_soc_codec *codec)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
arizona_init_spk(codec);
- snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
- priv->core.arizona->dapm = &codec->dapm;
+ priv->core.arizona->dapm = dapm;
return 0;
}
@@ -1126,6 +1130,8 @@ static int wm8997_probe(struct platform_device *pdev)
wm8997->core.arizona = arizona;
wm8997->core.num_inputs = 4;
+ arizona_init_dvfs(&wm8997->core);
+
for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++)
wm8997->fll[i].vco_mult = 1;
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 13a3f335ea5b..8a8b1c0f9142 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -838,7 +838,7 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
/* Initial cold start */
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
regcache_cache_only(wm9081->regmap, false);
regcache_sync(wm9081->regmap);
@@ -898,8 +898,6 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index 60d243c904f5..13d23fc797db 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -425,7 +425,7 @@ static const struct snd_soc_dapm_route audio_map_in2_diff[] = {
static int wm9090_add_controls(struct snd_soc_codec *codec)
{
struct wm9090_priv *wm9090 = 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 i;
snd_soc_dapm_new_controls(dapm, wm9090_dapm_widgets,
@@ -496,7 +496,7 @@ static int wm9090_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) {
/* Restore the register cache */
regcache_sync(wm9090->regmap);
}
@@ -515,8 +515,6 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
break;
}
- codec->dapm.bias_level = level;
-
return 0;
}
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 98c9525bd751..1fda104dfc45 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -610,7 +610,6 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,
ac97_write(codec, AC97_POWERDOWN, 0xffff);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
@@ -646,7 +645,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)
if (ret < 0)
return ret;
- wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
if (ret == 0) {
/* Sync reg_cache with the hardware after cold reset */
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 1b20b8d2b15d..89cd2d6f57c0 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1171,7 +1171,6 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec,
ac97_write(codec, AC97_POWERDOWN, 0xffff);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
@@ -1201,7 +1200,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
if (ret < 0)
return ret;
- wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* do we need to re-start the PLL ? */
if (wm9713->pll_in)
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index d01c2095452f..b62ffd0c133e 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -121,6 +121,11 @@
#define ADSP2_WDMA_CONFIG_2 0x31
#define ADSP2_RDMA_CONFIG_1 0x34
+#define ADSP2_SCRATCH0 0x40
+#define ADSP2_SCRATCH1 0x41
+#define ADSP2_SCRATCH2 0x42
+#define ADSP2_SCRATCH3 0x43
+
/*
* ADSP2 Control
*/
@@ -229,16 +234,18 @@ struct wm_coeff_ctl_ops {
struct wm_coeff_ctl {
const char *name;
- struct wm_adsp_alg_region region;
+ const char *fw_name;
+ struct wm_adsp_alg_region alg_region;
struct wm_coeff_ctl_ops ops;
- struct wm_adsp *adsp;
- void *private;
+ struct wm_adsp *dsp;
unsigned int enabled:1;
struct list_head list;
void *cache;
+ unsigned int offset;
size_t len;
unsigned int set:1;
struct snd_kcontrol *kcontrol;
+ unsigned int flags;
};
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
@@ -246,9 +253,9 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
+ struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
- ucontrol->value.integer.value[0] = adsp[e->shift_l].fw;
+ ucontrol->value.integer.value[0] = dsp[e->shift_l].fw;
return 0;
}
@@ -258,18 +265,18 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
+ struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
- if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw)
+ if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
return 0;
if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
return -EINVAL;
- if (adsp[e->shift_l].running)
+ if (dsp[e->shift_l].running)
return -EBUSY;
- adsp[e->shift_l].fw = ucontrol->value.integer.value[0];
+ dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
return 0;
}
@@ -340,28 +347,47 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
return NULL;
}
-static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
+static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
unsigned int offset)
{
- if (WARN_ON(!region))
+ if (WARN_ON(!mem))
return offset;
- switch (region->type) {
+ switch (mem->type) {
case WMFW_ADSP1_PM:
- return region->base + (offset * 3);
+ return mem->base + (offset * 3);
case WMFW_ADSP1_DM:
- return region->base + (offset * 2);
+ return mem->base + (offset * 2);
case WMFW_ADSP2_XM:
- return region->base + (offset * 2);
+ return mem->base + (offset * 2);
case WMFW_ADSP2_YM:
- return region->base + (offset * 2);
+ return mem->base + (offset * 2);
case WMFW_ADSP1_ZM:
- return region->base + (offset * 2);
+ return mem->base + (offset * 2);
default:
WARN(1, "Unknown memory region type");
return offset;
}
}
+static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
+{
+ u16 scratch[4];
+ int ret;
+
+ ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0,
+ scratch, sizeof(scratch));
+ if (ret) {
+ adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
+ return;
+ }
+
+ adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
+ be16_to_cpu(scratch[0]),
+ be16_to_cpu(scratch[1]),
+ be16_to_cpu(scratch[2]),
+ be16_to_cpu(scratch[3]));
+}
+
static int wm_coeff_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -372,40 +398,39 @@ static int wm_coeff_info(struct snd_kcontrol *kcontrol,
return 0;
}
-static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
+static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
const void *buf, size_t len)
{
- struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
- struct wm_adsp_alg_region *region = &ctl->region;
+ struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
const struct wm_adsp_region *mem;
- struct wm_adsp *adsp = ctl->adsp;
+ struct wm_adsp *dsp = ctl->dsp;
void *scratch;
int ret;
unsigned int reg;
- mem = wm_adsp_find_region(adsp, region->type);
+ mem = wm_adsp_find_region(dsp, alg_region->type);
if (!mem) {
- adsp_err(adsp, "No base for region %x\n",
- region->type);
+ adsp_err(dsp, "No base for region %x\n",
+ alg_region->type);
return -EINVAL;
}
- reg = ctl->region.base;
+ reg = ctl->alg_region.base + ctl->offset;
reg = wm_adsp_region_to_reg(mem, reg);
scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
if (!scratch)
return -ENOMEM;
- ret = regmap_raw_write(adsp->regmap, reg, scratch,
+ ret = regmap_raw_write(dsp->regmap, reg, scratch,
ctl->len);
if (ret) {
- adsp_err(adsp, "Failed to write %zu bytes to %x: %d\n",
+ adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
ctl->len, reg, ret);
kfree(scratch);
return ret;
}
- adsp_dbg(adsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
+ adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
kfree(scratch);
@@ -424,42 +449,41 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol,
if (!ctl->enabled)
return 0;
- return wm_coeff_write_control(kcontrol, p, ctl->len);
+ return wm_coeff_write_control(ctl, p, ctl->len);
}
-static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
+static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
void *buf, size_t len)
{
- struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
- struct wm_adsp_alg_region *region = &ctl->region;
+ struct wm_adsp_alg_region *alg_region = &ctl->alg_region;
const struct wm_adsp_region *mem;
- struct wm_adsp *adsp = ctl->adsp;
+ struct wm_adsp *dsp = ctl->dsp;
void *scratch;
int ret;
unsigned int reg;
- mem = wm_adsp_find_region(adsp, region->type);
+ mem = wm_adsp_find_region(dsp, alg_region->type);
if (!mem) {
- adsp_err(adsp, "No base for region %x\n",
- region->type);
+ adsp_err(dsp, "No base for region %x\n",
+ alg_region->type);
return -EINVAL;
}
- reg = ctl->region.base;
+ reg = ctl->alg_region.base + ctl->offset;
reg = wm_adsp_region_to_reg(mem, reg);
scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
if (!scratch)
return -ENOMEM;
- ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len);
+ ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len);
if (ret) {
- adsp_err(adsp, "Failed to read %zu bytes from %x: %d\n",
+ adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
ctl->len, reg, ret);
kfree(scratch);
return ret;
}
- adsp_dbg(adsp, "Read %zu bytes from %x\n", ctl->len, reg);
+ adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg);
memcpy(buf, scratch, ctl->len);
kfree(scratch);
@@ -473,17 +497,25 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol,
struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
char *p = ucontrol->value.bytes.data;
+ if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
+ if (ctl->enabled)
+ return wm_coeff_read_control(ctl, p, ctl->len);
+ else
+ return -EPERM;
+ }
+
memcpy(p, ctl->cache, ctl->len);
+
return 0;
}
struct wmfw_ctl_work {
- struct wm_adsp *adsp;
+ struct wm_adsp *dsp;
struct wm_coeff_ctl *ctl;
struct work_struct work;
};
-static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
+static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
{
struct snd_kcontrol_new *kcontrol;
int ret;
@@ -502,17 +534,25 @@ static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
kcontrol->put = wm_coeff_put;
kcontrol->private_value = (unsigned long)ctl;
- ret = snd_soc_add_card_controls(adsp->card,
+ if (ctl->flags) {
+ if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE)
+ kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+ if (ctl->flags & WMFW_CTL_FLAG_READABLE)
+ kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
+ if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+ kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+ }
+
+ ret = snd_soc_add_card_controls(dsp->card,
kcontrol, 1);
if (ret < 0)
goto err_kcontrol;
kfree(kcontrol);
- ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card,
+ ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card,
ctl->name);
- list_add(&ctl->list, &adsp->ctl_list);
return 0;
err_kcontrol:
@@ -520,6 +560,358 @@ err_kcontrol:
return ret;
}
+static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
+{
+ struct wm_coeff_ctl *ctl;
+ int ret;
+
+ list_for_each_entry(ctl, &dsp->ctl_list, list) {
+ if (!ctl->enabled || ctl->set)
+ continue;
+ if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+ continue;
+
+ ret = wm_coeff_read_control(ctl,
+ ctl->cache,
+ ctl->len);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int wm_coeff_sync_controls(struct wm_adsp *dsp)
+{
+ struct wm_coeff_ctl *ctl;
+ int ret;
+
+ list_for_each_entry(ctl, &dsp->ctl_list, list) {
+ if (!ctl->enabled)
+ continue;
+ if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
+ ret = wm_coeff_write_control(ctl,
+ ctl->cache,
+ ctl->len);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void wm_adsp_ctl_work(struct work_struct *work)
+{
+ struct wmfw_ctl_work *ctl_work = container_of(work,
+ struct wmfw_ctl_work,
+ work);
+
+ wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
+ kfree(ctl_work);
+}
+
+static int wm_adsp_create_control(struct wm_adsp *dsp,
+ const struct wm_adsp_alg_region *alg_region,
+ unsigned int offset, unsigned int len,
+ const char *subname, unsigned int subname_len,
+ unsigned int flags)
+{
+ struct wm_coeff_ctl *ctl;
+ struct wmfw_ctl_work *ctl_work;
+ char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ char *region_name;
+ int ret;
+
+ if (flags & WMFW_CTL_FLAG_SYS)
+ return 0;
+
+ switch (alg_region->type) {
+ case WMFW_ADSP1_PM:
+ region_name = "PM";
+ break;
+ case WMFW_ADSP1_DM:
+ region_name = "DM";
+ break;
+ case WMFW_ADSP2_XM:
+ region_name = "XM";
+ break;
+ case WMFW_ADSP2_YM:
+ region_name = "YM";
+ break;
+ case WMFW_ADSP1_ZM:
+ region_name = "ZM";
+ break;
+ default:
+ adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
+ return -EINVAL;
+ }
+
+ switch (dsp->fw_ver) {
+ case 0:
+ case 1:
+ snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
+ dsp->num, region_name, alg_region->alg);
+ break;
+ default:
+ ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "DSP%d%c %.12s %x", dsp->num, *region_name,
+ wm_adsp_fw_text[dsp->fw], alg_region->alg);
+
+ /* Truncate the subname from the start if it is too long */
+ if (subname) {
+ int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
+ int skip = 0;
+
+ if (subname_len > avail)
+ skip = subname_len - avail;
+
+ snprintf(name + ret,
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s",
+ subname_len - skip, subname + skip);
+ }
+ break;
+ }
+
+ list_for_each_entry(ctl, &dsp->ctl_list,
+ list) {
+ if (!strcmp(ctl->name, name)) {
+ if (!ctl->enabled)
+ ctl->enabled = 1;
+ return 0;
+ }
+ }
+
+ ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
+ if (!ctl)
+ return -ENOMEM;
+ ctl->fw_name = wm_adsp_fw_text[dsp->fw];
+ ctl->alg_region = *alg_region;
+ ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
+ if (!ctl->name) {
+ ret = -ENOMEM;
+ goto err_ctl;
+ }
+ ctl->enabled = 1;
+ ctl->set = 0;
+ ctl->ops.xget = wm_coeff_get;
+ ctl->ops.xput = wm_coeff_put;
+ ctl->dsp = dsp;
+
+ ctl->flags = flags;
+ ctl->offset = offset;
+ if (len > 512) {
+ adsp_warn(dsp, "Truncating control %s from %d\n",
+ ctl->name, len);
+ len = 512;
+ }
+ ctl->len = len;
+ ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
+ if (!ctl->cache) {
+ ret = -ENOMEM;
+ goto err_ctl_name;
+ }
+
+ list_add(&ctl->list, &dsp->ctl_list);
+
+ ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
+ if (!ctl_work) {
+ ret = -ENOMEM;
+ goto err_ctl_cache;
+ }
+
+ ctl_work->dsp = dsp;
+ ctl_work->ctl = ctl;
+ INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
+ schedule_work(&ctl_work->work);
+
+ return 0;
+
+err_ctl_cache:
+ kfree(ctl->cache);
+err_ctl_name:
+ kfree(ctl->name);
+err_ctl:
+ kfree(ctl);
+
+ return ret;
+}
+
+struct wm_coeff_parsed_alg {
+ int id;
+ const u8 *name;
+ int name_len;
+ int ncoeff;
+};
+
+struct wm_coeff_parsed_coeff {
+ int offset;
+ int mem_type;
+ const u8 *name;
+ int name_len;
+ int ctl_type;
+ int flags;
+ int len;
+};
+
+static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
+{
+ int length;
+
+ switch (bytes) {
+ case 1:
+ length = **pos;
+ break;
+ case 2:
+ length = le16_to_cpu(*((__le16 *)*pos));
+ break;
+ default:
+ return 0;
+ }
+
+ if (str)
+ *str = *pos + bytes;
+
+ *pos += ((length + bytes) + 3) & ~0x03;
+
+ return length;
+}
+
+static int wm_coeff_parse_int(int bytes, const u8 **pos)
+{
+ int val = 0;
+
+ switch (bytes) {
+ case 2:
+ val = le16_to_cpu(*((__le16 *)*pos));
+ break;
+ case 4:
+ val = le32_to_cpu(*((__le32 *)*pos));
+ break;
+ default:
+ break;
+ }
+
+ *pos += bytes;
+
+ return val;
+}
+
+static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
+ struct wm_coeff_parsed_alg *blk)
+{
+ const struct wmfw_adsp_alg_data *raw;
+
+ switch (dsp->fw_ver) {
+ case 0:
+ case 1:
+ raw = (const struct wmfw_adsp_alg_data *)*data;
+ *data = raw->data;
+
+ blk->id = le32_to_cpu(raw->id);
+ blk->name = raw->name;
+ blk->name_len = strlen(raw->name);
+ blk->ncoeff = le32_to_cpu(raw->ncoeff);
+ break;
+ default:
+ blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
+ blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
+ &blk->name);
+ wm_coeff_parse_string(sizeof(u16), data, NULL);
+ blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
+ break;
+ }
+
+ adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
+ adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
+ adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
+}
+
+static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
+ struct wm_coeff_parsed_coeff *blk)
+{
+ const struct wmfw_adsp_coeff_data *raw;
+ const u8 *tmp;
+ int length;
+
+ switch (dsp->fw_ver) {
+ case 0:
+ case 1:
+ raw = (const struct wmfw_adsp_coeff_data *)*data;
+ *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
+
+ blk->offset = le16_to_cpu(raw->hdr.offset);
+ blk->mem_type = le16_to_cpu(raw->hdr.type);
+ blk->name = raw->name;
+ blk->name_len = strlen(raw->name);
+ blk->ctl_type = le16_to_cpu(raw->ctl_type);
+ blk->flags = le16_to_cpu(raw->flags);
+ blk->len = le32_to_cpu(raw->len);
+ break;
+ default:
+ tmp = *data;
+ blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
+ blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
+ length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
+ blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
+ &blk->name);
+ wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
+ wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
+ blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
+ blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
+ blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
+
+ *data = *data + sizeof(raw->hdr) + length;
+ break;
+ }
+
+ adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
+ adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
+ adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
+ adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
+ adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
+ adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
+}
+
+static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
+ const struct wmfw_region *region)
+{
+ struct wm_adsp_alg_region alg_region = {};
+ struct wm_coeff_parsed_alg alg_blk;
+ struct wm_coeff_parsed_coeff coeff_blk;
+ const u8 *data = region->data;
+ int i, ret;
+
+ wm_coeff_parse_alg(dsp, &data, &alg_blk);
+ for (i = 0; i < alg_blk.ncoeff; i++) {
+ wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
+
+ switch (coeff_blk.ctl_type) {
+ case SNDRV_CTL_ELEM_TYPE_BYTES:
+ break;
+ default:
+ adsp_err(dsp, "Unknown control type: %d\n",
+ coeff_blk.ctl_type);
+ return -EINVAL;
+ }
+
+ alg_region.type = coeff_blk.mem_type;
+ alg_region.alg = alg_blk.id;
+
+ ret = wm_adsp_create_control(dsp, &alg_region,
+ coeff_blk.offset,
+ coeff_blk.len,
+ coeff_blk.name,
+ coeff_blk.name_len,
+ coeff_blk.flags);
+ if (ret < 0)
+ adsp_err(dsp, "Failed to create control: %.*s, %d\n",
+ coeff_blk.name_len, coeff_blk.name, ret);
+ }
+
+ return 0;
+}
+
static int wm_adsp_load(struct wm_adsp *dsp)
{
LIST_HEAD(buf_list);
@@ -568,12 +960,22 @@ static int wm_adsp_load(struct wm_adsp *dsp)
goto out_fw;
}
- if (header->ver != 0) {
+ switch (header->ver) {
+ case 0:
+ adsp_warn(dsp, "%s: Depreciated file format %d\n",
+ file, header->ver);
+ break;
+ case 1:
+ case 2:
+ break;
+ default:
adsp_err(dsp, "%s: unknown file format %d\n",
file, header->ver);
goto out_fw;
}
+
adsp_info(dsp, "Firmware version: %d\n", header->ver);
+ dsp->fw_ver = header->ver;
if (header->core != dsp->type) {
adsp_err(dsp, "%s: invalid core %d != %d\n",
@@ -638,6 +1040,12 @@ static int wm_adsp_load(struct wm_adsp *dsp)
text = kzalloc(le32_to_cpu(region->len) + 1,
GFP_KERNEL);
break;
+ case WMFW_ALGORITHM_DATA:
+ region_name = "Algorithm";
+ ret = wm_adsp_parse_coeff(dsp, region);
+ if (ret != 0)
+ goto out_fw;
+ break;
case WMFW_INFO_TEXT:
region_name = "Information";
text = kzalloc(le32_to_cpu(region->len) + 1,
@@ -730,444 +1138,316 @@ out:
return ret;
}
-static int wm_coeff_init_control_caches(struct wm_adsp *adsp)
+static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
+ const struct wm_adsp_alg_region *alg_region)
{
struct wm_coeff_ctl *ctl;
- int ret;
- list_for_each_entry(ctl, &adsp->ctl_list, list) {
- if (!ctl->enabled || ctl->set)
- continue;
- ret = wm_coeff_read_control(ctl->kcontrol,
- ctl->cache,
- ctl->len);
- if (ret < 0)
- return ret;
+ list_for_each_entry(ctl, &dsp->ctl_list, list) {
+ if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
+ alg_region->alg == ctl->alg_region.alg &&
+ alg_region->type == ctl->alg_region.type) {
+ ctl->alg_region.base = alg_region->base;
+ }
}
-
- return 0;
}
-static int wm_coeff_sync_controls(struct wm_adsp *adsp)
+static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
+ unsigned int pos, unsigned int len)
{
- struct wm_coeff_ctl *ctl;
+ void *alg;
int ret;
+ __be32 val;
- list_for_each_entry(ctl, &adsp->ctl_list, list) {
- if (!ctl->enabled)
- continue;
- if (ctl->set) {
- ret = wm_coeff_write_control(ctl->kcontrol,
- ctl->cache,
- ctl->len);
- if (ret < 0)
- return ret;
- }
+ if (n_algs == 0) {
+ adsp_err(dsp, "No algorithms\n");
+ return ERR_PTR(-EINVAL);
}
- return 0;
-}
-
-static void wm_adsp_ctl_work(struct work_struct *work)
-{
- struct wmfw_ctl_work *ctl_work = container_of(work,
- struct wmfw_ctl_work,
- work);
-
- wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl);
- kfree(ctl_work);
-}
-
-static int wm_adsp_create_control(struct wm_adsp *dsp,
- const struct wm_adsp_alg_region *region)
-
-{
- struct wm_coeff_ctl *ctl;
- struct wmfw_ctl_work *ctl_work;
- char *name;
- char *region_name;
- int ret;
-
- name = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!name)
- return -ENOMEM;
+ if (n_algs > 1024) {
+ adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs);
+ return ERR_PTR(-EINVAL);
+ }
- switch (region->type) {
- case WMFW_ADSP1_PM:
- region_name = "PM";
- break;
- case WMFW_ADSP1_DM:
- region_name = "DM";
- break;
- case WMFW_ADSP2_XM:
- region_name = "XM";
- break;
- case WMFW_ADSP2_YM:
- region_name = "YM";
- break;
- case WMFW_ADSP1_ZM:
- region_name = "ZM";
- break;
- default:
- ret = -EINVAL;
- goto err_name;
+ /* Read the terminator first to validate the length */
+ ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to read algorithm list end: %d\n",
+ ret);
+ return ERR_PTR(ret);
}
- snprintf(name, PAGE_SIZE, "DSP%d %s %x",
- dsp->num, region_name, region->alg);
+ if (be32_to_cpu(val) != 0xbedead)
+ adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
+ pos + len, be32_to_cpu(val));
- list_for_each_entry(ctl, &dsp->ctl_list,
- list) {
- if (!strcmp(ctl->name, name)) {
- if (!ctl->enabled)
- ctl->enabled = 1;
- goto found;
- }
- }
+ alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
+ if (!alg)
+ return ERR_PTR(-ENOMEM);
- ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
- if (!ctl) {
- ret = -ENOMEM;
- goto err_name;
- }
- ctl->region = *region;
- ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
- if (!ctl->name) {
- ret = -ENOMEM;
- goto err_ctl;
+ ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to read algorithm list: %d\n",
+ ret);
+ kfree(alg);
+ return ERR_PTR(ret);
}
- ctl->enabled = 1;
- ctl->set = 0;
- ctl->ops.xget = wm_coeff_get;
- ctl->ops.xput = wm_coeff_put;
- ctl->adsp = dsp;
- ctl->len = region->len;
- ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
- if (!ctl->cache) {
- ret = -ENOMEM;
- goto err_ctl_name;
- }
+ return alg;
+}
- ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
- if (!ctl_work) {
- ret = -ENOMEM;
- goto err_ctl_cache;
- }
+static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
+ int type, __be32 id,
+ __be32 base)
+{
+ struct wm_adsp_alg_region *alg_region;
- ctl_work->adsp = dsp;
- ctl_work->ctl = ctl;
- INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
- schedule_work(&ctl_work->work);
+ alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL);
+ if (!alg_region)
+ return ERR_PTR(-ENOMEM);
-found:
- kfree(name);
+ alg_region->type = type;
+ alg_region->alg = be32_to_cpu(id);
+ alg_region->base = be32_to_cpu(base);
- return 0;
+ list_add_tail(&alg_region->list, &dsp->alg_regions);
-err_ctl_cache:
- kfree(ctl->cache);
-err_ctl_name:
- kfree(ctl->name);
-err_ctl:
- kfree(ctl);
-err_name:
- kfree(name);
- return ret;
+ if (dsp->fw_ver > 0)
+ wm_adsp_ctl_fixup_base(dsp, alg_region);
+
+ return alg_region;
}
-static int wm_adsp_setup_algs(struct wm_adsp *dsp)
+static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
{
- struct regmap *regmap = dsp->regmap;
struct wmfw_adsp1_id_hdr adsp1_id;
- struct wmfw_adsp2_id_hdr adsp2_id;
struct wmfw_adsp1_alg_hdr *adsp1_alg;
- struct wmfw_adsp2_alg_hdr *adsp2_alg;
- void *alg, *buf;
- struct wm_adsp_alg_region *region;
+ struct wm_adsp_alg_region *alg_region;
const struct wm_adsp_region *mem;
- unsigned int pos, term;
- size_t algs, buf_size;
- __be32 val;
+ unsigned int pos, len;
+ size_t n_algs;
int i, ret;
- switch (dsp->type) {
- case WMFW_ADSP1:
- mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
- break;
- case WMFW_ADSP2:
- mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
- break;
- default:
- mem = NULL;
- break;
- }
-
+ mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
if (WARN_ON(!mem))
return -EINVAL;
- switch (dsp->type) {
- case WMFW_ADSP1:
- ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
- sizeof(adsp1_id));
- if (ret != 0) {
- adsp_err(dsp, "Failed to read algorithm info: %d\n",
- ret);
- return ret;
- }
-
- buf = &adsp1_id;
- buf_size = sizeof(adsp1_id);
-
- algs = be32_to_cpu(adsp1_id.algs);
- dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
- adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
- dsp->fw_id,
- (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
- (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
- be32_to_cpu(adsp1_id.fw.ver) & 0xff,
- algs);
-
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
- region->type = WMFW_ADSP1_ZM;
- region->alg = be32_to_cpu(adsp1_id.fw.id);
- region->base = be32_to_cpu(adsp1_id.zm);
- list_add_tail(&region->list, &dsp->alg_regions);
-
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
- region->type = WMFW_ADSP1_DM;
- region->alg = be32_to_cpu(adsp1_id.fw.id);
- region->base = be32_to_cpu(adsp1_id.dm);
- list_add_tail(&region->list, &dsp->alg_regions);
-
- pos = sizeof(adsp1_id) / 2;
- term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
- break;
-
- case WMFW_ADSP2:
- ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
- sizeof(adsp2_id));
- if (ret != 0) {
- adsp_err(dsp, "Failed to read algorithm info: %d\n",
- ret);
- return ret;
- }
-
- buf = &adsp2_id;
- buf_size = sizeof(adsp2_id);
-
- algs = be32_to_cpu(adsp2_id.algs);
- dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
- adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
- dsp->fw_id,
- (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
- (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
- be32_to_cpu(adsp2_id.fw.ver) & 0xff,
- algs);
-
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
- region->type = WMFW_ADSP2_XM;
- region->alg = be32_to_cpu(adsp2_id.fw.id);
- region->base = be32_to_cpu(adsp2_id.xm);
- list_add_tail(&region->list, &dsp->alg_regions);
-
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
- region->type = WMFW_ADSP2_YM;
- region->alg = be32_to_cpu(adsp2_id.fw.id);
- region->base = be32_to_cpu(adsp2_id.ym);
- list_add_tail(&region->list, &dsp->alg_regions);
-
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
- region->type = WMFW_ADSP2_ZM;
- region->alg = be32_to_cpu(adsp2_id.fw.id);
- region->base = be32_to_cpu(adsp2_id.zm);
- list_add_tail(&region->list, &dsp->alg_regions);
-
- pos = sizeof(adsp2_id) / 2;
- term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
- break;
-
- default:
- WARN(1, "Unknown DSP type");
- return -EINVAL;
- }
-
- if (algs == 0) {
- adsp_err(dsp, "No algorithms\n");
- return -EINVAL;
- }
-
- if (algs > 1024) {
- adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
- print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
- buf, buf_size);
- return -EINVAL;
- }
-
- /* Read the terminator first to validate the length */
- ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
+ ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
+ sizeof(adsp1_id));
if (ret != 0) {
- adsp_err(dsp, "Failed to read algorithm list end: %d\n",
- ret);
+ adsp_err(dsp, "Failed to read algorithm info: %d\n",
+ ret);
return ret;
}
- if (be32_to_cpu(val) != 0xbedead)
- adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
- term, be32_to_cpu(val));
-
- alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA);
- if (!alg)
- return -ENOMEM;
-
- ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
- if (ret != 0) {
- adsp_err(dsp, "Failed to read algorithm list: %d\n",
- ret);
- goto out;
- }
-
- adsp1_alg = alg;
- adsp2_alg = alg;
-
- for (i = 0; i < algs; i++) {
- switch (dsp->type) {
- case WMFW_ADSP1:
- adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
- i, be32_to_cpu(adsp1_alg[i].alg.id),
- (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
- (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
- be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
- be32_to_cpu(adsp1_alg[i].dm),
- be32_to_cpu(adsp1_alg[i].zm));
-
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region) {
- ret = -ENOMEM;
- goto out;
- }
- region->type = WMFW_ADSP1_DM;
- region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
- region->base = be32_to_cpu(adsp1_alg[i].dm);
- region->len = 0;
- list_add_tail(&region->list, &dsp->alg_regions);
- if (i + 1 < algs) {
- region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
- region->len -= be32_to_cpu(adsp1_alg[i].dm);
- region->len *= 4;
- wm_adsp_create_control(dsp, region);
+ n_algs = be32_to_cpu(adsp1_id.n_algs);
+ dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
+ adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
+ dsp->fw_id,
+ (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
+ (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
+ be32_to_cpu(adsp1_id.fw.ver) & 0xff,
+ n_algs);
+
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
+ adsp1_id.fw.id, adsp1_id.zm);
+ if (IS_ERR(alg_region))
+ return PTR_ERR(alg_region);
+
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
+ adsp1_id.fw.id, adsp1_id.dm);
+ if (IS_ERR(alg_region))
+ return PTR_ERR(alg_region);
+
+ pos = sizeof(adsp1_id) / 2;
+ len = (sizeof(*adsp1_alg) * n_algs) / 2;
+
+ adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+ if (IS_ERR(adsp1_alg))
+ return PTR_ERR(adsp1_alg);
+
+ for (i = 0; i < n_algs; i++) {
+ adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
+ i, be32_to_cpu(adsp1_alg[i].alg.id),
+ (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
+ (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
+ be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
+ be32_to_cpu(adsp1_alg[i].dm),
+ be32_to_cpu(adsp1_alg[i].zm));
+
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM,
+ adsp1_alg[i].alg.id,
+ adsp1_alg[i].dm);
+ if (IS_ERR(alg_region)) {
+ ret = PTR_ERR(alg_region);
+ goto out;
+ }
+ if (dsp->fw_ver == 0) {
+ if (i + 1 < n_algs) {
+ len = be32_to_cpu(adsp1_alg[i + 1].dm);
+ len -= be32_to_cpu(adsp1_alg[i].dm);
+ len *= 4;
+ wm_adsp_create_control(dsp, alg_region, 0,
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
be32_to_cpu(adsp1_alg[i].alg.id));
}
+ }
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region) {
- ret = -ENOMEM;
- goto out;
- }
- region->type = WMFW_ADSP1_ZM;
- region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
- region->base = be32_to_cpu(adsp1_alg[i].zm);
- region->len = 0;
- list_add_tail(&region->list, &dsp->alg_regions);
- if (i + 1 < algs) {
- region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
- region->len -= be32_to_cpu(adsp1_alg[i].zm);
- region->len *= 4;
- wm_adsp_create_control(dsp, region);
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
+ adsp1_alg[i].alg.id,
+ adsp1_alg[i].zm);
+ if (IS_ERR(alg_region)) {
+ ret = PTR_ERR(alg_region);
+ goto out;
+ }
+ if (dsp->fw_ver == 0) {
+ if (i + 1 < n_algs) {
+ len = be32_to_cpu(adsp1_alg[i + 1].zm);
+ len -= be32_to_cpu(adsp1_alg[i].zm);
+ len *= 4;
+ wm_adsp_create_control(dsp, alg_region, 0,
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
be32_to_cpu(adsp1_alg[i].alg.id));
}
- break;
+ }
+ }
- case WMFW_ADSP2:
- adsp_info(dsp,
- "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
- i, be32_to_cpu(adsp2_alg[i].alg.id),
- (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
- (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
- be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
- be32_to_cpu(adsp2_alg[i].xm),
- be32_to_cpu(adsp2_alg[i].ym),
- be32_to_cpu(adsp2_alg[i].zm));
-
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region) {
- ret = -ENOMEM;
- goto out;
- }
- region->type = WMFW_ADSP2_XM;
- region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
- region->base = be32_to_cpu(adsp2_alg[i].xm);
- region->len = 0;
- list_add_tail(&region->list, &dsp->alg_regions);
- if (i + 1 < algs) {
- region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
- region->len -= be32_to_cpu(adsp2_alg[i].xm);
- region->len *= 4;
- wm_adsp_create_control(dsp, region);
+out:
+ kfree(adsp1_alg);
+ return ret;
+}
+
+static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
+{
+ struct wmfw_adsp2_id_hdr adsp2_id;
+ struct wmfw_adsp2_alg_hdr *adsp2_alg;
+ struct wm_adsp_alg_region *alg_region;
+ const struct wm_adsp_region *mem;
+ unsigned int pos, len;
+ size_t n_algs;
+ int i, ret;
+
+ mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
+ if (WARN_ON(!mem))
+ return -EINVAL;
+
+ ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
+ sizeof(adsp2_id));
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to read algorithm info: %d\n",
+ ret);
+ return ret;
+ }
+
+ n_algs = be32_to_cpu(adsp2_id.n_algs);
+ dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
+ adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
+ dsp->fw_id,
+ (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
+ (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
+ be32_to_cpu(adsp2_id.fw.ver) & 0xff,
+ n_algs);
+
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
+ adsp2_id.fw.id, adsp2_id.xm);
+ if (IS_ERR(alg_region))
+ return PTR_ERR(alg_region);
+
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
+ adsp2_id.fw.id, adsp2_id.ym);
+ if (IS_ERR(alg_region))
+ return PTR_ERR(alg_region);
+
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
+ adsp2_id.fw.id, adsp2_id.zm);
+ if (IS_ERR(alg_region))
+ return PTR_ERR(alg_region);
+
+ pos = sizeof(adsp2_id) / 2;
+ len = (sizeof(*adsp2_alg) * n_algs) / 2;
+
+ adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+ if (IS_ERR(adsp2_alg))
+ return PTR_ERR(adsp2_alg);
+
+ for (i = 0; i < n_algs; i++) {
+ adsp_info(dsp,
+ "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
+ i, be32_to_cpu(adsp2_alg[i].alg.id),
+ (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
+ (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
+ be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
+ be32_to_cpu(adsp2_alg[i].xm),
+ be32_to_cpu(adsp2_alg[i].ym),
+ be32_to_cpu(adsp2_alg[i].zm));
+
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
+ adsp2_alg[i].alg.id,
+ adsp2_alg[i].xm);
+ if (IS_ERR(alg_region)) {
+ ret = PTR_ERR(alg_region);
+ goto out;
+ }
+ if (dsp->fw_ver == 0) {
+ if (i + 1 < n_algs) {
+ len = be32_to_cpu(adsp2_alg[i + 1].xm);
+ len -= be32_to_cpu(adsp2_alg[i].xm);
+ len *= 4;
+ wm_adsp_create_control(dsp, alg_region, 0,
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id));
}
+ }
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region) {
- ret = -ENOMEM;
- goto out;
- }
- region->type = WMFW_ADSP2_YM;
- region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
- region->base = be32_to_cpu(adsp2_alg[i].ym);
- region->len = 0;
- list_add_tail(&region->list, &dsp->alg_regions);
- if (i + 1 < algs) {
- region->len = be32_to_cpu(adsp2_alg[i + 1].ym);
- region->len -= be32_to_cpu(adsp2_alg[i].ym);
- region->len *= 4;
- wm_adsp_create_control(dsp, region);
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
+ adsp2_alg[i].alg.id,
+ adsp2_alg[i].ym);
+ if (IS_ERR(alg_region)) {
+ ret = PTR_ERR(alg_region);
+ goto out;
+ }
+ if (dsp->fw_ver == 0) {
+ if (i + 1 < n_algs) {
+ len = be32_to_cpu(adsp2_alg[i + 1].ym);
+ len -= be32_to_cpu(adsp2_alg[i].ym);
+ len *= 4;
+ wm_adsp_create_control(dsp, alg_region, 0,
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id));
}
+ }
- region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region) {
- ret = -ENOMEM;
- goto out;
- }
- region->type = WMFW_ADSP2_ZM;
- region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
- region->base = be32_to_cpu(adsp2_alg[i].zm);
- region->len = 0;
- list_add_tail(&region->list, &dsp->alg_regions);
- if (i + 1 < algs) {
- region->len = be32_to_cpu(adsp2_alg[i + 1].zm);
- region->len -= be32_to_cpu(adsp2_alg[i].zm);
- region->len *= 4;
- wm_adsp_create_control(dsp, region);
+ alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
+ adsp2_alg[i].alg.id,
+ adsp2_alg[i].zm);
+ if (IS_ERR(alg_region)) {
+ ret = PTR_ERR(alg_region);
+ goto out;
+ }
+ if (dsp->fw_ver == 0) {
+ if (i + 1 < n_algs) {
+ len = be32_to_cpu(adsp2_alg[i + 1].zm);
+ len -= be32_to_cpu(adsp2_alg[i].zm);
+ len *= 4;
+ wm_adsp_create_control(dsp, alg_region, 0,
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id));
}
- break;
}
}
out:
- kfree(alg);
+ kfree(adsp2_alg);
return ret;
}
@@ -1354,9 +1634,9 @@ out:
return ret;
}
-int wm_adsp1_init(struct wm_adsp *adsp)
+int wm_adsp1_init(struct wm_adsp *dsp)
{
- INIT_LIST_HEAD(&adsp->alg_regions);
+ INIT_LIST_HEAD(&dsp->alg_regions);
return 0;
}
@@ -1410,7 +1690,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
if (ret != 0)
goto err;
- ret = wm_adsp_setup_algs(dsp);
+ ret = wm_adsp1_setup_algs(dsp);
if (ret != 0)
goto err;
@@ -1531,35 +1811,6 @@ static void wm_adsp2_boot_work(struct work_struct *work)
return;
}
- if (dsp->dvfs) {
- ret = regmap_read(dsp->regmap,
- dsp->base + ADSP2_CLOCKING, &val);
- if (ret != 0) {
- adsp_err(dsp, "Failed to read clocking: %d\n", ret);
- return;
- }
-
- if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
- ret = regulator_enable(dsp->dvfs);
- if (ret != 0) {
- adsp_err(dsp,
- "Failed to enable supply: %d\n",
- ret);
- return;
- }
-
- ret = regulator_set_voltage(dsp->dvfs,
- 1800000,
- 1800000);
- if (ret != 0) {
- adsp_err(dsp,
- "Failed to raise supply: %d\n",
- ret);
- return;
- }
- }
- }
-
ret = wm_adsp2_ena(dsp);
if (ret != 0)
return;
@@ -1568,7 +1819,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
if (ret != 0)
goto err;
- ret = wm_adsp_setup_algs(dsp);
+ ret = wm_adsp2_setup_algs(dsp);
if (ret != 0)
goto err;
@@ -1642,6 +1893,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_PRE_PMD:
+ /* Log firmware state, it can be useful for analysis */
+ wm_adsp2_show_fw_status(dsp);
+
dsp->running = false;
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
@@ -1653,21 +1907,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
- if (dsp->dvfs) {
- ret = regulator_set_voltage(dsp->dvfs, 1200000,
- 1800000);
- if (ret != 0)
- adsp_warn(dsp,
- "Failed to lower supply: %d\n",
- ret);
-
- ret = regulator_disable(dsp->dvfs);
- if (ret != 0)
- adsp_err(dsp,
- "Failed to enable supply: %d\n",
- ret);
- }
-
list_for_each_entry(ctl, &dsp->ctl_list, list)
ctl->enabled = 0;
@@ -1694,7 +1933,7 @@ err:
}
EXPORT_SYMBOL_GPL(wm_adsp2_event);
-int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
+int wm_adsp2_init(struct wm_adsp *dsp)
{
int ret;
@@ -1702,43 +1941,16 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
* Disable the DSP memory by default when in reset for a small
* power saving.
*/
- ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL,
+ ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
ADSP2_MEM_ENA, 0);
if (ret != 0) {
- adsp_err(adsp, "Failed to clear memory retention: %d\n", ret);
+ adsp_err(dsp, "Failed to clear memory retention: %d\n", ret);
return ret;
}
- INIT_LIST_HEAD(&adsp->alg_regions);
- INIT_LIST_HEAD(&adsp->ctl_list);
- INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work);
-
- if (dvfs) {
- adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
- if (IS_ERR(adsp->dvfs)) {
- ret = PTR_ERR(adsp->dvfs);
- adsp_err(adsp, "Failed to get DCVDD: %d\n", ret);
- return ret;
- }
-
- ret = regulator_enable(adsp->dvfs);
- if (ret != 0) {
- adsp_err(adsp, "Failed to enable DCVDD: %d\n", ret);
- return ret;
- }
-
- ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
- if (ret != 0) {
- adsp_err(adsp, "Failed to initialise DVFS: %d\n", ret);
- return ret;
- }
-
- ret = regulator_disable(adsp->dvfs);
- if (ret != 0) {
- adsp_err(adsp, "Failed to disable DCVDD: %d\n", ret);
- return ret;
- }
- }
+ INIT_LIST_HEAD(&dsp->alg_regions);
+ INIT_LIST_HEAD(&dsp->ctl_list);
+ INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
return 0;
}
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index a4f6b64deb61..0e5f07c35d50 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -18,8 +18,6 @@
#include "wmfw.h"
-struct regulator;
-
struct wm_adsp_region {
int type;
unsigned int base;
@@ -30,7 +28,6 @@ struct wm_adsp_alg_region {
unsigned int alg;
int type;
unsigned int base;
- size_t len;
};
struct wm_adsp {
@@ -54,10 +51,9 @@ struct wm_adsp {
int num_mems;
int fw;
+ int fw_ver;
bool running;
- struct regulator *dvfs;
-
struct list_head ctl_list;
struct work_struct boot_work;
@@ -67,19 +63,22 @@ struct wm_adsp {
SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
-#define WM_ADSP2(wname, num) \
+#define WM_ADSP2_E(wname, num, event_fn) \
{ .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \
- .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_early_event, \
- .event_flags = SND_SOC_DAPM_PRE_PMU }, \
+ .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
+ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \
{ .id = snd_soc_dapm_out_drv, .name = wname, \
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+#define WM_ADSP2(wname, num) \
+ WM_ADSP2_E(wname, num, wm_adsp2_early_event)
+
extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
-int wm_adsp1_init(struct wm_adsp *adsp);
-int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
+int wm_adsp1_init(struct wm_adsp *dsp);
+int wm_adsp2_init(struct wm_adsp *dsp);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 8366e19657a7..fd86bd105460 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -1116,7 +1116,7 @@ static const struct snd_soc_dapm_route lineout2_se_routes[] = {
int wm_hubs_add_analogue_controls(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);
/* Latch volume update bits & default ZC on */
snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
@@ -1160,7 +1160,7 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
int lineout1_diff, int lineout2_diff)
{
struct wm_hubs_data *hubs = 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);
hubs->codec = codec;
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
index ef163360a745..7613d60d62ea 100644
--- a/sound/soc/codecs/wmfw.h
+++ b/sound/soc/codecs/wmfw.h
@@ -15,6 +15,17 @@
#include <linux/types.h>
+#define WMFW_MAX_ALG_NAME 256
+#define WMFW_MAX_ALG_DESCR_NAME 256
+
+#define WMFW_MAX_COEFF_NAME 256
+#define WMFW_MAX_COEFF_DESCR_NAME 256
+
+#define WMFW_CTL_FLAG_SYS 0x8000
+#define WMFW_CTL_FLAG_VOLATILE 0x0004
+#define WMFW_CTL_FLAG_WRITEABLE 0x0002
+#define WMFW_CTL_FLAG_READABLE 0x0001
+
struct wmfw_header {
char magic[4];
__le32 len;
@@ -61,7 +72,7 @@ struct wmfw_adsp1_id_hdr {
struct wmfw_id_hdr fw;
__be32 zm;
__be32 dm;
- __be32 algs;
+ __be32 n_algs;
} __packed;
struct wmfw_adsp2_id_hdr {
@@ -69,7 +80,7 @@ struct wmfw_adsp2_id_hdr {
__be32 zm;
__be32 xm;
__be32 ym;
- __be32 algs;
+ __be32 n_algs;
} __packed;
struct wmfw_alg_hdr {
@@ -90,6 +101,28 @@ struct wmfw_adsp2_alg_hdr {
__be32 ym;
} __packed;
+struct wmfw_adsp_alg_data {
+ __le32 id;
+ u8 name[WMFW_MAX_ALG_NAME];
+ u8 descr[WMFW_MAX_ALG_DESCR_NAME];
+ __le32 ncoeff;
+ u8 data[];
+} __packed;
+
+struct wmfw_adsp_coeff_data {
+ struct {
+ __le16 offset;
+ __le16 type;
+ __le32 size;
+ } hdr;
+ u8 name[WMFW_MAX_COEFF_NAME];
+ u8 descr[WMFW_MAX_COEFF_DESCR_NAME];
+ __le16 ctl_type;
+ __le16 flags;
+ __le32 len;
+ u8 data[];
+} __packed;
+
struct wmfw_coeff_hdr {
u8 magic[4];
__le32 len;
@@ -117,9 +150,10 @@ struct wmfw_coeff_item {
#define WMFW_ADSP1 1
#define WMFW_ADSP2 2
-#define WMFW_ABSOLUTE 0xf0
-#define WMFW_NAME_TEXT 0xfe
-#define WMFW_INFO_TEXT 0xff
+#define WMFW_ABSOLUTE 0xf0
+#define WMFW_ALGORITHM_DATA 0xf2
+#define WMFW_NAME_TEXT 0xfe
+#define WMFW_INFO_TEXT 0xff
#define WMFW_ADSP1_PM 2
#define WMFW_ADSP1_DM 3