summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/arizona.c29
-rw-r--r--sound/soc/codecs/arizona.h18
-rw-r--r--sound/soc/codecs/cs4271.c6
-rw-r--r--sound/soc/codecs/cs42l52.c4
-rw-r--r--sound/soc/codecs/lm49453.c106
-rw-r--r--sound/soc/codecs/sgtl5000.c4
-rw-r--r--sound/soc/codecs/sta529.c9
-rw-r--r--sound/soc/codecs/tlv320aic3x.c4
-rw-r--r--sound/soc/codecs/wm2000.c35
-rw-r--r--sound/soc/codecs/wm2200.c15
-rw-r--r--sound/soc/codecs/wm5100.c6
-rw-r--r--sound/soc/codecs/wm5102.c51
-rw-r--r--sound/soc/codecs/wm5110.c3
-rw-r--r--sound/soc/codecs/wm_adsp.c526
-rw-r--r--sound/soc/codecs/wm_adsp.h18
-rw-r--r--sound/soc/codecs/wmfw.h15
-rw-r--r--sound/soc/davinci/davinci-mcasp.c2
-rw-r--r--sound/soc/dwc/designware_i2s.c4
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c21
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c22
-rw-r--r--sound/soc/fsl/imx-pcm.c32
-rw-r--r--sound/soc/fsl/imx-pcm.h18
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c2
-rw-r--r--sound/soc/soc-core.c35
-rw-r--r--sound/soc/soc-dapm.c12
-rw-r--r--sound/soc/soc-pcm.c1
-rw-r--r--sound/soc/ux500/mop500.c2
27 files changed, 794 insertions, 206 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index adf397b9d0e..3b8e8c70b79 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -56,14 +56,14 @@
#define arizona_fll_warn(_fll, fmt, ...) \
dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_fll_dbg(_fll, fmt, ...) \
- dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
+ dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_aif_err(_dai, fmt, ...) \
dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_warn(_dai, fmt, ...) \
dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
#define arizona_aif_dbg(_dai, fmt, ...) \
- dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
+ dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"None",
@@ -446,15 +446,9 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
case SND_SOC_DAIFMT_DSP_A:
mode = 0;
break;
- case SND_SOC_DAIFMT_DSP_B:
- mode = 1;
- break;
case SND_SOC_DAIFMT_I2S:
mode = 2;
break;
- case SND_SOC_DAIFMT_LEFT_J:
- mode = 3;
- break;
default:
arizona_aif_err(dai, "Unsupported DAI format %d\n",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
@@ -691,7 +685,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
}
sr_val = i;
- lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
+ lrclk = rates[bclk] / params_rate(params);
arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
rates[bclk], rates[bclk] / lrclk);
@@ -714,7 +708,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
- ARIZONA_AIF1_RATE_MASK, 8);
+ ARIZONA_AIF1_RATE_MASK,
+ 8 << ARIZONA_AIF1_RATE_SHIFT);
break;
default:
arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
@@ -915,7 +910,7 @@ static int arizona_calc_fll(struct arizona_fll *fll,
cfg->n = target / (ratio * Fref);
- if (target % Fref) {
+ if (target % (ratio * Fref)) {
gcd_fll = gcd(target, ratio * Fref);
arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
@@ -927,6 +922,15 @@ static int arizona_calc_fll(struct arizona_fll *fll,
cfg->lambda = 0;
}
+ /* Round down to 16bit range with cost of accuracy lost.
+ * Denominator must be bigger than numerator so we only
+ * take care of it.
+ */
+ while (cfg->lambda >= (1 << 16)) {
+ cfg->theta >>= 1;
+ cfg->lambda >>= 1;
+ }
+
arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
cfg->n, cfg->theta, cfg->lambda);
arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
@@ -1087,6 +1091,9 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
id, ret);
}
+ regmap_update_bits(arizona->regmap, fll->base + 1,
+ ARIZONA_FLL1_FREERUN, 0);
+
return 0;
}
EXPORT_SYMBOL_GPL(arizona_init_fll);
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 41dae1ed3b7..4deebeb0717 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -34,15 +34,15 @@
#define ARIZONA_FLL_SRC_MCLK1 0
#define ARIZONA_FLL_SRC_MCLK2 1
-#define ARIZONA_FLL_SRC_SLIMCLK 2
-#define ARIZONA_FLL_SRC_FLL1 3
-#define ARIZONA_FLL_SRC_FLL2 4
-#define ARIZONA_FLL_SRC_AIF1BCLK 5
-#define ARIZONA_FLL_SRC_AIF2BCLK 6
-#define ARIZONA_FLL_SRC_AIF3BCLK 7
-#define ARIZONA_FLL_SRC_AIF1LRCLK 8
-#define ARIZONA_FLL_SRC_AIF2LRCLK 9
-#define ARIZONA_FLL_SRC_AIF3LRCLK 10
+#define ARIZONA_FLL_SRC_SLIMCLK 3
+#define ARIZONA_FLL_SRC_FLL1 4
+#define ARIZONA_FLL_SRC_FLL2 5
+#define ARIZONA_FLL_SRC_AIF1BCLK 8
+#define ARIZONA_FLL_SRC_AIF2BCLK 9
+#define ARIZONA_FLL_SRC_AIF3BCLK 10
+#define ARIZONA_FLL_SRC_AIF1LRCLK 12
+#define ARIZONA_FLL_SRC_AIF2LRCLK 13
+#define ARIZONA_FLL_SRC_AIF3LRCLK 14
#define ARIZONA_MIXER_VOL_MASK 0x00FE
#define ARIZONA_MIXER_VOL_SHIFT 1
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 4f1127935fd..ac8742a1f25 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -474,16 +474,16 @@ static int cs4271_probe(struct snd_soc_codec *codec)
struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
int ret;
int gpio_nreset = -EINVAL;
- int amutec_eq_bmutec = 0;
+ bool amutec_eq_bmutec = false;
#ifdef CONFIG_OF
if (of_match_device(cs4271_dt_ids, codec->dev)) {
gpio_nreset = of_get_named_gpio(codec->dev->of_node,
"reset-gpio", 0);
- if (!of_get_property(codec->dev->of_node,
+ if (of_get_property(codec->dev->of_node,
"cirrus,amutec-eq-bmutec", NULL))
- amutec_eq_bmutec = 1;
+ amutec_eq_bmutec = true;
}
#endif
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 99bb1c69499..9811a5478c8 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -737,7 +737,7 @@ static const struct cs42l52_clk_para clk_map_table[] = {
static int cs42l52_get_clk(int mclk, int rate)
{
- int i, ret = 0;
+ int i, ret = -EINVAL;
u_int mclk1, mclk2 = 0;
for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
@@ -749,8 +749,6 @@ static int cs42l52_get_clk(int mclk, int rate)
}
}
}
- if (ret > ARRAY_SIZE(clk_map_table))
- return -EINVAL;
return ret;
}
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index d75257d40a4..e19490cfb3a 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -111,9 +111,9 @@ static struct reg_default lm49453_reg_defs[] = {
{ 101, 0x00 },
{ 102, 0x00 },
{ 103, 0x01 },
- { 105, 0x01 },
- { 106, 0x00 },
- { 107, 0x01 },
+ { 104, 0x01 },
+ { 105, 0x00 },
+ { 106, 0x01 },
{ 107, 0x00 },
{ 108, 0x00 },
{ 109, 0x00 },
@@ -163,56 +163,25 @@ static struct reg_default lm49453_reg_defs[] = {
{ 184, 0x00 },
{ 185, 0x00 },
{ 186, 0x00 },
- { 189, 0x00 },
+ { 187, 0x00 },
{ 188, 0x00 },
- { 194, 0x00 },
- { 195, 0x00 },
- { 196, 0x00 },
- { 197, 0x00 },
- { 200, 0x00 },
- { 201, 0x00 },
- { 202, 0x00 },
- { 203, 0x00 },
- { 204, 0x00 },
- { 205, 0x00 },
- { 208, 0x00 },
+ { 189, 0x00 },
+ { 208, 0x06 },
{ 209, 0x00 },
- { 210, 0x00 },
- { 211, 0x00 },
- { 213, 0x00 },
- { 214, 0x00 },
- { 215, 0x00 },
- { 216, 0x00 },
- { 217, 0x00 },
- { 218, 0x00 },
- { 219, 0x00 },
+ { 210, 0x08 },
+ { 211, 0x54 },
+ { 212, 0x14 },
+ { 213, 0x0d },
+ { 214, 0x0d },
+ { 215, 0x14 },
+ { 216, 0x60 },
{ 221, 0x00 },
{ 222, 0x00 },
+ { 223, 0x00 },
{ 224, 0x00 },
- { 225, 0x00 },
- { 226, 0x00 },
- { 227, 0x00 },
- { 228, 0x00 },
- { 229, 0x00 },
- { 230, 0x13 },
- { 231, 0x00 },
- { 232, 0x80 },
- { 233, 0x0C },
- { 234, 0xDD },
- { 235, 0x00 },
- { 236, 0x04 },
- { 237, 0x00 },
- { 238, 0x00 },
- { 239, 0x00 },
- { 240, 0x00 },
- { 241, 0x00 },
- { 242, 0x00 },
- { 243, 0x00 },
- { 244, 0x00 },
- { 245, 0x00 },
{ 248, 0x00 },
{ 249, 0x00 },
- { 254, 0x00 },
+ { 250, 0x00 },
{ 255, 0x00 },
};
@@ -525,36 +494,41 @@ SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT2_TX2_REG, 7, 1, 0),
};
/* TLV Declarations */
-static const DECLARE_TLV_DB_SCALE(digital_tlv, -7650, 150, 1);
-static const DECLARE_TLV_DB_SCALE(port_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(adc_dac_tlv, -7650, 150, 1);
+static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 200, 1);
+static const DECLARE_TLV_DB_SCALE(port_tlv, -1800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(stn_tlv, -7200, 150, 0);
static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = {
/* Sidetone supports mono only */
SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG,
- 0, 0x3F, 0, digital_tlv),
+ 0, 0x3F, 0, stn_tlv),
SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG,
- 0, 0x3F, 0, digital_tlv),
+ 0, 0x3F, 0, stn_tlv),
SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG,
- 0, 0x3F, 0, digital_tlv),
+ 0, 0x3F, 0, stn_tlv),
SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG,
- 0, 0x3F, 0, digital_tlv),
+ 0, 0x3F, 0, stn_tlv),
SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG,
- 0, 0x3F, 0, digital_tlv),
+ 0, 0x3F, 0, stn_tlv),
SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG,
- 0, 0x3F, 0, digital_tlv),
+ 0, 0x3F, 0, stn_tlv),
};
static const struct snd_kcontrol_new lm49453_snd_controls[] = {
/* mic1 and mic2 supports mono only */
- SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_ADC_LEVELL_REG, 0, 6,
- 0, digital_tlv),
- SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_ADC_LEVELR_REG, 0, 6,
- 0, digital_tlv),
+ SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_MICL_REG, 0, 15, 0, mic_tlv),
+ SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_MICR_REG, 0, 15, 0, mic_tlv),
+
+ SOC_SINGLE_TLV("ADCL Volume", LM49453_P0_ADC_LEVELL_REG, 0, 63,
+ 0, adc_dac_tlv),
+ SOC_SINGLE_TLV("ADCR Volume", LM49453_P0_ADC_LEVELR_REG, 0, 63,
+ 0, adc_dac_tlv),
SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG,
- LM49453_P0_DMIC1_LEVELR_REG, 0, 6, 0, digital_tlv),
+ LM49453_P0_DMIC1_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG,
- LM49453_P0_DMIC2_LEVELR_REG, 0, 6, 0, digital_tlv),
+ LM49453_P0_DMIC2_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum),
SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum),
@@ -569,16 +543,16 @@ static const struct snd_kcontrol_new lm49453_snd_controls[] = {
2, 1, 0),
SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG,
- LM49453_P0_DAC_HP_LEVELR_REG, 0, 6, 0, digital_tlv),
+ LM49453_P0_DAC_HP_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG,
- LM49453_P0_DAC_LO_LEVELR_REG, 0, 6, 0, digital_tlv),
+ LM49453_P0_DAC_LO_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG,
- LM49453_P0_DAC_LS_LEVELR_REG, 0, 6, 0, digital_tlv),
+ LM49453_P0_DAC_LS_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG,
- LM49453_P0_DAC_HA_LEVELR_REG, 0, 6, 0, digital_tlv),
+ LM49453_P0_DAC_HA_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG,
- 0, 6, 0, digital_tlv),
+ 0, 63, 0, adc_dac_tlv),
SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
0, 3, 0, port_tlv),
@@ -1218,7 +1192,7 @@ static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
}
snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG,
- LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(1)|BIT(5),
+ LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(0)|BIT(5),
(aif_val | mode | clk_phase));
snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift);
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index cb1675cd8e1..92bbfec9b10 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -401,7 +401,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
5, 1, 0),
SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL,
- 0, 4, 0, mic_gain_tlv),
+ 0, 3, 0, mic_gain_tlv),
};
/* mute the codec used by alsa core */
@@ -1344,7 +1344,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
SGTL5000_HP_ZCD_EN |
SGTL5000_ADC_ZCD_EN);
- snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 0);
+ snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2);
/*
* disable DAP
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index ab355c4f0b2..40c07be9b58 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -74,9 +74,10 @@
SNDRV_PCM_FMTBIT_S32_LE)
#define S2PC_VALUE 0x98
#define CLOCK_OUT 0x60
-#define LEFT_J_DATA_FORMAT 0x10
-#define I2S_DATA_FORMAT 0x12
-#define RIGHT_J_DATA_FORMAT 0x14
+#define DATA_FORMAT_MSK 0x0E
+#define LEFT_J_DATA_FORMAT 0x00
+#define I2S_DATA_FORMAT 0x02
+#define RIGHT_J_DATA_FORMAT 0x04
#define CODEC_MUTE_VAL 0x80
#define POWER_CNTLMSAK 0x40
@@ -289,7 +290,7 @@ static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
return -EINVAL;
}
- snd_soc_update_bits(codec, STA529_S2PCFG0, 0x0D, mode);
+ snd_soc_update_bits(codec, STA529_S2PCFG0, DATA_FORMAT_MSK, mode);
return 0;
}
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 5708a973a77..49891432af7 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1210,13 +1210,13 @@ static struct snd_soc_dai_driver aic3x_dai = {
.name = "tlv320aic3x-hifi",
.playback = {
.stream_name = "Playback",
- .channels_min = 1,
+ .channels_min = 2,
.channels_max = 2,
.rates = AIC3X_RATES,
.formats = AIC3X_FORMATS,},
.capture = {
.stream_name = "Capture",
- .channels_min = 1,
+ .channels_min = 2,
.channels_max = 2,
.rates = AIC3X_RATES,
.formats = AIC3X_FORMATS,},
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 1cbe88f01d6..eb96b876809 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -76,6 +76,8 @@ struct wm2000_priv {
int anc_download_size;
char *anc_download;
+
+ struct mutex lock;
};
static int wm2000_write(struct i2c_client *i2c, unsigned int reg,
@@ -209,9 +211,9 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY);
if (wm2000->speech_clarity)
- ret &= ~WM2000_SPEECH_CLARITY;
- else
ret |= WM2000_SPEECH_CLARITY;
+ else
+ ret &= ~WM2000_SPEECH_CLARITY;
wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret);
wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33);
@@ -599,13 +601,20 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
int anc_active = ucontrol->value.enumerated.item[0];
+ int ret;
if (anc_active > 1)
return -EINVAL;
+ mutex_lock(&wm2000->lock);
+
wm2000->anc_active = anc_active;
- return wm2000_anc_set_mode(wm2000);
+ ret = wm2000_anc_set_mode(wm2000);
+
+ mutex_unlock(&wm2000->lock);
+
+ return ret;
}
static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
@@ -625,13 +634,20 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
int val = ucontrol->value.enumerated.item[0];
+ int ret;
if (val > 1)
return -EINVAL;
+ mutex_lock(&wm2000->lock);
+
wm2000->spk_ena = val;
- return wm2000_anc_set_mode(wm2000);
+ ret = wm2000_anc_set_mode(wm2000);
+
+ mutex_unlock(&wm2000->lock);
+
+ return ret;
}
static const struct snd_kcontrol_new wm2000_controls[] = {
@@ -648,6 +664,9 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = w->codec;
struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+ int ret;
+
+ mutex_lock(&wm2000->lock);
if (SND_SOC_DAPM_EVENT_ON(event))
wm2000->anc_eng_ena = 1;
@@ -655,7 +674,11 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_OFF(event))
wm2000->anc_eng_ena = 0;
- return wm2000_anc_set_mode(wm2000);
+ ret = wm2000_anc_set_mode(wm2000);
+
+ mutex_unlock(&wm2000->lock);
+
+ return ret;
}
static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = {
@@ -782,6 +805,8 @@ static int wm2000_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
}
+ mutex_init(&wm2000->lock);
+
dev_set_drvdata(&i2c->dev, wm2000);
wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap);
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index afcf31df77e..d5371e0d890 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1019,8 +1019,6 @@ static const char *wm2200_mixer_texts[] = {
"EQR",
"LHPF1",
"LHPF2",
- "LHPF3",
- "LHPF4",
"DSP1.1",
"DSP1.2",
"DSP1.3",
@@ -1053,7 +1051,6 @@ static int wm2200_mixer_values[] = {
0x25,
0x50, /* EQ */
0x51,
- 0x52,
0x60, /* LHPF1 */
0x61, /* LHPF2 */
0x68, /* DSP1 */
@@ -1129,9 +1126,9 @@ SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL,
SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1),
-SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
+SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_2L,
WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1),
-SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
+SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_3L,
WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1),
SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L,
@@ -1566,15 +1563,9 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
case SND_SOC_DAIFMT_DSP_A:
fmt_val = 0;
break;
- case SND_SOC_DAIFMT_DSP_B:
- fmt_val = 1;
- break;
case SND_SOC_DAIFMT_I2S:
fmt_val = 2;
break;
- case SND_SOC_DAIFMT_LEFT_J:
- fmt_val = 3;
- break;
default:
dev_err(codec->dev, "Unsupported DAI format %d\n",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
@@ -1626,7 +1617,7 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
lrclk);
snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5,
- WM2200_AIF1_FMT_MASK << 1, fmt_val << 1);
+ WM2200_AIF1_FMT_MASK, fmt_val);
return 0;
}
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 5a5f3693623..54397a50807 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -1279,15 +1279,9 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
case SND_SOC_DAIFMT_DSP_A:
mask = 0;
break;
- case SND_SOC_DAIFMT_DSP_B:
- mask = 1;
- break;
case SND_SOC_DAIFMT_I2S:
mask = 2;
break;
- case SND_SOC_DAIFMT_LEFT_J:
- mask = 3;
- break;
default:
dev_err(codec->dev, "Unsupported DAI format %d\n",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 688ade08058..1440b3f9b7b 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -36,6 +36,9 @@
struct wm5102_priv {
struct arizona_priv core;
struct arizona_fll fll[2];
+
+ unsigned int spk_ena:2;
+ unsigned int spk_ena_pending:1;
};
static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
@@ -787,6 +790,47 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
};
+static int wm5102_spk_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+ struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
+
+ if (arizona->rev < 1)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (!wm5102->spk_ena) {
+ snd_soc_write(codec, 0x4f5, 0x25a);
+ wm5102->spk_ena_pending = true;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ if (wm5102->spk_ena_pending) {
+ msleep(75);
+ snd_soc_write(codec, 0x4f5, 0xda);
+ wm5102->spk_ena_pending = false;
+ wm5102->spk_ena++;
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wm5102->spk_ena--;
+ if (!wm5102->spk_ena)
+ snd_soc_write(codec, 0x4f5, 0x25a);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ if (!wm5102->spk_ena)
+ snd_soc_write(codec, 0x4f5, 0x0da);
+ break;
+ }
+
+ return 0;
+}
+
+
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
@@ -852,8 +896,7 @@ static const unsigned int wm5102_aec_loopback_values[] = {
static const struct soc_enum wm5102_aec_loopback =
SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
- ARIZONA_AEC_LOOPBACK_SRC_SHIFT,
- ARIZONA_AEC_LOOPBACK_SRC_MASK,
+ ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
ARRAY_SIZE(wm5102_aec_loopback_texts),
wm5102_aec_loopback_texts,
wm5102_aec_loopback_values);
@@ -1034,10 +1077,10 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
- ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+ ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
- ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+ ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index ae80c8c2853..7a090968c4f 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -344,8 +344,7 @@ static const unsigned int wm5110_aec_loopback_values[] = {
static const struct soc_enum wm5110_aec_loopback =
SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
- ARIZONA_AEC_LOOPBACK_SRC_SHIFT,
- ARIZONA_AEC_LOOPBACK_SRC_MASK,
+ ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
ARRAY_SIZE(wm5110_aec_loopback_texts),
wm5110_aec_loopback_texts,
wm5110_aec_loopback_values);
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index ffc89fab96f..f3f7e75f862 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/firmware.h>
+#include <linux/list.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -103,9 +104,19 @@
#define ADSP1_START_SHIFT 0 /* DSP1_START */
#define ADSP1_START_WIDTH 1 /* DSP1_START */
-#define ADSP2_CONTROL 0
-#define ADSP2_CLOCKING 1
-#define ADSP2_STATUS1 4
+/*
+ * ADSP1 Control 31
+ */
+#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
+#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
+#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
+
+#define ADSP2_CONTROL 0x0
+#define ADSP2_CLOCKING 0x1
+#define ADSP2_STATUS1 0x4
+#define ADSP2_WDMA_CONFIG_1 0x30
+#define ADSP2_WDMA_CONFIG_2 0x31
+#define ADSP2_RDMA_CONFIG_1 0x34
/*
* ADSP2 Control
@@ -143,6 +154,109 @@
#define ADSP2_RAM_RDY_SHIFT 0
#define ADSP2_RAM_RDY_WIDTH 1
+struct wm_adsp_buf {
+ struct list_head list;
+ void *buf;
+};
+
+static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
+ struct list_head *list)
+{
+ struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+
+ if (buf == NULL)
+ return NULL;
+
+ buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA);
+ if (!buf->buf) {
+ kfree(buf);
+ return NULL;
+ }
+
+ if (list)
+ list_add_tail(&buf->list, list);
+
+ return buf;
+}
+
+static void wm_adsp_buf_free(struct list_head *list)
+{
+ while (!list_empty(list)) {
+ struct wm_adsp_buf *buf = list_first_entry(list,
+ struct wm_adsp_buf,
+ list);
+ list_del(&buf->list);
+ kfree(buf->buf);
+ kfree(buf);
+ }
+}
+
+#define WM_ADSP_NUM_FW 4
+
+static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
+ "MBC/VSS", "Tx", "Tx Speaker", "Rx ANC"
+};
+
+static struct {
+ const char *file;
+} wm_adsp_fw[WM_ADSP_NUM_FW] = {
+ { .file = "mbc-vss" },
+ { .file = "tx" },
+ { .file = "tx-spk" },
+ { .file = "rx-anc" },
+};
+
+static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = adsp[e->shift_l].fw;
+
+ return 0;
+}
+
+static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
+
+ if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw)
+ return 0;
+
+ if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
+ return -EINVAL;
+
+ if (adsp[e->shift_l].running)
+ return -EBUSY;
+
+ adsp[e->shift_l].fw = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static const struct soc_enum wm_adsp_fw_enum[] = {
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+ SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+ SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+ SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
+};
+
+const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
+ SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
+ wm_adsp_fw_get, wm_adsp_fw_put),
+ SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
+ wm_adsp_fw_get, wm_adsp_fw_put),
+ SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
+ wm_adsp_fw_get, wm_adsp_fw_put),
+ SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
+ wm_adsp_fw_get, wm_adsp_fw_put),
+};
+EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
int type)
@@ -156,8 +270,29 @@ 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,
+ unsigned int offset)
+{
+ switch (region->type) {
+ case WMFW_ADSP1_PM:
+ return region->base + (offset * 3);
+ case WMFW_ADSP1_DM:
+ return region->base + (offset * 2);
+ case WMFW_ADSP2_XM:
+ return region->base + (offset * 2);
+ case WMFW_ADSP2_YM:
+ return region->base + (offset * 2);
+ case WMFW_ADSP1_ZM:
+ return region->base + (offset * 2);
+ default:
+ WARN_ON(NULL != "Unknown memory region type");
+ return offset;
+ }
+}
+
static int wm_adsp_load(struct wm_adsp *dsp)
{
+ LIST_HEAD(buf_list);
const struct firmware *firmware;
struct regmap *regmap = dsp->regmap;
unsigned int pos = 0;
@@ -169,6 +304,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
const struct wm_adsp_region *mem;
const char *region_name;
char *file, *text;
+ struct wm_adsp_buf *buf;
unsigned int reg;
int regions = 0;
int ret, offset, type, sizes;
@@ -177,7 +313,8 @@ static int wm_adsp_load(struct wm_adsp *dsp)
if (file == NULL)
return -ENOMEM;
- snprintf(file, PAGE_SIZE, "%s-dsp%d.wmfw", dsp->part, dsp->num);
+ snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
+ wm_adsp_fw[dsp->fw].file);
file[PAGE_SIZE - 1] = '\0';
ret = request_firmware(&firmware, file, dsp->dev);
@@ -282,27 +419,27 @@ static int wm_adsp_load(struct wm_adsp *dsp)
case WMFW_ADSP1_PM:
BUG_ON(!mem);
region_name = "PM";
- reg = mem->base + (offset * 3);
+ reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP1_DM:
BUG_ON(!mem);
region_name = "DM";
- reg = mem->base + (offset * 2);
+ reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP2_XM:
BUG_ON(!mem);
region_name = "XM";
- reg = mem->base + (offset * 2);
+ reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP2_YM:
BUG_ON(!mem);
region_name = "YM";
- reg = mem->base + (offset * 2);
+ reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP1_ZM:
BUG_ON(!mem);
region_name = "ZM";
- reg = mem->base + (offset * 2);
+ reg = wm_adsp_region_to_reg(mem, offset);
break;
default:
adsp_warn(dsp,
@@ -322,8 +459,16 @@ static int wm_adsp_load(struct wm_adsp *dsp)
}
if (reg) {
- ret = regmap_raw_write(regmap, reg, region->data,
- le32_to_cpu(region->len));
+ buf = wm_adsp_buf_alloc(region->data,
+ le32_to_cpu(region->len),
+ &buf_list);
+ if (!buf) {
+ adsp_err(dsp, "Out of memory\n");
+ return -ENOMEM;
+ }
+
+ ret = regmap_raw_write_async(regmap, reg, buf->buf,
+ le32_to_cpu(region->len));
if (ret != 0) {
adsp_err(dsp,
"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
@@ -337,12 +482,20 @@ static int wm_adsp_load(struct wm_adsp *dsp)
pos += le32_to_cpu(region->len) + sizeof(*region);
regions++;
}
-
+
+ ret = regmap_async_complete(regmap);
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to complete async write: %d\n", ret);
+ goto out_fw;
+ }
+
if (pos > firmware->size)
adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
file, regions, pos - firmware->size);
out_fw:
+ regmap_async_complete(regmap);
+ wm_adsp_buf_free(&buf_list);
release_firmware(firmware);
out:
kfree(file);
@@ -350,21 +503,222 @@ out:
return ret;
}
+static int wm_adsp_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;
+ const struct wm_adsp_region *mem;
+ unsigned int pos, term;
+ size_t algs, buf_size;
+ __be32 val;
+ 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;
+ }
+
+ if (mem == NULL) {
+ BUG_ON(mem != NULL);
+ 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);
+ adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
+ be32_to_cpu(adsp1_id.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);
+
+ 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);
+ adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
+ be32_to_cpu(adsp2_id.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);
+
+ pos = sizeof(adsp2_id) / 2;
+ term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
+ break;
+
+ default:
+ BUG_ON(NULL == "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));
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to read algorithm list end: %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)
+ return -ENOMEM;
+ region->type = WMFW_ADSP1_DM;
+ region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
+ region->base = be32_to_cpu(adsp1_alg[i].dm);
+ list_add_tail(&region->list, &dsp->alg_regions);
+
+ region = kzalloc(sizeof(*region), GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+ region->type = WMFW_ADSP1_ZM;
+ region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
+ region->base = be32_to_cpu(adsp1_alg[i].zm);
+ list_add_tail(&region->list, &dsp->alg_regions);
+ 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)
+ return -ENOMEM;
+ region->type = WMFW_ADSP2_XM;
+ region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
+ region->base = be32_to_cpu(adsp2_alg[i].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_alg[i].alg.id);
+ region->base = be32_to_cpu(adsp2_alg[i].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_alg[i].alg.id);
+ region->base = be32_to_cpu(adsp2_alg[i].zm);
+ list_add_tail(&region->list, &dsp->alg_regions);
+ break;
+ }
+ }
+
+out:
+ kfree(alg);
+ return ret;
+}
+
static int wm_adsp_load_coeff(struct wm_adsp *dsp)
{
+ LIST_HEAD(buf_list);
struct regmap *regmap = dsp->regmap;
struct wmfw_coeff_hdr *hdr;
struct wmfw_coeff_item *blk;
const struct firmware *firmware;
+ const struct wm_adsp_region *mem;
+ struct wm_adsp_alg_region *alg_region;
const char *region_name;
int ret, pos, blocks, type, offset, reg;
char *file;
+ struct wm_adsp_buf *buf;
+ int tmp;
file = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (file == NULL)
return -ENOMEM;
- snprintf(file, PAGE_SIZE, "%s-dsp%d.bin", dsp->part, dsp->num);
+ snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
+ wm_adsp_fw[dsp->fw].file);
file[PAGE_SIZE - 1] = '\0';
ret = request_firmware(&firmware, file, dsp->dev);
@@ -384,7 +738,17 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
hdr = (void*)&firmware->data[0];
if (memcmp(hdr->magic, "WMDR", 4) != 0) {
adsp_err(dsp, "%s: invalid magic\n", file);
- return -EINVAL;
+ goto out_fw;
+ }
+
+ switch (be32_to_cpu(hdr->rev) & 0xff) {
+ case 1:
+ break;
+ default:
+ adsp_err(dsp, "%s: Unsupported coefficient file format %d\n",
+ file, be32_to_cpu(hdr->rev) & 0xff);
+ ret = -EINVAL;
+ goto out_fw;
}
adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
@@ -399,8 +763,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
pos - firmware->size > sizeof(*blk)) {
blk = (void*)(&firmware->data[pos]);
- type = be32_to_cpu(blk->type) & 0xff;
- offset = le32_to_cpu(blk->offset) & 0xffffff;
+ type = le16_to_cpu(blk->type);
+ offset = le16_to_cpu(blk->offset);
adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
file, blocks, le32_to_cpu(blk->id),
@@ -413,21 +777,65 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
reg = 0;
region_name = "Unknown";
switch (type) {
- case WMFW_NAME_TEXT:
- case WMFW_INFO_TEXT:
+ case (WMFW_NAME_TEXT << 8):
+ case (WMFW_INFO_TEXT << 8):
break;
- case WMFW_ABSOLUTE:
+ case (WMFW_ABSOLUTE << 8):
region_name = "register";
reg = offset;
break;
+
+ case WMFW_ADSP1_DM:
+ case WMFW_ADSP1_ZM:
+ case WMFW_ADSP2_XM:
+ case WMFW_ADSP2_YM:
+ adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
+ file, blocks, le32_to_cpu(blk->len),
+ type, le32_to_cpu(blk->id));
+
+ mem = wm_adsp_find_region(dsp, type);
+ if (!mem) {
+ adsp_err(dsp, "No base for region %x\n", type);
+ break;
+ }
+
+ reg = 0;
+ list_for_each_entry(alg_region,
+ &dsp->alg_regions, list) {
+ if (le32_to_cpu(blk->id) == alg_region->alg &&
+ type == alg_region->type) {
+ reg = alg_region->base;
+ reg = wm_adsp_region_to_reg(mem,
+ reg);
+ reg += offset;
+ }
+ }
+
+ if (reg == 0)
+ adsp_err(dsp, "No %x for algorithm %x\n",
+ type, le32_to_cpu(blk->id));
+ break;
+
default:
- adsp_err(dsp, "Unknown region type %x\n", type);
+ adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n",
+ file, blocks, type, pos);
break;
}
if (reg) {
- ret = regmap_raw_write(regmap, reg, blk->data,
- le32_to_cpu(blk->len));
+ buf = wm_adsp_buf_alloc(blk->data,
+ le32_to_cpu(blk->len),
+ &buf_list);
+ if (!buf) {
+ adsp_err(dsp, "Out of memory\n");
+ return -ENOMEM;
+ }
+
+ adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
+ file, blocks, le32_to_cpu(blk->len),
+ reg);
+ ret = regmap_raw_write_async(regmap, reg, buf->buf,
+ le32_to_cpu(blk->len));
if (ret != 0) {
adsp_err(dsp,
"%s.%d: Failed to write to %x in %s\n",
@@ -435,21 +843,39 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
}
}
- pos += le32_to_cpu(blk->len) + sizeof(*blk);
+ tmp = le32_to_cpu(blk->len) % 4;
+ if (tmp)
+ pos += le32_to_cpu(blk->len) + (4 - tmp) + sizeof(*blk);
+ else
+ pos += le32_to_cpu(blk->len) + sizeof(*blk);
+
blocks++;
}
+ ret = regmap_async_complete(regmap);
+ if (ret != 0)
+ adsp_err(dsp, "Failed to complete async write: %d\n", ret);
+
if (pos > firmware->size)
adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
file, blocks, pos - firmware->size);
out_fw:
release_firmware(firmware);
+ wm_adsp_buf_free(&buf_list);
out:
kfree(file);
return 0;
}
+int wm_adsp1_init(struct wm_adsp *adsp)
+{
+ INIT_LIST_HEAD(&adsp->alg_regions);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp1_init);
+
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
@@ -458,16 +884,46 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = &dsps[w->shift];
int ret;
+ int val;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
ADSP1_SYS_ENA, ADSP1_SYS_ENA);
+ /*
+ * For simplicity set the DSP clock rate to be the
+ * SYSCLK rate rather than making it configurable.
+ */
+ if(dsp->sysclk_reg) {
+ ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val);
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
+ ret);
+ return ret;
+ }
+
+ val = (val & dsp->sysclk_mask)
+ >> dsp->sysclk_shift;
+
+ ret = regmap_update_bits(dsp->regmap,
+ dsp->base + ADSP1_CONTROL_31,
+ ADSP1_CLK_SEL_MASK, val);
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to set clock rate: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
ret = wm_adsp_load(dsp);
if (ret != 0)
goto err;
+ ret = wm_adsp_setup_algs(dsp);
+ if (ret != 0)
+ goto err;
+
ret = wm_adsp_load_coeff(dsp);
if (ret != 0)
goto err;
@@ -539,6 +995,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_soc_codec *codec = w->codec;
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = &dsps[w->shift];
+ struct wm_adsp_alg_region *alg_region;
unsigned int val;
int ret;
@@ -604,6 +1061,10 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
if (ret != 0)
goto err;
+ ret = wm_adsp_setup_algs(dsp);
+ if (ret != 0)
+ goto err;
+
ret = wm_adsp_load_coeff(dsp);
if (ret != 0)
goto err;
@@ -614,13 +1075,22 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
ADSP2_CORE_ENA | ADSP2_START);
if (ret != 0)
goto err;
+
+ dsp->running = true;
break;
case SND_SOC_DAPM_PRE_PMD:
+ dsp->running = false;
+
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
ADSP2_SYS_ENA | ADSP2_CORE_ENA |
ADSP2_START, 0);
+ /* Make sure DMAs are quiesced */
+ regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
+ 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);
@@ -635,6 +1105,14 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
"Failed to enable supply: %d\n",
ret);
}
+
+ while (!list_empty(&dsp->alg_regions)) {
+ alg_region = list_first_entry(&dsp->alg_regions,
+ struct wm_adsp_alg_region,
+ list);
+ list_del(&alg_region->list);
+ kfree(alg_region);
+ }
break;
default:
@@ -664,6 +1142,8 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
return ret;
}
+ INIT_LIST_HEAD(&adsp->alg_regions);
+
if (dvfs) {
adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
if (IS_ERR(adsp->dvfs)) {
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index ffd29a4609e..cb8871a3ec0 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -25,6 +25,13 @@ struct wm_adsp_region {
unsigned int base;
};
+struct wm_adsp_alg_region {
+ struct list_head list;
+ unsigned int alg;
+ int type;
+ unsigned int base;
+};
+
struct wm_adsp {
const char *part;
int num;
@@ -33,10 +40,18 @@ struct wm_adsp {
struct regmap *regmap;
int base;
+ int sysclk_reg;
+ int sysclk_mask;
+ int sysclk_shift;
+
+ struct list_head alg_regions;
const struct wm_adsp_region *mem;
int num_mems;
+ int fw;
+ bool running;
+
struct regulator *dvfs;
};
@@ -50,6 +65,9 @@ struct wm_adsp {
.shift = num, .event = wm_adsp2_event, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
+
+int wm_adsp1_init(struct wm_adsp *adsp);
int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
index 5632ded67fd..ef163360a74 100644
--- a/sound/soc/codecs/wmfw.h
+++ b/sound/soc/codecs/wmfw.h
@@ -93,15 +93,20 @@ struct wmfw_adsp2_alg_hdr {
struct wmfw_coeff_hdr {
u8 magic[4];
__le32 len;
- __le32 ver;
+ union {
+ __be32 rev;
+ __le32 ver;
+ };
+ union {
+ __be32 core;
+ __le32 core_ver;
+ };
u8 data[];
} __packed;
struct wmfw_coeff_item {
- union {
- __be32 type;
- __le32 offset;
- };
+ __le16 offset;
+ __le16 type;
__le32 id;
__le32 ver;
__le32 sr;
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 55e2bf652be..9321e5c9d8c 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -626,7 +626,7 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
int word_length)
{
u32 fmt;
- u32 rotate = (32 - word_length) / 4;
+ u32 rotate = (word_length / 4) & 0x7;
u32 mask = (1ULL << word_length) - 1;
/*
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index 1aa51300c56..deb30d59965 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -210,15 +210,19 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
switch (config->chan_nr) {
case EIGHT_CHANNEL_SUPPORT:
ch_reg = 3;
+ break;
case SIX_CHANNEL_SUPPORT:
ch_reg = 2;
+ break;
case FOUR_CHANNEL_SUPPORT:
ch_reg = 1;
+ break;
case TWO_CHANNEL_SUPPORT:
ch_reg = 0;
break;
default:
dev_err(dev->dev, "channel not supported\n");
+ return -EINVAL;
}
i2s_disable_channels(dev, substream->stream);
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index bf363d8d044..500f8ce55d7 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -154,26 +154,7 @@ static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
.pcm_free = imx_pcm_free,
};
-static int imx_soc_platform_probe(struct platform_device *pdev)
+int imx_pcm_dma_init(struct platform_device *pdev)
{
return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
}
-
-static int imx_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver imx_pcm_driver = {
- .driver = {
- .name = "imx-pcm-audio",
- .owner = THIS_MODULE,
- },
- .probe = imx_soc_platform_probe,
- .remove = imx_soc_platform_remove,
-};
-
-module_platform_driver(imx_pcm_driver);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-pcm-audio");
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 5ec362ae4d0..920f945cb2f 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -281,7 +281,7 @@ static struct snd_soc_platform_driver imx_soc_platform_fiq = {
.pcm_free = imx_pcm_fiq_free,
};
-static int imx_soc_platform_probe(struct platform_device *pdev)
+int imx_pcm_fiq_init(struct platform_device *pdev)
{
struct imx_ssi *ssi = platform_get_drvdata(pdev);
int ret;
@@ -314,23 +314,3 @@ failed_register:
return ret;
}
-
-static int imx_soc_platform_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver imx_pcm_driver = {
- .driver = {
- .name = "imx-fiq-pcm-audio",
- .owner = THIS_MODULE,
- },
-
- .probe = imx_soc_platform_probe,
- .remove = imx_soc_platform_remove,
-};
-
-module_platform_driver(imx_pcm_driver);
-
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/imx-pcm.c b/sound/soc/fsl/imx-pcm.c
index d5cd9eff3b4..0d0625bfcb6 100644
--- a/sound/soc/fsl/imx-pcm.c
+++ b/sound/soc/fsl/imx-pcm.c
@@ -104,6 +104,38 @@ void imx_pcm_free(struct snd_pcm *pcm)
}
EXPORT_SYMBOL_GPL(imx_pcm_free);
+static int imx_pcm_probe(struct platform_device *pdev)
+{
+ if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
+ return imx_pcm_fiq_init(pdev);
+
+ return imx_pcm_dma_init(pdev);
+}
+
+static int imx_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_device_id imx_pcm_devtype[] = {
+ { .name = "imx-pcm-audio", },
+ { .name = "imx-fiq-pcm-audio", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, imx_pcm_devtype);
+
+static struct platform_driver imx_pcm_driver = {
+ .driver = {
+ .name = "imx-pcm",
+ .owner = THIS_MODULE,
+ },
+ .id_table = imx_pcm_devtype,
+ .probe = imx_pcm_probe,
+ .remove = imx_pcm_remove,
+};
+module_platform_driver(imx_pcm_driver);
+
MODULE_DESCRIPTION("Freescale i.MX PCM driver");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
index 83c0ed7d55c..5ae13a13a35 100644
--- a/sound/soc/fsl/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -30,4 +30,22 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
void imx_pcm_free(struct snd_pcm *pcm);
+#ifdef CONFIG_SND_SOC_IMX_PCM_DMA
+int imx_pcm_dma_init(struct platform_device *pdev);
+#else
+static inline int imx_pcm_dma_init(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
+#endif
+
+#ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
+int imx_pcm_fiq_init(struct platform_device *pdev);
+#else
+static inline int imx_pcm_fiq_init(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
+#endif
+
#endif /* _IMX_PCM_H */
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index ee10e8704e9..13f6dd1ceb0 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -469,7 +469,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
{
int ret = 0;
- ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
if (ret) {
pr_err("failed to register the dai\n");
return ret;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 91d592ff67b..2370063b582 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1255,6 +1255,8 @@ static int soc_post_component_init(struct snd_soc_card *card,
INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
ret = device_add(rtd->dev);
if (ret < 0) {
+ /* calling put_device() here to free the rtd->dev */
+ put_device(rtd->dev);
dev_err(card->dev,
"ASoC: failed to register runtime device: %d\n", ret);
return ret;
@@ -1554,7 +1556,7 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
/* unregister the rtd device */
if (rtd->dev_registered) {
device_remove_file(rtd->dev, &dev_attr_codec_reg);
- device_del(rtd->dev);
+ device_unregister(rtd->dev);
rtd->dev_registered = 0;
}
@@ -2917,7 +2919,7 @@ int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
platform_max = mc->platform_max;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
+ uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = platform_max - min;
@@ -2941,12 +2943,14 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
+ unsigned int rreg = mc->rreg;
unsigned int shift = mc->shift;
int min = mc->min;
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
unsigned int val, val_mask;
+ int ret;
val = ((ucontrol->value.integer.value[0] + min) & mask);
if (invert)
@@ -2954,7 +2958,21 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
val_mask = mask << shift;
val = val << shift;
- return snd_soc_update_bits_locked(codec, reg, val_mask, val);
+ ret = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+ if (ret != 0)
+ return ret;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ val = ((ucontrol->value.integer.value[1] + min) & mask);
+ if (invert)
+ val = max - val;
+ val_mask = mask << shift;
+ val = val << shift;
+
+ ret = snd_soc_update_bits_locked(codec, rreg, val_mask, val);
+ }
+
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
@@ -2974,6 +2992,7 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
+ unsigned int rreg = mc->rreg;
unsigned int shift = mc->shift;
int min = mc->min;
int max = mc->max;
@@ -2988,6 +3007,16 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] =
ucontrol->value.integer.value[0] - min;
+ if (snd_soc_volsw_is_stereo(mc)) {
+ ucontrol->value.integer.value[1] =
+ (snd_soc_read(codec, rreg) >> shift) & mask;
+ if (invert)
+ ucontrol->value.integer.value[1] =
+ max - ucontrol->value.integer.value[1];
+ ucontrol->value.integer.value[1] =
+ ucontrol->value.integer.value[1] - min;
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1e36bc81e5a..258acadb9e7 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1023,7 +1023,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_ON(event)) {
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
- ret = regulator_allow_bypass(w->regulator, true);
+ ret = regulator_allow_bypass(w->regulator, false);
if (ret != 0)
dev_warn(w->dapm->dev,
"ASoC: Failed to bypass %s: %d\n",
@@ -1033,7 +1033,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
return regulator_enable(w->regulator);
} else {
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
- ret = regulator_allow_bypass(w->regulator, false);
+ ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0)
dev_warn(w->dapm->dev,
"ASoC: Failed to unbypass %s: %d\n",
@@ -3039,6 +3039,14 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
w->name, ret);
return NULL;
}
+
+ if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+ ret = regulator_allow_bypass(w->regulator, true);
+ if (ret != 0)
+ dev_warn(w->dapm->dev,
+ "ASoC: Failed to unbypass %s: %d\n",
+ w->name, ret);
+ }
break;
case snd_soc_dapm_clock_supply:
#ifdef CONFIG_CLKDEV_LOOKUP
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index d7711fce119..cf191e6aebb 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1243,6 +1243,7 @@ static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
continue;
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index ae699073878..204b899c231 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -24,7 +24,7 @@
#include "ux500_pcm.h"
#include "ux500_msp_dai.h"
-#include <mop500_ab8500.h>
+#include "mop500_ab8500.h"
/* Define the whole MOP500 soundcard, linking platform to the codec-drivers */
struct snd_soc_dai_link mop500_dai_links[] = {