summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/amd/acp-pcm-dma.c1
-rw-r--r--sound/soc/codecs/Kconfig21
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/ab8500-codec.c9
-rw-r--r--sound/soc/codecs/adau17x1.h6
-rw-r--r--sound/soc/codecs/ads117x.c12
-rw-r--r--sound/soc/codecs/arizona.c114
-rw-r--r--sound/soc/codecs/arizona.h4
-rw-r--r--sound/soc/codecs/cs42l51.c8
-rw-r--r--sound/soc/codecs/cs47l24.c123
-rw-r--r--sound/soc/codecs/da732x.c8
-rw-r--r--sound/soc/codecs/hdac_hdmi.c1220
-rw-r--r--sound/soc/codecs/hdac_hdmi.h6
-rw-r--r--sound/soc/codecs/max98088.c2
-rw-r--r--sound/soc/codecs/max98095.c4
-rw-r--r--sound/soc/codecs/pcm179x-i2c.c73
-rw-r--r--sound/soc/codecs/pcm179x-spi.c72
-rw-r--r--sound/soc/codecs/pcm179x.c56
-rw-r--r--sound/soc/codecs/pcm179x.h9
-rw-r--r--sound/soc/codecs/pcm3168a.c8
-rw-r--r--sound/soc/codecs/rt286.c26
-rw-r--r--sound/soc/codecs/rt5645.c17
-rw-r--r--sound/soc/codecs/rt5659.c31
-rw-r--r--sound/soc/codecs/rt5659.h1
-rw-r--r--sound/soc/codecs/sigmadsp-i2c.c5
-rw-r--r--sound/soc/codecs/tlv320dac33.c9
-rw-r--r--sound/soc/codecs/wl1273.c13
-rw-r--r--sound/soc/codecs/wm5102.c93
-rw-r--r--sound/soc/codecs/wm5110.c76
-rw-r--r--sound/soc/codecs/wm8753.c6
-rw-r--r--sound/soc/codecs/wm8904.c4
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c8
-rw-r--r--sound/soc/codecs/wm8960.c40
-rw-r--r--sound/soc/codecs/wm8983.c14
-rw-r--r--sound/soc/codecs/wm8985.c14
-rw-r--r--sound/soc/codecs/wm8994.c4
-rw-r--r--sound/soc/codecs/wm8996.c2
-rw-r--r--sound/soc/codecs/wm8997.c2
-rw-r--r--sound/soc/codecs/wm8998.c2
-rw-r--r--sound/soc/codecs/wm9081.c8
-rw-r--r--sound/soc/codecs/wm9713.c2
-rw-r--r--sound/soc/codecs/wm_adsp.c139
-rw-r--r--sound/soc/codecs/wm_adsp.h8
-rw-r--r--sound/soc/dwc/designware_i2s.c5
-rw-r--r--sound/soc/fsl/imx-spdif.c2
-rw-r--r--sound/soc/generic/simple-card.c2
-rw-r--r--sound/soc/intel/Kconfig17
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c1
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_ipc.c2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c50
-rw-r--r--sound/soc/intel/boards/cht_bsw_max98090_ti.c17
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c34
-rw-r--r--sound/soc/intel/boards/mfld_machine.c16
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c122
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c130
-rw-r--r--sound/soc/intel/boards/skl_rt286.c118
-rw-r--r--sound/soc/intel/common/Makefile9
-rw-r--r--sound/soc/intel/common/sst-acpi.c4
-rw-r--r--sound/soc/intel/common/sst-acpi.h3
-rw-r--r--sound/soc/intel/common/sst-dsp-priv.h1
-rw-r--r--sound/soc/intel/common/sst-match-acpi.c48
-rw-r--r--sound/soc/intel/skylake/skl-messages.c130
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c34
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c105
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.c14
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h7
-rw-r--r--sound/soc/intel/skylake/skl-sst.c3
-rw-r--r--sound/soc/intel/skylake/skl-topology.c285
-rw-r--r--sound/soc/intel/skylake/skl-topology.h27
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h3
-rw-r--r--sound/soc/intel/skylake/skl.c90
-rw-r--r--sound/soc/intel/skylake/skl.h15
-rw-r--r--sound/soc/mediatek/Kconfig4
-rw-r--r--sound/soc/mxs/mxs-saif.c13
-rw-r--r--sound/soc/omap/n810.c18
-rw-r--r--sound/soc/omap/rx51.c18
-rw-r--r--sound/soc/pxa/corgi.c12
-rw-r--r--sound/soc/pxa/magician.c6
-rw-r--r--sound/soc/pxa/poodle.c12
-rw-r--r--sound/soc/pxa/spitz.c12
-rw-r--r--sound/soc/pxa/tosa.c12
-rw-r--r--sound/soc/qcom/lpass-cpu.c1
-rw-r--r--sound/soc/qcom/lpass-platform.c15
-rw-r--r--sound/soc/samsung/i2s.c21
-rw-r--r--sound/soc/soc-core.c8
-rw-r--r--sound/soc/soc-dapm.c20
-rw-r--r--sound/soc/soc-pcm.c27
88 files changed, 3051 insertions, 730 deletions
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 3191e0a7d273..d1fb035f44db 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -635,6 +635,7 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
dev_err(prtd->platform->dev, "set integer constraint failed\n");
+ kfree(adata);
return ret;
}
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 50693c867e71..bfbb6deb1be6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -87,7 +87,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ML26124 if I2C
select SND_SOC_NAU8825 if I2C
select SND_SOC_PCM1681 if I2C
- select SND_SOC_PCM179X if SPI_MASTER
+ select SND_SOC_PCM179X_I2C if I2C
+ select SND_SOC_PCM179X_SPI if SPI_MASTER
select SND_SOC_PCM3008
select SND_SOC_PCM3168A_I2C if I2C
select SND_SOC_PCM3168A_SPI if SPI_MASTER
@@ -490,6 +491,7 @@ config SND_SOC_GTM601
config SND_SOC_HDAC_HDMI
tristate
select SND_HDA_EXT_CORE
+ select SND_PCM_ELD
select HDMI
config SND_SOC_ICS43432
@@ -527,8 +529,23 @@ config SND_SOC_PCM1681
depends on I2C
config SND_SOC_PCM179X
- tristate "Texas Instruments PCM179X CODEC"
+ tristate
+
+config SND_SOC_PCM179X_I2C
+ tristate "Texas Instruments PCM179X CODEC (I2C)"
+ depends on I2C
+ select SND_SOC_PCM179X
+ help
+ Enable support for Texas Instruments PCM179x CODEC.
+ Select this if your PCM179x is connected via an I2C bus.
+
+config SND_SOC_PCM179X_SPI
+ tristate "Texas Instruments PCM179X CODEC (SPI)"
depends on SPI_MASTER
+ select SND_SOC_PCM179X
+ help
+ Enable support for Texas Instruments PCM179x CODEC.
+ Select this if your PCM179x is connected via an SPI bus.
config SND_SOC_PCM3008
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d44f7d347183..9acd777a7a98 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -81,6 +81,8 @@ snd-soc-ml26124-objs := ml26124.o
snd-soc-nau8825-objs := nau8825.o
snd-soc-pcm1681-objs := pcm1681.o
snd-soc-pcm179x-codec-objs := pcm179x.o
+snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o
+snd-soc-pcm179x-spi-objs := pcm179x-spi.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-pcm3168a-objs := pcm3168a.o
snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
@@ -285,6 +287,8 @@ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o
+obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o
+obj-$(CONFIG_SND_SOC_PCM179X_SPI) += snd-soc-pcm179x-spi.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index affb192238a4..8b1d0c1a7839 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -1130,7 +1130,7 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
mutex_lock(&drvdata->ctrl_lock);
- ucontrol->value.integer.value[0] = drvdata->sid_status;
+ ucontrol->value.enumerated.item[0] = drvdata->sid_status;
mutex_unlock(&drvdata->ctrl_lock);
return 0;
@@ -1147,7 +1147,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
dev_dbg(codec->dev, "%s: Enter\n", __func__);
- if (ucontrol->value.integer.value[0] != SID_APPLY_FIR) {
+ if (ucontrol->value.enumerated.item[0] != SID_APPLY_FIR) {
dev_err(codec->dev,
"%s: ERROR: This control supports '%s' only!\n",
__func__, enum_sid_state[SID_APPLY_FIR]);
@@ -1199,7 +1199,7 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
mutex_lock(&drvdata->ctrl_lock);
- ucontrol->value.integer.value[0] = drvdata->anc_status;
+ ucontrol->value.enumerated.item[0] = drvdata->anc_status;
mutex_unlock(&drvdata->ctrl_lock);
return 0;
@@ -1220,7 +1220,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
mutex_lock(&drvdata->ctrl_lock);
- req = ucontrol->value.integer.value[0];
+ req = ucontrol->value.enumerated.item[0];
if (req >= ARRAY_SIZE(enum_anc_state)) {
status = -EINVAL;
goto cleanup;
@@ -2134,7 +2134,6 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
"%s: ERROR: Unsupporter master mask 0x%x\n",
__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
return -EINVAL;
- break;
}
snd_soc_update_bits(codec, AB8500_DIGIFCONF3, mask, val);
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h
index e13583e6ff56..5ae87a084d97 100644
--- a/sound/soc/codecs/adau17x1.h
+++ b/sound/soc/codecs/adau17x1.h
@@ -103,9 +103,9 @@ bool adau17x1_has_dsp(struct adau *adau);
#define ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL BIT(3)
#define ADAU17X1_CLOCK_CONTROL_SYSCLK_EN BIT(0)
-#define ADAU17X1_SERIAL_PORT1_BCLK32 (0x0 << 5)
-#define ADAU17X1_SERIAL_PORT1_BCLK48 (0x1 << 5)
-#define ADAU17X1_SERIAL_PORT1_BCLK64 (0x2 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK64 (0x0 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK32 (0x1 << 5)
+#define ADAU17X1_SERIAL_PORT1_BCLK48 (0x2 << 5)
#define ADAU17X1_SERIAL_PORT1_BCLK128 (0x3 << 5)
#define ADAU17X1_SERIAL_PORT1_BCLK256 (0x4 << 5)
#define ADAU17X1_SERIAL_PORT1_BCLK_MASK (0x7 << 5)
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index 1222282e93c3..c5be1bdc2c9a 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -20,6 +20,8 @@
#include <sound/initval.h>
#include <sound/soc.h>
+#include <linux/of.h>
+
#define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
#define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
@@ -75,9 +77,19 @@ static int ads117x_remove(struct platform_device *pdev)
return 0;
}
+#if defined(CONFIG_OF)
+static const struct of_device_id ads117x_dt_ids[] = {
+ { .compatible = "ti,ads1174" },
+ { .compatible = "ti,ads1178" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ads117x_dt_ids);
+#endif
+
static struct platform_driver ads117x_codec_driver = {
.driver = {
.name = "ads117x-codec",
+ .of_match_table = of_match_ptr(ads117x_dt_ids),
},
.probe = ads117x_probe,
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 33143fe1de0b..92d22a018d68 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -1398,29 +1398,6 @@ static const int arizona_48k_bclk_rates[] = {
24576000,
};
-static const unsigned int arizona_48k_rates[] = {
- 12000,
- 24000,
- 48000,
- 96000,
- 192000,
- 384000,
- 768000,
- 4000,
- 8000,
- 16000,
- 32000,
- 64000,
- 128000,
- 256000,
- 512000,
-};
-
-static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
- .count = ARRAY_SIZE(arizona_48k_rates),
- .list = arizona_48k_rates,
-};
-
static const int arizona_44k1_bclk_rates[] = {
-1,
44100,
@@ -1443,22 +1420,7 @@ static const int arizona_44k1_bclk_rates[] = {
22579200,
};
-static const unsigned int arizona_44k1_rates[] = {
- 11025,
- 22050,
- 44100,
- 88200,
- 176400,
- 352800,
- 705600,
-};
-
-static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
- .count = ARRAY_SIZE(arizona_44k1_rates),
- .list = arizona_44k1_rates,
-};
-
-static int arizona_sr_vals[] = {
+static const unsigned int arizona_sr_vals[] = {
0,
12000,
24000,
@@ -1485,13 +1447,21 @@ static int arizona_sr_vals[] = {
512000,
};
+#define ARIZONA_48K_RATE_MASK 0x0F003E
+#define ARIZONA_44K1_RATE_MASK 0x003E00
+#define ARIZONA_RATE_MASK (ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK)
+
+static const struct snd_pcm_hw_constraint_list arizona_constraint = {
+ .count = ARRAY_SIZE(arizona_sr_vals),
+ .list = arizona_sr_vals,
+};
+
static int arizona_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
- const struct snd_pcm_hw_constraint_list *constraint;
unsigned int base_rate;
if (!substream->runtime)
@@ -1509,16 +1479,15 @@ static int arizona_startup(struct snd_pcm_substream *substream,
}
if (base_rate == 0)
- return 0;
-
- if (base_rate % 8000)
- constraint = &arizona_44k1_constraint;
+ dai_priv->constraint.mask = ARIZONA_RATE_MASK;
+ else if (base_rate % 8000)
+ dai_priv->constraint.mask = ARIZONA_44K1_RATE_MASK;
else
- constraint = &arizona_48k_constraint;
+ dai_priv->constraint.mask = ARIZONA_48K_RATE_MASK;
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
- constraint);
+ &dai_priv->constraint);
}
static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
@@ -1911,6 +1880,7 @@ int arizona_init_dai(struct arizona_priv *priv, int id)
struct arizona_dai_priv *dai_priv = &priv->dai[id];
dai_priv->clk = ARIZONA_CLK_SYSCLK;
+ dai_priv->constraint = arizona_constraint;
return 0;
}
@@ -1929,6 +1899,25 @@ static struct {
{ 1000000, 13500000, 0, 1 },
};
+static const unsigned int pseudo_fref_max[ARIZONA_FLL_MAX_FRATIO] = {
+ 13500000,
+ 6144000,
+ 6144000,
+ 3072000,
+ 3072000,
+ 2822400,
+ 2822400,
+ 1536000,
+ 1536000,
+ 1536000,
+ 1536000,
+ 1536000,
+ 1536000,
+ 1536000,
+ 1536000,
+ 768000,
+};
+
static struct {
unsigned int min;
unsigned int max;
@@ -2042,16 +2031,32 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
/* Adjust FRATIO/refdiv to avoid integer mode if possible */
refdiv = cfg->refdiv;
+ arizona_fll_dbg(fll, "pseudo: initial ratio=%u fref=%u refdiv=%u\n",
+ init_ratio, Fref, refdiv);
+
while (div <= ARIZONA_FLL_MAX_REFDIV) {
for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
ratio++) {
if ((ARIZONA_FLL_VCO_CORNER / 2) /
- (fll->vco_mult * ratio) < Fref)
+ (fll->vco_mult * ratio) < Fref) {
+ arizona_fll_dbg(fll, "pseudo: hit VCO corner\n");
break;
+ }
+
+ if (Fref > pseudo_fref_max[ratio - 1]) {
+ arizona_fll_dbg(fll,
+ "pseudo: exceeded max fref(%u) for ratio=%u\n",
+ pseudo_fref_max[ratio - 1],
+ ratio);
+ break;
+ }
if (target % (ratio * Fref)) {
cfg->refdiv = refdiv;
cfg->fratio = ratio - 1;
+ arizona_fll_dbg(fll,
+ "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
+ Fref, refdiv, div, ratio);
return ratio;
}
}
@@ -2060,6 +2065,9 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
if (target % (ratio * Fref)) {
cfg->refdiv = refdiv;
cfg->fratio = ratio - 1;
+ arizona_fll_dbg(fll,
+ "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
+ Fref, refdiv, div, ratio);
return ratio;
}
}
@@ -2068,6 +2076,9 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
Fref /= 2;
refdiv++;
init_ratio = arizona_find_fratio(Fref, NULL);
+ arizona_fll_dbg(fll,
+ "pseudo: change fref=%u refdiv=%d(%d) ratio=%u\n",
+ Fref, refdiv, div, init_ratio);
}
arizona_fll_warn(fll, "Falling back to integer mode operation\n");
@@ -2138,11 +2149,12 @@ static int arizona_calc_fll(struct arizona_fll *fll,
return -EINVAL;
}
- arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
+ arizona_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n",
cfg->n, cfg->theta, cfg->lambda);
- arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
- cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
- arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
+ arizona_fll_dbg(fll, "FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d)\n",
+ cfg->fratio, ratio, cfg->outdiv,
+ cfg->refdiv, 1 << cfg->refdiv);
+ arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
return 0;
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 8b6adb5419bb..1ea8e4ecf8d4 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -57,7 +57,7 @@
#define ARIZONA_CLK_98MHZ 5
#define ARIZONA_CLK_147MHZ 6
-#define ARIZONA_MAX_DAI 8
+#define ARIZONA_MAX_DAI 10
#define ARIZONA_MAX_ADSP 4
#define ARIZONA_DVFS_SR1_RQ 0x001
@@ -68,6 +68,8 @@ struct wm_adsp;
struct arizona_dai_priv {
int clk;
+
+ struct snd_pcm_hw_constraint_list constraint;
};
struct arizona_priv {
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index b3951524339f..35488f14e237 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -60,15 +60,15 @@ static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
switch (value) {
default:
case 0:
- ucontrol->value.integer.value[0] = 0;
+ ucontrol->value.enumerated.item[0] = 0;
break;
/* same value : (L+R)/2 and (R+L)/2 */
case 1:
case 2:
- ucontrol->value.integer.value[0] = 1;
+ ucontrol->value.enumerated.item[0] = 1;
break;
case 3:
- ucontrol->value.integer.value[0] = 2;
+ ucontrol->value.enumerated.item[0] = 2;
break;
}
@@ -85,7 +85,7 @@ static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
unsigned char val;
- switch (ucontrol->value.integer.value[0]) {
+ switch (ucontrol->value.enumerated.item[0]) {
default:
case 0:
val = CHAN_MIX_NORMAL;
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index dc5ae7f7a1bd..576087bda330 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -57,6 +57,25 @@ static const struct wm_adsp_region *cs47l24_dsp_regions[] = {
cs47l24_dsp3_regions,
};
+static int cs47l24_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;
+
+ 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 ret;
+ }
+
+ v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
+
+ return wm_adsp2_early_event(w, kcontrol, event, v);
+}
+
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
@@ -405,8 +424,8 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
NULL, 0),
-WM_ADSP2("DSP2", 1),
-WM_ADSP2("DSP3", 2),
+WM_ADSP2("DSP2", 1, cs47l24_adsp_power_ev),
+WM_ADSP2("DSP3", 2, cs47l24_adsp_power_ev),
SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
@@ -779,6 +798,9 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = {
{ "AIF2 Capture", NULL, "SYSCLK" },
{ "AIF3 Capture", NULL, "SYSCLK" },
+ { "Voice Control DSP", NULL, "DSP3" },
+ { "Voice Control DSP", NULL, "SYSCLK" },
+
{ "IN1L PGA", NULL, "IN1L" },
{ "IN1R PGA", NULL, "IN1R" },
@@ -901,7 +923,7 @@ static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
}
-#define CS47L24_RATES SNDRV_PCM_RATE_8000_192000
+#define CS47L24_RATES SNDRV_PCM_RATE_KNOT
#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -973,12 +995,68 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
.symmetric_rates = 1,
.symmetric_samplebits = 1,
},
+ {
+ .name = "cs47l24-cpu-voicectrl",
+ .capture = {
+ .stream_name = "Voice Control CPU",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = CS47L24_RATES,
+ .formats = CS47L24_FORMATS,
+ },
+ .compress_new = snd_soc_new_compress,
+ },
+ {
+ .name = "cs47l24-dsp-voicectrl",
+ .capture = {
+ .stream_name = "Voice Control DSP",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = CS47L24_RATES,
+ .formats = CS47L24_FORMATS,
+ },
+ },
};
+static int cs47l24_open(struct snd_compr_stream *stream)
+{
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
+ struct arizona *arizona = priv->core.arizona;
+ int n_adsp;
+
+ if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) {
+ n_adsp = 2;
+ } else {
+ dev_err(arizona->dev,
+ "No suitable compressed stream for DAI '%s'\n",
+ rtd->codec_dai->name);
+ return -EINVAL;
+ }
+
+ return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
+}
+
+static irqreturn_t cs47l24_adsp2_irq(int irq, void *data)
+{
+ struct cs47l24_priv *priv = data;
+ struct arizona *arizona = priv->core.arizona;
+ int ret;
+
+ ret = wm_adsp_compr_handle_irq(&priv->core.adsp[2]);
+ if (ret == -ENODEV) {
+ dev_err(arizona->dev, "Spurious compressed data IRQ\n");
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
static int cs47l24_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct arizona *arizona = priv->core.arizona;
int ret;
priv->core.arizona->dapm = dapm;
@@ -987,6 +1065,14 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
arizona_init_gpio(codec);
arizona_init_mono(codec);
+ ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+ "ADSP2 Compressed IRQ", cs47l24_adsp2_irq,
+ priv);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
+ return ret;
+ }
+
ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
if (ret)
goto err_adsp2_codec_probe;
@@ -1014,13 +1100,14 @@ err_adsp2_codec_probe:
static int cs47l24_codec_remove(struct snd_soc_codec *codec)
{
struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec);
-
+ struct arizona *arizona = priv->core.arizona;
wm_adsp2_codec_remove(&priv->core.adsp[1], codec);
wm_adsp2_codec_remove(&priv->core.adsp[2], codec);
priv->core.arizona->dapm = NULL;
+ arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
return 0;
}
@@ -1057,6 +1144,19 @@ static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = {
.num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes),
};
+static struct snd_compr_ops cs47l24_compr_ops = {
+ .open = cs47l24_open,
+ .free = wm_adsp_compr_free,
+ .set_params = wm_adsp_compr_set_params,
+ .get_caps = wm_adsp_compr_get_caps,
+ .trigger = wm_adsp_compr_trigger,
+ .pointer = wm_adsp_compr_pointer,
+ .copy = wm_adsp_compr_copy,
+};
+
+static struct snd_soc_platform_driver cs47l24_compr_platform = {
+ .compr_ops = &cs47l24_compr_ops,
+};
static int cs47l24_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -1120,12 +1220,25 @@ static int cs47l24_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
- return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
+ ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
+ return ret;
+ }
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24,
cs47l24_dai, ARRAY_SIZE(cs47l24_dai));
+
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+ snd_soc_unregister_platform(&pdev->dev);
+ }
+
+ return ret;
}
static int cs47l24_remove(struct platform_device *pdev)
{
+ snd_soc_unregister_platform(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 1d5a89c5164b..461506a4ca6a 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -334,7 +334,7 @@ static int da732x_hpf_set(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value;
unsigned int reg = enum_ctrl->reg;
- unsigned int sel = ucontrol->value.integer.value[0];
+ unsigned int sel = ucontrol->value.enumerated.item[0];
unsigned int bits;
switch (sel) {
@@ -368,13 +368,13 @@ static int da732x_hpf_get(struct snd_kcontrol *kcontrol,
switch (val) {
case DA732X_HPF_VOICE_EN:
- ucontrol->value.integer.value[0] = DA732X_HPF_VOICE;
+ ucontrol->value.enumerated.item[0] = DA732X_HPF_VOICE;
break;
case DA732X_HPF_MUSIC_EN:
- ucontrol->value.integer.value[0] = DA732X_HPF_MUSIC;
+ ucontrol->value.enumerated.item[0] = DA732X_HPF_MUSIC;
break;
default:
- ucontrol->value.integer.value[0] = DA732X_HPF_DISABLED;
+ ucontrol->value.enumerated.item[0] = DA732X_HPF_DISABLED;
break;
}
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 5a1ec0f7a1a6..cb0b036a1139 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -22,11 +22,17 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/hdmi.h>
+#include <drm/drm_edid.h>
#include <sound/pcm_params.h>
+#include <sound/jack.h>
#include <sound/soc.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda_i915.h>
+#include <sound/pcm_drm_eld.h>
#include "../../hda/local.h"
+#include "hdac_hdmi.h"
+
+#define NAME_SIZE 32
#define AMP_OUT_MUTE 0xb080
#define AMP_OUT_UNMUTE 0xb000
@@ -34,6 +40,11 @@
#define HDA_MAX_CONNECTIONS 32
+#define HDA_MAX_CVTS 3
+
+#define ELD_MAX_SIZE 256
+#define ELD_FIXED_BYTES 20
+
struct hdac_hdmi_cvt_params {
unsigned int channels_min;
unsigned int channels_max;
@@ -45,14 +56,34 @@ struct hdac_hdmi_cvt_params {
struct hdac_hdmi_cvt {
struct list_head head;
hda_nid_t nid;
+ const char *name;
struct hdac_hdmi_cvt_params params;
};
+struct hdac_hdmi_eld {
+ bool monitor_present;
+ bool eld_valid;
+ int eld_size;
+ char eld_buffer[ELD_MAX_SIZE];
+};
+
struct hdac_hdmi_pin {
struct list_head head;
hda_nid_t nid;
int num_mux_nids;
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+ struct hdac_hdmi_eld eld;
+ struct hdac_ext_device *edev;
+ int repoll_count;
+ struct delayed_work work;
+};
+
+struct hdac_hdmi_pcm {
+ struct list_head head;
+ int pcm_id;
+ struct hdac_hdmi_pin *pin;
+ struct hdac_hdmi_cvt *cvt;
+ struct snd_jack *jack;
};
struct hdac_hdmi_dai_pin_map {
@@ -62,11 +93,13 @@ struct hdac_hdmi_dai_pin_map {
};
struct hdac_hdmi_priv {
- struct hdac_hdmi_dai_pin_map dai_map[3];
+ struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS];
struct list_head pin_list;
struct list_head cvt_list;
+ struct list_head pcm_list;
int num_pin;
int num_cvt;
+ struct mutex pin_mutex;
};
static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
@@ -76,6 +109,119 @@ static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
return to_ehdac_device(hdac);
}
+static unsigned int sad_format(const u8 *sad)
+{
+ return ((sad[0] >> 0x3) & 0x1f);
+}
+
+static unsigned int sad_sample_bits_lpcm(const u8 *sad)
+{
+ return (sad[2] & 7);
+}
+
+static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
+ void *eld)
+{
+ u64 formats = SNDRV_PCM_FMTBIT_S16;
+ int i;
+ const u8 *sad, *eld_buf = eld;
+
+ sad = drm_eld_sad(eld_buf);
+ if (!sad)
+ goto format_constraint;
+
+ for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) {
+ if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */
+
+ /*
+ * the controller support 20 and 24 bits in 32 bit
+ * container so we set S32
+ */
+ if (sad_sample_bits_lpcm(sad) & 0x6)
+ formats |= SNDRV_PCM_FMTBIT_S32;
+ }
+ }
+
+format_constraint:
+ return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT,
+ formats);
+
+}
+
+ /* HDMI ELD routines */
+static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec,
+ hda_nid_t nid, int byte_index)
+{
+ unsigned int val;
+
+ val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD,
+ byte_index);
+
+ dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n",
+ byte_index, val);
+
+ return val;
+}
+
+static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid)
+{
+ return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
+ AC_DIPSIZE_ELD_BUF);
+}
+
+/*
+ * This function queries the ELD size and ELD data and fills in the buffer
+ * passed by user
+ */
+static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid,
+ unsigned char *buf, int *eld_size)
+{
+ int i, size, ret = 0;
+
+ /*
+ * ELD size is initialized to zero in caller function. If no errors and
+ * ELD is valid, actual eld_size is assigned.
+ */
+
+ size = hdac_hdmi_get_eld_size(codec, nid);
+ if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
+ dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size);
+ return -ERANGE;
+ }
+
+ /* set ELD buffer */
+ for (i = 0; i < size; i++) {
+ unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i);
+ /*
+ * Graphics driver might be writing to ELD buffer right now.
+ * Just abort. The caller will repoll after a while.
+ */
+ if (!(val & AC_ELDD_ELD_VALID)) {
+ dev_err(&codec->dev,
+ "HDMI: invalid ELD data byte %d\n", i);
+ ret = -EINVAL;
+ goto error;
+ }
+ val &= AC_ELDD_ELD_DATA;
+ /*
+ * The first byte cannot be zero. This can happen on some DVI
+ * connections. Some Intel chips may also need some 250ms delay
+ * to return non-zero ELD data, even when the graphics driver
+ * correctly writes ELD content before setting ELD_valid bit.
+ */
+ if (!val && !i) {
+ dev_err(&codec->dev, "HDMI: 0 ELD data\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ buf[i] = val;
+ }
+
+ *eld_size = size;
+error:
+ return ret;
+}
+
static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
hda_nid_t cvt_nid, hda_nid_t pin_nid,
u32 stream_tag, int format)
@@ -107,27 +253,75 @@ hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
AC_VERB_SET_HDMI_DIP_INDEX, val);
}
+struct dp_audio_infoframe {
+ u8 type; /* 0x84 */
+ u8 len; /* 0x1b */
+ u8 ver; /* 0x11 << 2 */
+
+ u8 CC02_CT47; /* match with HDMI infoframe from this on */
+ u8 SS01_SF24;
+ u8 CXT04;
+ u8 CA;
+ u8 LFEPBL01_LSV36_DM_INH7;
+};
+
static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
hda_nid_t cvt_nid, hda_nid_t pin_nid)
{
uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
struct hdmi_audio_infoframe frame;
- u8 *dip = (u8 *)&frame;
+ struct dp_audio_infoframe dp_ai;
+ struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ struct hdac_hdmi_pin *pin;
+ u8 *dip;
int ret;
int i;
+ const u8 *eld_buf;
+ u8 conn_type;
+ int channels = 2;
- hdmi_audio_infoframe_init(&frame);
+ list_for_each_entry(pin, &hdmi->pin_list, head) {
+ if (pin->nid == pin_nid)
+ break;
+ }
- /* Default stereo for now */
- frame.channels = 2;
+ eld_buf = pin->eld.eld_buffer;
+ conn_type = drm_eld_get_conn_type(eld_buf);
/* setup channel count */
snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
- AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1);
+ AC_VERB_SET_CVT_CHAN_COUNT, channels - 1);
- ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
- if (ret < 0)
- return ret;
+ switch (conn_type) {
+ case DRM_ELD_CONN_TYPE_HDMI:
+ hdmi_audio_infoframe_init(&frame);
+
+ /* Default stereo for now */
+ frame.channels = channels;
+
+ ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
+ if (ret < 0)
+ return ret;
+
+ dip = (u8 *)&frame;
+ break;
+
+ case DRM_ELD_CONN_TYPE_DP:
+ memset(&dp_ai, 0, sizeof(dp_ai));
+ dp_ai.type = 0x84;
+ dp_ai.len = 0x1b;
+ dp_ai.ver = 0x11 << 2;
+ dp_ai.CC02_CT47 = channels - 1;
+ dp_ai.CA = 0;
+
+ dip = (u8 *)&dp_ai;
+ break;
+
+ default:
+ dev_err(&hdac->hdac.dev, "Invalid connection type: %d\n",
+ conn_type);
+ return -EIO;
+ }
/* stop infoframe transmission */
hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
@@ -137,9 +331,15 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
/* Fill infoframe. Index auto-incremented */
hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
- for (i = 0; i < sizeof(frame); i++)
- snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ if (conn_type == DRM_ELD_CONN_TYPE_HDMI) {
+ for (i = 0; i < sizeof(frame); i++)
+ snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
+ } else {
+ for (i = 0; i < sizeof(dp_ai); i++)
+ snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
+ }
/* Start infoframe */
hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
@@ -174,11 +374,6 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
struct hdac_ext_dma_params *dd;
int ret;
- if (dai->id > 0) {
- dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
- return -ENODEV;
- }
-
dai_map = &hdmi->dai_map[dai->id];
dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
@@ -198,16 +393,30 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
{
struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+ struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ struct hdac_hdmi_dai_pin_map *dai_map;
+ struct hdac_hdmi_pin *pin;
struct hdac_ext_dma_params *dd;
- if (dai->id > 0) {
- dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
+ dai_map = &hdmi->dai_map[dai->id];
+ pin = dai_map->pin;
+
+ if (!pin)
+ return -ENODEV;
+
+ if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) {
+ dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n",
+ pin->nid);
return -ENODEV;
}
- dd = kzalloc(sizeof(*dd), GFP_KERNEL);
- if (!dd)
- return -ENOMEM;
+ dd = snd_soc_dai_get_dma_data(dai, substream);
+ if (!dd) {
+ dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+ if (!dd)
+ return -ENOMEM;
+ }
+
dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
params_channels(hparams), params_format(hparams),
24, 0);
@@ -227,50 +436,187 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id];
+ dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
+
+ if (dd) {
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+ kfree(dd);
+ }
+
+ return 0;
+}
+
+static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev,
+ struct hdac_hdmi_dai_pin_map *dai_map)
+{
+ /* Enable transmission */
snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
- AC_VERB_SET_CHANNEL_STREAMID, 0);
+ AC_VERB_SET_DIGI_CONVERT_1, 1);
+
+ /* Category Code (CC) to zero */
snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
- AC_VERB_SET_STREAM_FORMAT, 0);
+ AC_VERB_SET_DIGI_CONVERT_2, 0);
+}
- dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
- snd_soc_dai_set_dma_data(dai, substream, NULL);
+static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac,
+ struct hdac_hdmi_dai_pin_map *dai_map)
+{
+ int mux_idx;
+ struct hdac_hdmi_pin *pin = dai_map->pin;
+
+ for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) {
+ if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) {
+ snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+ AC_VERB_SET_CONNECT_SEL, mux_idx);
+ break;
+ }
+ }
- kfree(dd);
+ if (mux_idx == pin->num_mux_nids)
+ return -EIO;
+
+ /* Enable out path for this pin widget */
+ snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+ hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
+
+ snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
return 0;
}
+static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
+ struct hdac_hdmi_pin *pin)
+{
+ if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
+ dev_warn(&hdac->hdac.dev,
+ "HDMI: pin %d wcaps %#x does not support connection list\n",
+ pin->nid, get_wcaps(&hdac->hdac, pin->nid));
+ return -EINVAL;
+ }
+
+ pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
+ pin->mux_nids, HDA_MAX_CONNECTIONS);
+ if (pin->num_mux_nids == 0)
+ dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n",
+ pin->nid);
+
+ dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n",
+ pin->num_mux_nids, pin->nid);
+
+ return pin->num_mux_nids;
+}
+
+/*
+ * Query pcm list and return pin widget to which stream is routed.
+ *
+ * Also query connection list of the pin, to validate the cvt to pin map.
+ *
+ * Same stream rendering to multiple pins simultaneously can be done
+ * possibly, but not supported for now in driver. So return the first pin
+ * connected.
+ */
+static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt(
+ struct hdac_ext_device *edev,
+ struct hdac_hdmi_priv *hdmi,
+ struct hdac_hdmi_cvt *cvt)
+{
+ struct hdac_hdmi_pcm *pcm;
+ struct hdac_hdmi_pin *pin = NULL;
+ int ret, i;
+
+ list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+ if (pcm->cvt == cvt) {
+ pin = pcm->pin;
+ break;
+ }
+ }
+
+ if (pin) {
+ ret = hdac_hdmi_query_pin_connlist(edev, pin);
+ if (ret < 0)
+ return NULL;
+
+ for (i = 0; i < pin->num_mux_nids; i++) {
+ if (pin->mux_nids[i] == cvt->nid)
+ return pin;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * This tries to get a valid pin and set the HW constraints based on the
+ * ELD. Even if a valid pin is not found return success so that device open
+ * doesn't fail.
+ */
static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
struct hdac_hdmi_priv *hdmi = hdac->private_data;
struct hdac_hdmi_dai_pin_map *dai_map;
- int val;
-
- if (dai->id > 0) {
- dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
- return -ENODEV;
- }
+ struct hdac_hdmi_cvt *cvt;
+ struct hdac_hdmi_pin *pin;
+ int ret;
dai_map = &hdmi->dai_map[dai->id];
- val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0,
- AC_VERB_GET_PIN_SENSE, 0);
- dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
+ cvt = dai_map->cvt;
+ pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt);
- if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) {
- dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val);
- return -ENODEV;
+ /*
+ * To make PA and other userland happy.
+ * userland scans devices so returning error does not help.
+ */
+ if (!pin)
+ return 0;
+
+ if ((!pin->eld.monitor_present) ||
+ (!pin->eld.eld_valid)) {
+
+ dev_warn(&hdac->hdac.dev,
+ "Failed: montior present? %d ELD valid?: %d for pin: %d\n",
+ pin->eld.monitor_present, pin->eld.eld_valid, pin->nid);
+
+ return 0;
}
- hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
+ dai_map->pin = pin;
- snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ hdac_hdmi_enable_cvt(hdac, dai_map);
+ ret = hdac_hdmi_enable_pin(hdac, dai_map);
+ if (ret < 0)
+ return ret;
- snd_pcm_hw_constraint_step(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+ ret = hdac_hdmi_eld_limit_formats(substream->runtime,
+ pin->eld.eld_buffer);
+ if (ret < 0)
+ return ret;
+
+ return snd_pcm_hw_constraint_eld(substream->runtime,
+ pin->eld.eld_buffer);
+}
+
+static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct hdac_hdmi_dai_pin_map *dai_map;
+ struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
+ struct hdac_hdmi_priv *hdmi = hdac->private_data;
+ int ret;
+
+ dai_map = &hdmi->dai_map[dai->id];
+ if (cmd == SNDRV_PCM_TRIGGER_RESUME) {
+ ret = hdac_hdmi_enable_pin(hdac, dai_map);
+ if (ret < 0)
+ return ret;
+
+ return hdac_hdmi_playback_prepare(substream, dai);
+ }
return 0;
}
@@ -284,10 +630,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id];
- hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
+ if (dai_map->pin) {
+ snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0,
+ AC_VERB_SET_CHANNEL_STREAMID, 0);
+ snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0,
+ AC_VERB_SET_STREAM_FORMAT, 0);
+
+ hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
- snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
+ snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+ dai_map->pin = NULL;
+ }
}
static int
@@ -310,85 +665,326 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
return err;
}
-static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w,
- enum snd_soc_dapm_type id,
- const char *wname, const char *stream)
+static int hdac_hdmi_fill_widget_info(struct device *dev,
+ struct snd_soc_dapm_widget *w,
+ enum snd_soc_dapm_type id, void *priv,
+ const char *wname, const char *stream,
+ struct snd_kcontrol_new *wc, int numkc)
{
w->id = id;
- w->name = wname;
+ w->name = devm_kstrdup(dev, wname, GFP_KERNEL);
+ if (!w->name)
+ return -ENOMEM;
+
w->sname = stream;
w->reg = SND_SOC_NOPM;
w->shift = 0;
- w->kcontrol_news = NULL;
- w->num_kcontrols = 0;
- w->priv = NULL;
+ w->kcontrol_news = wc;
+ w->num_kcontrols = numkc;
+ w->priv = priv;
+
+ return 0;
}
static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
- const char *sink, const char *control, const char *src)
+ const char *sink, const char *control, const char *src,
+ int (*handler)(struct snd_soc_dapm_widget *src,
+ struct snd_soc_dapm_widget *sink))
{
route->sink = sink;
route->source = src;
route->control = control;
- route->connected = NULL;
+ route->connected = handler;
}
-static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm,
- struct hdac_hdmi_dai_pin_map *dai_map)
+static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
+ struct hdac_hdmi_pin *pin)
{
- struct snd_soc_dapm_route route[1];
- struct snd_soc_dapm_widget widgets[2] = { {0} };
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pcm *pcm = NULL;
- memset(&route, 0, sizeof(route));
+ list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+ if (pcm->pin == pin)
+ return pcm;
+ }
- hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output,
- "hif1 Output", NULL);
- hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
- "Coverter 1", "hif1");
+ return NULL;
+}
- hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1");
+/*
+ * Based on user selection, map the PINs with the PCMs.
+ */
+static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct hdac_hdmi_pin *pin = w->priv;
+ struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pcm *pcm = NULL;
+ const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]];
- snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets));
- snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route));
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&hdmi->pin_mutex);
+ list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+ if (pcm->pin == pin)
+ pcm->pin = NULL;
+
+ /*
+ * Jack status is not reported during device probe as the
+ * PCMs are not registered by then. So report it here.
+ */
+ if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) {
+ pcm->pin = pin;
+ if (pin->eld.monitor_present && pin->eld.eld_valid) {
+ dev_dbg(&edev->hdac.dev,
+ "jack report for pcm=%d\n",
+ pcm->pcm_id);
+
+ snd_jack_report(pcm->jack, SND_JACK_AVOUT);
+ }
+ mutex_unlock(&hdmi->pin_mutex);
+ return ret;
+ }
+ }
+ mutex_unlock(&hdmi->pin_mutex);
+
+ return ret;
}
-static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
+/*
+ * Ideally the Mux inputs should be based on the num_muxs enumerated, but
+ * the display driver seem to be programming the connection list for the pin
+ * widget runtime.
+ *
+ * So programming all the possible inputs for the mux, the user has to take
+ * care of selecting the right one and leaving all other inputs selected to
+ * "NONE"
+ */
+static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
+ struct hdac_hdmi_pin *pin,
+ struct snd_soc_dapm_widget *widget,
+ const char *widget_name)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
- struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0];
+ struct snd_kcontrol_new *kc;
+ struct hdac_hdmi_cvt *cvt;
+ struct soc_enum *se;
+ char kc_name[NAME_SIZE];
+ char mux_items[NAME_SIZE];
+ /* To hold inputs to the Pin mux */
+ char *items[HDA_MAX_CONNECTIONS];
+ int i = 0;
+ int num_items = hdmi->num_cvt + 1;
+
+ kc = devm_kzalloc(&edev->hdac.dev, sizeof(*kc), GFP_KERNEL);
+ if (!kc)
+ return -ENOMEM;
+
+ se = devm_kzalloc(&edev->hdac.dev, sizeof(*se), GFP_KERNEL);
+ if (!se)
+ return -ENOMEM;
+
+ sprintf(kc_name, "Pin %d Input", pin->nid);
+ kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL);
+ if (!kc->name)
+ return -ENOMEM;
+
+ kc->private_value = (long)se;
+ kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ kc->access = 0;
+ kc->info = snd_soc_info_enum_double;
+ kc->put = hdac_hdmi_set_pin_mux;
+ kc->get = snd_soc_dapm_get_enum_double;
+
+ se->reg = SND_SOC_NOPM;
+
+ /* enum texts: ["NONE", "cvt #", "cvt #", ...] */
+ se->items = num_items;
+ se->mask = roundup_pow_of_two(se->items) - 1;
+
+ sprintf(mux_items, "NONE");
+ items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL);
+ if (!items[i])
+ return -ENOMEM;
+
+ list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+ i++;
+ sprintf(mux_items, "cvt %d", cvt->nid);
+ items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL);
+ if (!items[i])
+ return -ENOMEM;
+ }
+
+ se->texts = devm_kmemdup(&edev->hdac.dev, items,
+ (num_items * sizeof(char *)), GFP_KERNEL);
+ if (!se->texts)
+ return -ENOMEM;
+
+ return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget,
+ snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1);
+}
+
+/* Add cvt <- input <- mux route map */
+static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
+ struct snd_soc_dapm_widget *widgets,
+ struct snd_soc_dapm_route *route, int rindex)
+{
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ const struct snd_kcontrol_new *kc;
+ struct soc_enum *se;
+ int mux_index = hdmi->num_cvt + hdmi->num_pin;
+ int i, j;
+
+ for (i = 0; i < hdmi->num_pin; i++) {
+ kc = widgets[mux_index].kcontrol_news;
+ se = (struct soc_enum *)kc->private_value;
+ for (j = 0; j < hdmi->num_cvt; j++) {
+ hdac_hdmi_fill_route(&route[rindex],
+ widgets[mux_index].name,
+ se->texts[j + 1],
+ widgets[j].name, NULL);
+
+ rindex++;
+ }
+
+ mux_index++;
+ }
+}
+
+/*
+ * Widgets are added in the below sequence
+ * Converter widgets for num converters enumerated
+ * Pin widgets for num pins enumerated
+ * Pin mux widgets to represent connenction list of pin widget
+ *
+ * Total widgets elements = num_cvt + num_pin + num_pin;
+ *
+ * Routes are added as below:
+ * pin mux -> pin (based on num_pins)
+ * cvt -> "Input sel control" -> pin_mux
+ *
+ * Total route elements:
+ * num_pins + (pin_muxes * num_cvt)
+ */
+static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
+{
+ struct snd_soc_dapm_widget *widgets;
+ struct snd_soc_dapm_route *route;
+ struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv;
+ char widget_name[NAME_SIZE];
struct hdac_hdmi_cvt *cvt;
struct hdac_hdmi_pin *pin;
+ int ret, i = 0, num_routes = 0;
if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
return -EINVAL;
- /*
- * Currently on board only 1 pin and 1 converter is enabled for
- * simplification, more will be added eventually
- * So using fixed map for dai_id:pin:cvt
- */
- cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head);
- pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head);
+ widgets = devm_kzalloc(dapm->dev,
+ (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)),
+ GFP_KERNEL);
- dai_map->dai_id = 0;
- dai_map->pin = pin;
+ if (!widgets)
+ return -ENOMEM;
- dai_map->cvt = cvt;
+ /* DAPM widgets to represent each converter widget */
+ list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+ sprintf(widget_name, "Converter %d", cvt->nid);
+ ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
+ snd_soc_dapm_aif_in, &cvt->nid,
+ widget_name, dai_drv[i].playback.stream_name, NULL, 0);
+ if (ret < 0)
+ return ret;
+ i++;
+ }
- /* Enable out path for this pin widget */
- snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ list_for_each_entry(pin, &hdmi->pin_list, head) {
+ sprintf(widget_name, "hif%d Output", pin->nid);
+ ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
+ snd_soc_dapm_output, &pin->nid,
+ widget_name, NULL, NULL, 0);
+ if (ret < 0)
+ return ret;
+ i++;
+ }
- /* Enable transmission */
- snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
- AC_VERB_SET_DIGI_CONVERT_1, 1);
+ /* DAPM widgets to represent the connection list to pin widget */
+ list_for_each_entry(pin, &hdmi->pin_list, head) {
+ sprintf(widget_name, "Pin %d Mux", pin->nid);
+ ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i],
+ widget_name);
+ if (ret < 0)
+ return ret;
+ i++;
- /* Category Code (CC) to zero */
- snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
- AC_VERB_SET_DIGI_CONVERT_2, 0);
+ /* For cvt to pin_mux mapping */
+ num_routes += hdmi->num_cvt;
+
+ /* For pin_mux to pin mapping */
+ num_routes++;
+ }
- snd_hdac_codec_write(&edev->hdac, pin->nid, 0,
- AC_VERB_SET_CONNECT_SEL, 0);
+ route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes),
+ GFP_KERNEL);
+ if (!route)
+ return -ENOMEM;
+
+ i = 0;
+ /* Add pin <- NULL <- mux route map */
+ list_for_each_entry(pin, &hdmi->pin_list, head) {
+ int sink_index = i + hdmi->num_cvt;
+ int src_index = sink_index + hdmi->num_pin;
+
+ hdac_hdmi_fill_route(&route[i],
+ widgets[sink_index].name, NULL,
+ widgets[src_index].name, NULL);
+ i++;
+
+ }
+
+ hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i);
+
+ snd_soc_dapm_new_controls(dapm, widgets,
+ ((2 * hdmi->num_pin) + hdmi->num_cvt));
+
+ snd_soc_dapm_add_routes(dapm, route, num_routes);
+ snd_soc_dapm_new_widgets(dapm->card);
+
+ return 0;
+
+}
+
+static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
+{
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_dai_pin_map *dai_map;
+ struct hdac_hdmi_cvt *cvt;
+ int dai_id = 0;
+
+ if (list_empty(&hdmi->cvt_list))
+ return -EINVAL;
+
+ list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+ dai_map = &hdmi->dai_map[dai_id];
+ dai_map->dai_id = dai_id;
+ dai_map->cvt = cvt;
+
+ dai_id++;
+
+ if (dai_id == HDA_MAX_CVTS) {
+ dev_warn(&edev->hdac.dev,
+ "Max dais supported: %d\n", dai_id);
+ break;
+ }
+ }
return 0;
}
@@ -397,12 +993,15 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_cvt *cvt;
+ char name[NAME_SIZE];
cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
if (!cvt)
return -ENOMEM;
cvt->nid = nid;
+ sprintf(name, "cvt %d", cvt->nid);
+ cvt->name = kstrdup(name, GFP_KERNEL);
list_add_tail(&cvt->head, &hdmi->cvt_list);
hdmi->num_cvt++;
@@ -410,6 +1009,106 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
}
+static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
+{
+ struct hdac_ext_device *edev = pin->edev;
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pcm *pcm;
+ int val;
+
+ pin->repoll_count = repoll;
+
+ pm_runtime_get_sync(&edev->hdac.dev);
+ val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0,
+ AC_VERB_GET_PIN_SENSE, 0);
+
+ dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n",
+ val, pin->nid);
+
+
+ mutex_lock(&hdmi->pin_mutex);
+ pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE);
+ pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV);
+
+ pcm = hdac_hdmi_get_pcm(edev, pin);
+
+ if (!pin->eld.monitor_present || !pin->eld.eld_valid) {
+
+ dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n",
+ __func__, pin->nid);
+
+ /*
+ * PCMs are not registered during device probe, so don't
+ * report jack here. It will be done in usermode mux
+ * control select.
+ */
+ if (pcm) {
+ dev_dbg(&edev->hdac.dev,
+ "jack report for pcm=%d\n", pcm->pcm_id);
+
+ snd_jack_report(pcm->jack, 0);
+ }
+
+ mutex_unlock(&hdmi->pin_mutex);
+ goto put_hdac_device;
+ }
+
+ if (pin->eld.monitor_present && pin->eld.eld_valid) {
+ /* TODO: use i915 component for reading ELD later */
+ if (hdac_hdmi_get_eld(&edev->hdac, pin->nid,
+ pin->eld.eld_buffer,
+ &pin->eld.eld_size) == 0) {
+
+ if (pcm) {
+ dev_dbg(&edev->hdac.dev,
+ "jack report for pcm=%d\n",
+ pcm->pcm_id);
+
+ snd_jack_report(pcm->jack, SND_JACK_AVOUT);
+ }
+
+ print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET,
+ pin->eld.eld_buffer, pin->eld.eld_size);
+ } else {
+ pin->eld.monitor_present = false;
+ pin->eld.eld_valid = false;
+
+ if (pcm) {
+ dev_dbg(&edev->hdac.dev,
+ "jack report for pcm=%d\n",
+ pcm->pcm_id);
+
+ snd_jack_report(pcm->jack, 0);
+ }
+ }
+ }
+
+ mutex_unlock(&hdmi->pin_mutex);
+
+ /*
+ * Sometimes the pin_sense may present invalid monitor
+ * present and eld_valid. If ELD data is not valid, loop few
+ * more times to get correct pin sense and valid ELD.
+ */
+ if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll)
+ schedule_delayed_work(&pin->work, msecs_to_jiffies(300));
+
+put_hdac_device:
+ pm_runtime_put_sync(&edev->hdac.dev);
+}
+
+static void hdac_hdmi_repoll_eld(struct work_struct *work)
+{
+ struct hdac_hdmi_pin *pin =
+ container_of(to_delayed_work(work), struct hdac_hdmi_pin, work);
+
+ /* picked from legacy HDA driver */
+ if (pin->repoll_count++ > 6)
+ pin->repoll_count = 0;
+
+ hdac_hdmi_present_sense(pin, pin->repoll_count);
+}
+
static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
@@ -424,6 +1123,120 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
list_add_tail(&pin->head, &hdmi->pin_list);
hdmi->num_pin++;
+ pin->edev = edev;
+ INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
+
+ return 0;
+}
+
+#define INTEL_VENDOR_NID 0x08
+#define INTEL_GET_VENDOR_VERB 0xf81
+#define INTEL_SET_VENDOR_VERB 0x781
+#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
+#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */
+
+static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
+{
+ unsigned int vendor_param;
+
+ vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+ INTEL_GET_VENDOR_VERB, 0);
+ if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
+ return;
+
+ vendor_param |= INTEL_EN_ALL_PIN_CVTS;
+ vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+ INTEL_SET_VENDOR_VERB, vendor_param);
+ if (vendor_param == -1)
+ return;
+}
+
+static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
+{
+ unsigned int vendor_param;
+
+ vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+ INTEL_GET_VENDOR_VERB, 0);
+ if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
+ return;
+
+ /* enable DP1.2 mode */
+ vendor_param |= INTEL_EN_DP12;
+ vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0,
+ INTEL_SET_VENDOR_VERB, vendor_param);
+ if (vendor_param == -1)
+ return;
+
+}
+
+static struct snd_soc_dai_ops hdmi_dai_ops = {
+ .startup = hdac_hdmi_pcm_open,
+ .shutdown = hdac_hdmi_pcm_close,
+ .hw_params = hdac_hdmi_set_hw_params,
+ .prepare = hdac_hdmi_playback_prepare,
+ .trigger = hdac_hdmi_trigger,
+ .hw_free = hdac_hdmi_playback_cleanup,
+};
+
+/*
+ * Each converter can support a stream independently. So a dai is created
+ * based on the number of converter queried.
+ */
+static int hdac_hdmi_create_dais(struct hdac_device *hdac,
+ struct snd_soc_dai_driver **dais,
+ struct hdac_hdmi_priv *hdmi, int num_dais)
+{
+ struct snd_soc_dai_driver *hdmi_dais;
+ struct hdac_hdmi_cvt *cvt;
+ char name[NAME_SIZE], dai_name[NAME_SIZE];
+ int i = 0;
+ u32 rates, bps;
+ unsigned int rate_max = 384000, rate_min = 8000;
+ u64 formats;
+ int ret;
+
+ hdmi_dais = devm_kzalloc(&hdac->dev,
+ (sizeof(*hdmi_dais) * num_dais),
+ GFP_KERNEL);
+ if (!hdmi_dais)
+ return -ENOMEM;
+
+ list_for_each_entry(cvt, &hdmi->cvt_list, head) {
+ ret = snd_hdac_query_supported_pcm(hdac, cvt->nid,
+ &rates, &formats, &bps);
+ if (ret)
+ return ret;
+
+ sprintf(dai_name, "intel-hdmi-hifi%d", i+1);
+ hdmi_dais[i].name = devm_kstrdup(&hdac->dev,
+ dai_name, GFP_KERNEL);
+
+ if (!hdmi_dais[i].name)
+ return -ENOMEM;
+
+ snprintf(name, sizeof(name), "hifi%d", i+1);
+ hdmi_dais[i].playback.stream_name =
+ devm_kstrdup(&hdac->dev, name, GFP_KERNEL);
+ if (!hdmi_dais[i].playback.stream_name)
+ return -ENOMEM;
+
+ /*
+ * Set caps based on capability queried from the converter.
+ * It will be constrained runtime based on ELD queried.
+ */
+ hdmi_dais[i].playback.formats = formats;
+ hdmi_dais[i].playback.rates = rates;
+ hdmi_dais[i].playback.rate_max = rate_max;
+ hdmi_dais[i].playback.rate_min = rate_min;
+ hdmi_dais[i].playback.channels_min = 2;
+ hdmi_dais[i].playback.channels_max = 2;
+ hdmi_dais[i].ops = &hdmi_dai_ops;
+
+ i++;
+ }
+
+ *dais = hdmi_dais;
+
return 0;
}
@@ -431,7 +1244,8 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
* Parse all nodes and store the cvt/pin nids in array
* Add one time initialization for pin and cvt widgets
*/
-static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
+static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
+ struct snd_soc_dai_driver **dais, int *num_dais)
{
hda_nid_t nid;
int i, num_nodes;
@@ -439,6 +1253,9 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
struct hdac_hdmi_priv *hdmi = edev->private_data;
int ret;
+ hdac_hdmi_skl_enable_all_pins(hdac);
+ hdac_hdmi_skl_enable_dp12(hdac);
+
num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
if (!nid || num_nodes <= 0) {
dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n");
@@ -479,19 +1296,107 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
if (!hdmi->num_pin || !hdmi->num_cvt)
return -EIO;
+ ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt);
+ if (ret) {
+ dev_err(&hdac->dev, "Failed to create dais with err: %d\n",
+ ret);
+ return ret;
+ }
+
+ *num_dais = hdmi->num_cvt;
+
return hdac_hdmi_init_dai_map(edev);
}
+static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
+{
+ struct hdac_ext_device *edev = aptr;
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pin *pin;
+ struct snd_soc_codec *codec = edev->scodec;
+
+ /* Don't know how this mapping is derived */
+ hda_nid_t pin_nid = port + 0x04;
+
+ dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid);
+
+ /*
+ * skip notification during system suspend (but not in runtime PM);
+ * the state will be updated at resume. Also since the ELD and
+ * connection states are updated in anyway at the end of the resume,
+ * we can skip it when received during PM process.
+ */
+ if (snd_power_get_state(codec->component.card->snd_card) !=
+ SNDRV_CTL_POWER_D0)
+ return;
+
+ if (atomic_read(&edev->hdac.in_pm))
+ return;
+
+ list_for_each_entry(pin, &hdmi->pin_list, head) {
+ if (pin->nid == pin_nid)
+ hdac_hdmi_present_sense(pin, 1);
+ }
+}
+
+static struct i915_audio_component_audio_ops aops = {
+ .pin_eld_notify = hdac_hdmi_eld_notify_cb,
+};
+
+int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
+{
+ char jack_name[NAME_SIZE];
+ struct snd_soc_codec *codec = dai->codec;
+ struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(&codec->component);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pcm *pcm;
+
+ /*
+ * this is a new PCM device, create new pcm and
+ * add to the pcm list
+ */
+ pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+ pcm->pcm_id = device;
+ pcm->cvt = hdmi->dai_map[dai->id].cvt;
+
+ list_add_tail(&pcm->head, &hdmi->pcm_list);
+
+ sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device);
+
+ return snd_jack_new(dapm->card->snd_card, jack_name,
+ SND_JACK_AVOUT, &pcm->jack, true, false);
+}
+EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
+
static int hdmi_codec_probe(struct snd_soc_codec *codec)
{
struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(&codec->component);
+ struct hdac_hdmi_pin *pin;
+ int ret;
edev->scodec = codec;
- create_fill_widget_route_map(dapm, &hdmi->dai_map[0]);
+ ret = create_fill_widget_route_map(dapm);
+ if (ret < 0)
+ return ret;
+
+ aops.audio_ptr = edev;
+ ret = snd_hdac_i915_register_notifier(&aops);
+ if (ret < 0) {
+ dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n",
+ ret);
+ return ret;
+ }
+
+ list_for_each_entry(pin, &hdmi->pin_list, head)
+ hdac_hdmi_present_sense(pin, 1);
/* Imp: Store the card pointer in hda_codec */
edev->card = dapm->card->snd_card;
@@ -515,44 +1420,73 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec)
return 0;
}
+#ifdef CONFIG_PM
+static int hdmi_codec_resume(struct snd_soc_codec *codec)
+{
+ struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pin *pin;
+ struct hdac_device *hdac = &edev->hdac;
+ struct hdac_bus *bus = hdac->bus;
+ int err;
+ unsigned long timeout;
+
+ hdac_hdmi_skl_enable_all_pins(&edev->hdac);
+ hdac_hdmi_skl_enable_dp12(&edev->hdac);
+
+ /* Power up afg */
+ if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) {
+
+ snd_hdac_codec_write(hdac, hdac->afg, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+ /* Wait till power state is set to D0 */
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)
+ && time_before(jiffies, timeout)) {
+ msleep(50);
+ }
+ }
+
+ /*
+ * As the ELD notify callback request is not entertained while the
+ * device is in suspend state. Need to manually check detection of
+ * all pins here.
+ */
+ list_for_each_entry(pin, &hdmi->pin_list, head)
+ hdac_hdmi_present_sense(pin, 1);
+
+ /*
+ * Codec power is turned ON during controller resume.
+ * Turn it OFF here
+ */
+ err = snd_hdac_display_power(bus, false);
+ if (err < 0) {
+ dev_err(bus->dev,
+ "Cannot turn OFF display power on i915, err: %d\n",
+ err);
+ return err;
+ }
+
+ return 0;
+}
+#else
+#define hdmi_codec_resume NULL
+#endif
+
static struct snd_soc_codec_driver hdmi_hda_codec = {
.probe = hdmi_codec_probe,
.remove = hdmi_codec_remove,
+ .resume = hdmi_codec_resume,
.idle_bias_off = true,
};
-static struct snd_soc_dai_ops hdmi_dai_ops = {
- .startup = hdac_hdmi_pcm_open,
- .shutdown = hdac_hdmi_pcm_close,
- .hw_params = hdac_hdmi_set_hw_params,
- .prepare = hdac_hdmi_playback_prepare,
- .hw_free = hdac_hdmi_playback_cleanup,
-};
-
-static struct snd_soc_dai_driver hdmi_dais[] = {
- { .name = "intel-hdmi-hif1",
- .playback = {
- .stream_name = "hif1",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S20_3LE |
- SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
-
- },
- .ops = &hdmi_dai_ops,
- },
-};
-
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
{
struct hdac_device *codec = &edev->hdac;
struct hdac_hdmi_priv *hdmi_priv;
+ struct snd_soc_dai_driver *hdmi_dais = NULL;
+ int num_dais = 0;
int ret = 0;
hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
@@ -565,14 +1499,31 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
INIT_LIST_HEAD(&hdmi_priv->pin_list);
INIT_LIST_HEAD(&hdmi_priv->cvt_list);
+ INIT_LIST_HEAD(&hdmi_priv->pcm_list);
+ mutex_init(&hdmi_priv->pin_mutex);
- ret = hdac_hdmi_parse_and_map_nid(edev);
- if (ret < 0)
+ /*
+ * Turned off in the runtime_suspend during the first explicit
+ * pm_runtime_suspend call.
+ */
+ ret = snd_hdac_display_power(edev->hdac.bus, true);
+ if (ret < 0) {
+ dev_err(&edev->hdac.dev,
+ "Cannot turn on display power on i915 err: %d\n",
+ ret);
return ret;
+ }
+
+ ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais);
+ if (ret < 0) {
+ dev_err(&codec->dev,
+ "Failed in parse and map nid with err: %d\n", ret);
+ return ret;
+ }
/* ASoC specific initialization */
return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
- hdmi_dais, ARRAY_SIZE(hdmi_dais));
+ hdmi_dais, num_dais);
}
static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
@@ -580,11 +1531,20 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pin *pin, *pin_next;
struct hdac_hdmi_cvt *cvt, *cvt_next;
+ struct hdac_hdmi_pcm *pcm, *pcm_next;
snd_soc_unregister_codec(&edev->hdac.dev);
+ list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
+ pcm->cvt = NULL;
+ pcm->pin = NULL;
+ list_del(&pcm->head);
+ kfree(pcm);
+ }
+
list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
list_del(&cvt->head);
+ kfree(cvt->name);
kfree(cvt);
}
@@ -602,6 +1562,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
struct hdac_ext_device *edev = to_hda_ext_device(dev);
struct hdac_device *hdac = &edev->hdac;
struct hdac_bus *bus = hdac->bus;
+ unsigned long timeout;
int err;
dev_dbg(dev, "Enter: %s\n", __func__);
@@ -611,10 +1572,19 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
return 0;
/* Power down afg */
- if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3))
+ if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) {
snd_hdac_codec_write(hdac, hdac->afg, 0,
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ /* Wait till power state is set to D3 */
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)
+ && time_before(jiffies, timeout)) {
+
+ msleep(50);
+ }
+ }
+
err = snd_hdac_display_power(bus, false);
if (err < 0) {
dev_err(bus->dev, "Cannot turn on display power on i915\n");
@@ -643,6 +1613,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
return err;
}
+ hdac_hdmi_skl_enable_all_pins(&edev->hdac);
+ hdac_hdmi_skl_enable_dp12(&edev->hdac);
+
/* Power up afg */
if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
snd_hdac_codec_write(hdac, hdac->afg, 0,
@@ -661,6 +1634,7 @@ static const struct dev_pm_ops hdac_hdmi_pm = {
static const struct hda_device_id hdmi_list[] = {
HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
+ HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
{}
};
diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h
new file mode 100644
index 000000000000..8dfd1e0b57b3
--- /dev/null
+++ b/sound/soc/codecs/hdac_hdmi.h
@@ -0,0 +1,6 @@
+#ifndef __HDAC_HDMI_H__
+#define __HDAC_HDMI_H__
+
+int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm);
+
+#endif /* __HDAC_HDMI_H__ */
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 20dcc496d39c..fc22804cabc5 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1496,7 +1496,7 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
struct max98088_pdata *pdata = max98088->pdata;
int channel = max98088_get_channel(codec, kcontrol->id.name);
struct max98088_cdata *cdata;
- int sel = ucontrol->value.integer.value[0];
+ int sel = ucontrol->value.enumerated.item[0];
if (channel < 0)
return channel;
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 1fedac50355e..3577003f39cf 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -1499,7 +1499,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
struct max98095_pdata *pdata = max98095->pdata;
int channel = max98095_get_eq_channel(kcontrol->id.name);
struct max98095_cdata *cdata;
- unsigned int sel = ucontrol->value.integer.value[0];
+ unsigned int sel = ucontrol->value.enumerated.item[0];
struct max98095_eq_cfg *coef_set;
int fs, best, best_val, i;
int regmask, regsave;
@@ -1653,7 +1653,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
struct max98095_pdata *pdata = max98095->pdata;
int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
struct max98095_cdata *cdata;
- unsigned int sel = ucontrol->value.integer.value[0];
+ unsigned int sel = ucontrol->value.enumerated.item[0];
struct max98095_biquad_cfg *coef_set;
int fs, best, best_val, i;
int regmask, regsave;
diff --git a/sound/soc/codecs/pcm179x-i2c.c b/sound/soc/codecs/pcm179x-i2c.c
new file mode 100644
index 000000000000..4118106abb8d
--- /dev/null
+++ b/sound/soc/codecs/pcm179x-i2c.c
@@ -0,0 +1,73 @@
+/*
+ * PCM179X ASoC I2C driver
+ *
+ * Copyright (c) Teenage Engineering AB 2016
+ *
+ * Jacob Siverskog <jacob@teenage.engineering>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include "pcm179x.h"
+
+static int pcm179x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = devm_regmap_init_i2c(client, &pcm179x_regmap_config);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ return pcm179x_common_init(&client->dev, regmap);
+}
+
+static int pcm179x_i2c_remove(struct i2c_client *client)
+{
+ return pcm179x_common_exit(&client->dev);
+}
+
+static const struct of_device_id pcm179x_of_match[] = {
+ { .compatible = "ti,pcm1792a", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm179x_of_match);
+
+static const struct i2c_device_id pcm179x_i2c_ids[] = {
+ { "pcm179x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcm179x_i2c_ids);
+
+static struct i2c_driver pcm179x_i2c_driver = {
+ .driver = {
+ .name = "pcm179x",
+ .of_match_table = of_match_ptr(pcm179x_of_match),
+ },
+ .id_table = pcm179x_i2c_ids,
+ .probe = pcm179x_i2c_probe,
+ .remove = pcm179x_i2c_remove,
+};
+
+module_i2c_driver(pcm179x_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC PCM179X I2C driver");
+MODULE_AUTHOR("Jacob Siverskog <jacob@teenage.engineering>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm179x-spi.c b/sound/soc/codecs/pcm179x-spi.c
new file mode 100644
index 000000000000..da924d444083
--- /dev/null
+++ b/sound/soc/codecs/pcm179x-spi.c
@@ -0,0 +1,72 @@
+/*
+ * PCM179X ASoC SPI driver
+ *
+ * Copyright (c) Amarula Solutions B.V. 2013
+ *
+ * Michael Trimarchi <michael@amarulasolutions.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+#include "pcm179x.h"
+
+static int pcm179x_spi_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = devm_regmap_init_spi(spi, &pcm179x_regmap_config);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ dev_err(&spi->dev, "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ return pcm179x_common_init(&spi->dev, regmap);
+}
+
+static int pcm179x_spi_remove(struct spi_device *spi)
+{
+ return pcm179x_common_exit(&spi->dev);
+}
+
+static const struct of_device_id pcm179x_of_match[] = {
+ { .compatible = "ti,pcm1792a", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm179x_of_match);
+
+static const struct spi_device_id pcm179x_spi_ids[] = {
+ { "pcm179x", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids);
+
+static struct spi_driver pcm179x_spi_driver = {
+ .driver = {
+ .name = "pcm179x",
+ .of_match_table = of_match_ptr(pcm179x_of_match),
+ },
+ .id_table = pcm179x_spi_ids,
+ .probe = pcm179x_spi_probe,
+ .remove = pcm179x_spi_remove,
+};
+
+module_spi_driver(pcm179x_spi_driver);
+
+MODULE_DESCRIPTION("ASoC PCM179X SPI driver");
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
index a56c7b767d90..06a66579ca6d 100644
--- a/sound/soc/codecs/pcm179x.c
+++ b/sound/soc/codecs/pcm179x.c
@@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -29,7 +28,6 @@
#include <sound/soc.h>
#include <sound/tlv.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include "pcm179x.h"
@@ -189,18 +187,14 @@ static struct snd_soc_dai_driver pcm179x_dai = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
- .rates = PCM1792A_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 10000,
+ .rate_max = 200000,
.formats = PCM1792A_FORMATS, },
.ops = &pcm179x_dai_ops,
};
-static const struct of_device_id pcm179x_of_match[] = {
- { .compatible = "ti,pcm1792a", },
- { }
-};
-MODULE_DEVICE_TABLE(of, pcm179x_of_match);
-
-static const struct regmap_config pcm179x_regmap = {
+const struct regmap_config pcm179x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 23,
@@ -209,6 +203,7 @@ static const struct regmap_config pcm179x_regmap = {
.writeable_reg = pcm179x_writeable_reg,
.readable_reg = pcm179x_accessible_reg,
};
+EXPORT_SYMBOL_GPL(pcm179x_regmap_config);
static struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
.controls = pcm179x_controls,
@@ -219,52 +214,29 @@ static struct snd_soc_codec_driver soc_codec_dev_pcm179x = {
.num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes),
};
-static int pcm179x_spi_probe(struct spi_device *spi)
+int pcm179x_common_init(struct device *dev, struct regmap *regmap)
{
struct pcm179x_private *pcm179x;
- int ret;
- pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private),
+ pcm179x = devm_kzalloc(dev, sizeof(struct pcm179x_private),
GFP_KERNEL);
if (!pcm179x)
return -ENOMEM;
- spi_set_drvdata(spi, pcm179x);
-
- pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap);
- if (IS_ERR(pcm179x->regmap)) {
- ret = PTR_ERR(pcm179x->regmap);
- dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
- return ret;
- }
+ pcm179x->regmap = regmap;
+ dev_set_drvdata(dev, pcm179x);
- return snd_soc_register_codec(&spi->dev,
+ return snd_soc_register_codec(dev,
&soc_codec_dev_pcm179x, &pcm179x_dai, 1);
}
+EXPORT_SYMBOL_GPL(pcm179x_common_init);
-static int pcm179x_spi_remove(struct spi_device *spi)
+int pcm179x_common_exit(struct device *dev)
{
- snd_soc_unregister_codec(&spi->dev);
+ snd_soc_unregister_codec(dev);
return 0;
}
-
-static const struct spi_device_id pcm179x_spi_ids[] = {
- { "pcm179x", 0 },
- { },
-};
-MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids);
-
-static struct spi_driver pcm179x_codec_driver = {
- .driver = {
- .name = "pcm179x",
- .of_match_table = of_match_ptr(pcm179x_of_match),
- },
- .id_table = pcm179x_spi_ids,
- .probe = pcm179x_spi_probe,
- .remove = pcm179x_spi_remove,
-};
-
-module_spi_driver(pcm179x_codec_driver);
+EXPORT_SYMBOL_GPL(pcm179x_common_exit);
MODULE_DESCRIPTION("ASoC PCM179X driver");
MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
diff --git a/sound/soc/codecs/pcm179x.h b/sound/soc/codecs/pcm179x.h
index c6fdc062a497..11e331268aae 100644
--- a/sound/soc/codecs/pcm179x.h
+++ b/sound/soc/codecs/pcm179x.h
@@ -17,11 +17,12 @@
#ifndef __PCM179X_H__
#define __PCM179X_H__
-#define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
- SNDRV_PCM_RATE_192000)
-
#define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S16_LE)
+extern const struct regmap_config pcm179x_regmap_config;
+
+int pcm179x_common_init(struct device *dev, struct regmap *regmap);
+int pcm179x_common_exit(struct device *dev);
+
#endif
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 44b268aa4dd8..992a77edcd5d 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -299,10 +299,15 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(dai->codec);
+ int ret;
if (freq > PCM1368A_MAX_SYSCLK)
return -EINVAL;
+ ret = clk_set_rate(pcm3168a->scki, freq);
+ if (ret)
+ return ret;
+
pcm3168a->sysclk = freq;
return 0;
@@ -395,13 +400,12 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec);
bool tx, master_mode;
u32 val, mask, shift, reg;
- unsigned int rate, channels, fmt, ratio, max_ratio;
+ unsigned int rate, fmt, ratio, max_ratio;
int i, min_frame_size;
snd_pcm_format_t format;
rate = params_rate(params);
format = params_format(params);
- channels = params_channels(params);
ratio = pcm3168a->sysclk / rate;
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index bc08f0c5a5f6..1bd31644a782 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -266,6 +266,8 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
} else {
*mic = false;
regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20);
+ regmap_update_bits(rt286->regmap,
+ RT286_CBJ_CTRL1, 0x0400, 0x0000);
}
} else {
regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
@@ -470,24 +472,6 @@ static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static int rt286_vref_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_PRE_PMU:
- snd_soc_update_bits(codec,
- RT286_CBJ_CTRL1, 0x0400, 0x0000);
- mdelay(50);
- break;
- default:
- return 0;
- }
-
- return 0;
-}
-
static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -536,7 +520,7 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1,
12, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1,
- 0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU),
+ 0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2,
2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1,
@@ -911,8 +895,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
mdelay(10);
snd_soc_update_bits(codec,
- RT286_CBJ_CTRL1, 0x0400, 0x0400);
- snd_soc_update_bits(codec,
RT286_DC_GAIN, 0x200, 0x0);
break;
@@ -920,8 +902,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
snd_soc_write(codec,
RT286_SET_AUDIO_POWER, AC_PWRST_D3);
- snd_soc_update_bits(codec,
- RT286_CBJ_CTRL1, 0x0400, 0x0000);
break;
default:
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index c61d38b585fb..7af5e7380d61 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -776,7 +776,7 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
/* IN1/IN2 Control */
SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1,
- RT5645_BST_SFT1, 8, 0, bst_tlv),
+ RT5645_BST_SFT1, 12, 0, bst_tlv),
SOC_SINGLE_TLV("IN2 Boost", RT5645_IN2_CTRL,
RT5645_BST_SFT2, 8, 0, bst_tlv),
@@ -1674,7 +1674,7 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
regmap_write(rt5645->regmap, RT5645_PR_BASE +
RT5645_MAMP_INT_REG2, 0xfc00);
snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
- msleep(70);
+ msleep(90);
rt5645->hp_on = true;
} else {
/* depop parameters */
@@ -3029,13 +3029,18 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
RT5645_PWR_BG | RT5645_PWR_VREF2,
RT5645_PWR_VREF1 | RT5645_PWR_MB |
RT5645_PWR_BG | RT5645_PWR_VREF2);
+ mdelay(10);
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
RT5645_PWR_FV1 | RT5645_PWR_FV2,
RT5645_PWR_FV1 | RT5645_PWR_FV2);
- if (rt5645->en_button_func &&
- snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
- queue_delayed_work(system_power_efficient_wq,
- &rt5645->jack_detect_work, msecs_to_jiffies(0));
+ if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+ snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
+ msleep(40);
+ if (rt5645->en_button_func)
+ queue_delayed_work(system_power_efficient_wq,
+ &rt5645->jack_detect_work,
+ msecs_to_jiffies(0));
+ }
break;
case SND_SOC_BIAS_OFF:
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 820d8fa62b5e..fb8ea05c0de1 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -3985,7 +3985,6 @@ static int rt5659_i2c_probe(struct i2c_client *i2c,
if (rt5659 == NULL)
return -ENOMEM;
- rt5659->i2c = i2c;
i2c_set_clientdata(i2c, rt5659);
if (pdata)
@@ -4157,24 +4156,17 @@ static int rt5659_i2c_probe(struct i2c_client *i2c,
INIT_DELAYED_WORK(&rt5659->jack_detect_work, rt5659_jack_detect_work);
- if (rt5659->i2c->irq) {
- ret = request_threaded_irq(rt5659->i2c->irq, NULL, rt5659_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ if (i2c->irq) {
+ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+ rt5659_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5659", rt5659);
if (ret)
dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
}
- ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
+ return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
rt5659_dai, ARRAY_SIZE(rt5659_dai));
-
- if (ret) {
- if (rt5659->i2c->irq)
- free_irq(rt5659->i2c->irq, rt5659);
- }
-
- return 0;
}
static int rt5659_i2c_remove(struct i2c_client *i2c)
@@ -4191,24 +4183,29 @@ void rt5659_i2c_shutdown(struct i2c_client *client)
regmap_write(rt5659->regmap, RT5659_RESET, 0);
}
+#ifdef CONFIG_OF
static const struct of_device_id rt5659_of_match[] = {
{ .compatible = "realtek,rt5658", },
{ .compatible = "realtek,rt5659", },
- {},
+ { },
};
+MODULE_DEVICE_TABLE(of, rt5659_of_match);
+#endif
+#ifdef CONFIG_ACPI
static struct acpi_device_id rt5659_acpi_match[] = {
- { "10EC5658", 0},
- { "10EC5659", 0},
- { },
+ { "10EC5658", 0, },
+ { "10EC5659", 0, },
+ { },
};
MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match);
+#endif
struct i2c_driver rt5659_i2c_driver = {
.driver = {
.name = "rt5659",
.owner = THIS_MODULE,
- .of_match_table = rt5659_of_match,
+ .of_match_table = of_match_ptr(rt5659_of_match),
.acpi_match_table = ACPI_PTR(rt5659_acpi_match),
},
.probe = rt5659_i2c_probe,
diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h
index 8f07ee903eaa..d31c9e5bcec8 100644
--- a/sound/soc/codecs/rt5659.h
+++ b/sound/soc/codecs/rt5659.h
@@ -1792,7 +1792,6 @@ struct rt5659_priv {
struct snd_soc_codec *codec;
struct rt5659_platform_data pdata;
struct regmap *regmap;
- struct i2c_client *i2c;
struct gpio_desc *gpiod_ldo1_en;
struct gpio_desc *gpiod_reset;
struct snd_soc_jack *hs_jack;
diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c
index 21ca3a5e9f66..d374c18d4db7 100644
--- a/sound/soc/codecs/sigmadsp-i2c.c
+++ b/sound/soc/codecs/sigmadsp-i2c.c
@@ -31,7 +31,10 @@ static int sigmadsp_write_i2c(void *control_data,
kfree(buf);
- return ret;
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static int sigmadsp_read_i2c(void *control_data,
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 781398fb2841..f7a6ce7e5fb1 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -446,7 +446,7 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
- ucontrol->value.integer.value[0] = dac33->fifo_mode;
+ ucontrol->value.enumerated.item[0] = dac33->fifo_mode;
return 0;
}
@@ -458,17 +458,16 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- if (dac33->fifo_mode == ucontrol->value.integer.value[0])
+ if (dac33->fifo_mode == ucontrol->value.enumerated.item[0])
return 0;
/* Do not allow changes while stream is running*/
if (snd_soc_codec_is_active(codec))
return -EPERM;
- if (ucontrol->value.integer.value[0] < 0 ||
- ucontrol->value.integer.value[0] >= DAC33_FIFO_LAST_MODE)
+ if (ucontrol->value.enumerated.item[0] >= DAC33_FIFO_LAST_MODE)
ret = -EINVAL;
else
- dac33->fifo_mode = ucontrol->value.integer.value[0];
+ dac33->fifo_mode = ucontrol->value.enumerated.item[0];
return ret;
}
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 7693c1129bab..1b79778098d2 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -175,7 +175,7 @@ static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
- ucontrol->value.integer.value[0] = wl1273->mode;
+ ucontrol->value.enumerated.item[0] = wl1273->mode;
return 0;
}
@@ -193,18 +193,17 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
- if (wl1273->mode == ucontrol->value.integer.value[0])
+ if (wl1273->mode == ucontrol->value.enumerated.item[0])
return 0;
/* Do not allow changes while stream is running */
if (snd_soc_codec_is_active(codec))
return -EPERM;
- if (ucontrol->value.integer.value[0] < 0 ||
- ucontrol->value.integer.value[0] >= ARRAY_SIZE(wl1273_audio_route))
+ if (ucontrol->value.enumerated.item[0] >= ARRAY_SIZE(wl1273_audio_route))
return -EINVAL;
- wl1273->mode = ucontrol->value.integer.value[0];
+ wl1273->mode = ucontrol->value.enumerated.item[0];
return 1;
}
@@ -219,7 +218,7 @@ static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
dev_dbg(codec->dev, "%s: enter.\n", __func__);
- ucontrol->value.integer.value[0] = wl1273->core->audio_mode;
+ ucontrol->value.enumerated.item[0] = wl1273->core->audio_mode;
return 0;
}
@@ -233,7 +232,7 @@ static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
dev_dbg(codec->dev, "%s: enter.\n", __func__);
- val = ucontrol->value.integer.value[0];
+ val = ucontrol->value.enumerated.item[0];
if (wl1273->core->audio_mode == val)
return 0;
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 64637d1cf4e5..a8b3e3f701f9 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -619,7 +619,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
- unsigned int v;
+ unsigned int v = 0;
int ret;
switch (event) {
@@ -654,7 +654,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
break;
}
- return wm_adsp2_early_event(w, kcontrol, event);
+ return wm_adsp2_early_event(w, kcontrol, event, v);
}
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
@@ -1408,7 +1408,7 @@ ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
-WM_ADSP2_E("DSP1", 0, wm5102_adsp_power_ev),
+WM_ADSP2("DSP1", 0, wm5102_adsp_power_ev),
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
@@ -1599,6 +1599,9 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
{ "Slim2 Capture", NULL, "SYSCLK" },
{ "Slim3 Capture", NULL, "SYSCLK" },
+ { "Audio Trace DSP", NULL, "DSP1" },
+ { "Audio Trace DSP", NULL, "SYSCLK" },
+
{ "IN1L PGA", NULL, "IN1L" },
{ "IN1R PGA", NULL, "IN1R" },
@@ -1735,7 +1738,7 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
}
-#define WM5102_RATES SNDRV_PCM_RATE_8000_192000
+#define WM5102_RATES SNDRV_PCM_RATE_KNOT
#define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -1864,14 +1867,67 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
},
.ops = &arizona_simple_dai_ops,
},
+ {
+ .name = "wm5102-cpu-trace",
+ .capture = {
+ .stream_name = "Audio Trace CPU",
+ .channels_min = 1,
+ .channels_max = 6,
+ .rates = WM5102_RATES,
+ .formats = WM5102_FORMATS,
+ },
+ .compress_new = snd_soc_new_compress,
+ },
+ {
+ .name = "wm5102-dsp-trace",
+ .capture = {
+ .stream_name = "Audio Trace DSP",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = WM5102_RATES,
+ .formats = WM5102_FORMATS,
+ },
+ },
};
+static int wm5102_open(struct snd_compr_stream *stream)
+{
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct wm5102_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
+
+ return wm_adsp_compr_open(&priv->core.adsp[0], stream);
+}
+
+static irqreturn_t wm5102_adsp2_irq(int irq, void *data)
+{
+ struct wm5102_priv *priv = data;
+ struct arizona *arizona = priv->core.arizona;
+ int ret;
+
+ ret = wm_adsp_compr_handle_irq(&priv->core.adsp[0]);
+ if (ret == -ENODEV) {
+ dev_err(arizona->dev, "Spurious compressed data IRQ\n");
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
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);
+ struct arizona *arizona = priv->core.arizona;
int ret;
+ ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
+ "ADSP2 Compressed IRQ", wm5102_adsp2_irq,
+ priv);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
+ return ret;
+ }
+
ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec);
if (ret)
return ret;
@@ -1946,6 +2002,20 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5102 = {
.num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes),
};
+static struct snd_compr_ops wm5102_compr_ops = {
+ .open = wm5102_open,
+ .free = wm_adsp_compr_free,
+ .set_params = wm_adsp_compr_set_params,
+ .get_caps = wm_adsp_compr_get_caps,
+ .trigger = wm_adsp_compr_trigger,
+ .pointer = wm_adsp_compr_pointer,
+ .copy = wm_adsp_compr_copy,
+};
+
+static struct snd_soc_platform_driver wm5102_compr_platform = {
+ .compr_ops = &wm5102_compr_ops,
+};
+
static int wm5102_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -2005,12 +2075,25 @@ static int wm5102_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
- return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
+ ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102,
wm5102_dai, ARRAY_SIZE(wm5102_dai));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+ snd_soc_unregister_platform(&pdev->dev);
+ }
+
+ return ret;
}
static int wm5102_remove(struct platform_device *pdev)
{
+ snd_soc_unregister_platform(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 6088d30962a9..83ba70fe16e6 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -191,6 +191,25 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
return 0;
}
+static int wm5110_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;
+
+ 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 ret;
+ }
+
+ v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
+
+ return wm_adsp2_early_event(w, kcontrol, event, v);
+}
+
static const struct reg_sequence wm5110_no_dre_left_enable[] = {
{ 0x3024, 0xE410 },
{ 0x3025, 0x0056 },
@@ -1179,10 +1198,10 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
NULL, 0),
-WM_ADSP2("DSP1", 0),
-WM_ADSP2("DSP2", 1),
-WM_ADSP2("DSP3", 2),
-WM_ADSP2("DSP4", 3),
+WM_ADSP2("DSP1", 0, wm5110_adsp_power_ev),
+WM_ADSP2("DSP2", 1, wm5110_adsp_power_ev),
+WM_ADSP2("DSP3", 2, wm5110_adsp_power_ev),
+WM_ADSP2("DSP4", 3, wm5110_adsp_power_ev),
SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
@@ -1809,6 +1828,9 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "Voice Control DSP", NULL, "DSP3" },
{ "Voice Control DSP", NULL, "SYSCLK" },
+ { "Audio Trace DSP", NULL, "DSP1" },
+ { "Audio Trace DSP", NULL, "SYSCLK" },
+
{ "IN1L PGA", NULL, "IN1L" },
{ "IN1R PGA", NULL, "IN1R" },
@@ -2002,7 +2024,7 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
}
-#define WM5110_RATES SNDRV_PCM_RATE_8000_192000
+#define WM5110_RATES SNDRV_PCM_RATE_KNOT
#define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -2152,6 +2174,27 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
.formats = WM5110_FORMATS,
},
},
+ {
+ .name = "wm5110-cpu-trace",
+ .capture = {
+ .stream_name = "Audio Trace CPU",
+ .channels_min = 1,
+ .channels_max = 6,
+ .rates = WM5110_RATES,
+ .formats = WM5110_FORMATS,
+ },
+ .compress_new = snd_soc_new_compress,
+ },
+ {
+ .name = "wm5110-dsp-trace",
+ .capture = {
+ .stream_name = "Audio Trace DSP",
+ .channels_min = 1,
+ .channels_max = 6,
+ .rates = WM5110_RATES,
+ .formats = WM5110_FORMATS,
+ },
+ },
};
static int wm5110_open(struct snd_compr_stream *stream)
@@ -2163,6 +2206,8 @@ static int wm5110_open(struct snd_compr_stream *stream)
if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) {
n_adsp = 2;
+ } else if (strcmp(rtd->codec_dai->name, "wm5110-dsp-trace") == 0) {
+ n_adsp = 0;
} else {
dev_err(arizona->dev,
"No suitable compressed stream for DAI '%s'\n",
@@ -2175,12 +2220,21 @@ static int wm5110_open(struct snd_compr_stream *stream)
static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
{
- struct wm5110_priv *florida = data;
- int ret;
+ struct wm5110_priv *priv = data;
+ struct arizona *arizona = priv->core.arizona;
+ int serviced = 0;
+ int i, ret;
- ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]);
- if (ret == -ENODEV)
+ for (i = 0; i < WM5110_NUM_ADSP; ++i) {
+ ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]);
+ if (ret != -ENODEV)
+ serviced++;
+ }
+
+ if (!serviced) {
+ dev_err(arizona->dev, "Spurious compressed data IRQ\n");
return IRQ_NONE;
+ }
return IRQ_HANDLED;
}
@@ -2366,7 +2420,7 @@ static int wm5110_probe(struct platform_device *pdev)
ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
- goto error;
+ return ret;
}
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
@@ -2376,12 +2430,12 @@ static int wm5110_probe(struct platform_device *pdev)
snd_soc_unregister_platform(&pdev->dev);
}
-error:
return ret;
}
static int wm5110_remove(struct platform_device *pdev)
{
+ snd_soc_unregister_platform(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 61299ca372ff..6f1024f48b19 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -233,7 +233,7 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
- ucontrol->value.integer.value[0] = wm8753->dai_func;
+ ucontrol->value.enumerated.item[0] = wm8753->dai_func;
return 0;
}
@@ -244,7 +244,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
u16 ioctl;
- if (wm8753->dai_func == ucontrol->value.integer.value[0])
+ if (wm8753->dai_func == ucontrol->value.enumerated.item[0])
return 0;
if (snd_soc_codec_is_active(codec))
@@ -252,7 +252,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
ioctl = snd_soc_read(codec, WM8753_IOCTL);
- wm8753->dai_func = ucontrol->value.integer.value[0];
+ wm8753->dai_func = ucontrol->value.enumerated.item[0];
if (((ioctl >> 2) & 0x3) == wm8753->dai_func)
return 1;
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 8172e499e6ed..edd7a7709194 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -396,7 +396,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
if (value >= pdata->num_drc_cfgs)
return -EINVAL;
@@ -467,7 +467,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
struct wm8904_pdata *pdata = wm8904->pdata;
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
if (value >= pdata->num_retune_mobile_cfgs)
return -EINVAL;
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index c799cca5abeb..6b864c0fc2b6 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -459,7 +459,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
int reg;
/* Don't allow on the fly reconfiguration */
@@ -549,7 +549,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
int reg;
/* Don't allow on the fly reconfiguration */
@@ -582,7 +582,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
int reg;
/* Don't allow on the fly reconfiguration */
@@ -749,7 +749,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
int reg;
/* Don't allow on the fly reconfiguration */
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index ff237726775a..d7f444f87460 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -240,13 +240,13 @@ SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
7, 1, 1),
-SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
WM8960_INBMIX1, 4, 7, 0, lineinboost_tlv),
-SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
WM8960_INBMIX1, 1, 7, 0, lineinboost_tlv),
-SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
WM8960_INBMIX2, 4, 7, 0, lineinboost_tlv),
-SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
WM8960_INBMIX2, 1, 7, 0, lineinboost_tlv),
SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT1 Volume",
WM8960_RINPATH, 4, 3, 0, micboost_tlv),
@@ -643,29 +643,31 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec)
return -EINVAL;
}
- /* check if the sysclk frequency is available. */
- for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
- if (sysclk_divs[i] == -1)
- continue;
- sysclk = freq_out / sysclk_divs[i];
- for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
- if (sysclk == dac_divs[j] * lrclk) {
+ if (wm8960->clk_id != WM8960_SYSCLK_PLL) {
+ /* check if the sysclk frequency is available. */
+ for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
+ if (sysclk_divs[i] == -1)
+ continue;
+ sysclk = freq_out / sysclk_divs[i];
+ for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
+ if (sysclk != dac_divs[j] * lrclk)
+ continue;
for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
if (sysclk == bclk * bclk_divs[k] / 10)
break;
if (k != ARRAY_SIZE(bclk_divs))
break;
}
+ if (j != ARRAY_SIZE(dac_divs))
+ break;
}
- if (j != ARRAY_SIZE(dac_divs))
- break;
- }
- if (i != ARRAY_SIZE(sysclk_divs)) {
- goto configure_clock;
- } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
- dev_err(codec->dev, "failed to configure clock\n");
- return -EINVAL;
+ if (i != ARRAY_SIZE(sysclk_divs)) {
+ goto configure_clock;
+ } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
+ dev_err(codec->dev, "failed to configure clock\n");
+ return -EINVAL;
+ }
}
/* get a available pll out frequency and set pll */
for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 7350ff654bbf..0c002a5712cb 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -497,9 +497,9 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
reg = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF);
if (reg & WM8983_EQ3DMODE)
- ucontrol->value.integer.value[0] = 1;
+ ucontrol->value.enumerated.item[0] = 1;
else
- ucontrol->value.integer.value[0] = 0;
+ ucontrol->value.enumerated.item[0] = 0;
return 0;
}
@@ -511,18 +511,18 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
unsigned int regpwr2, regpwr3;
unsigned int reg_eq;
- if (ucontrol->value.integer.value[0] != 0
- && ucontrol->value.integer.value[0] != 1)
+ if (ucontrol->value.enumerated.item[0] != 0
+ && ucontrol->value.enumerated.item[0] != 1)
return -EINVAL;
reg_eq = snd_soc_read(codec, WM8983_EQ1_LOW_SHELF);
switch ((reg_eq & WM8983_EQ3DMODE) >> WM8983_EQ3DMODE_SHIFT) {
case 0:
- if (!ucontrol->value.integer.value[0])
+ if (!ucontrol->value.enumerated.item[0])
return 0;
break;
case 1:
- if (ucontrol->value.integer.value[0])
+ if (ucontrol->value.enumerated.item[0])
return 0;
break;
}
@@ -537,7 +537,7 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
/* set the desired eqmode */
snd_soc_update_bits(codec, WM8983_EQ1_LOW_SHELF,
WM8983_EQ3DMODE_MASK,
- ucontrol->value.integer.value[0]
+ ucontrol->value.enumerated.item[0]
<< WM8983_EQ3DMODE_SHIFT);
/* restore DAC/ADC configuration */
snd_soc_write(codec, WM8983_POWER_MANAGEMENT_2, regpwr2);
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 9918152a03c7..6ac76fe116b0 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -531,9 +531,9 @@ static int eqmode_get(struct snd_kcontrol *kcontrol,
reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
if (reg & WM8985_EQ3DMODE)
- ucontrol->value.integer.value[0] = 1;
+ ucontrol->value.enumerated.item[0] = 1;
else
- ucontrol->value.integer.value[0] = 0;
+ ucontrol->value.enumerated.item[0] = 0;
return 0;
}
@@ -545,18 +545,18 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
unsigned int regpwr2, regpwr3;
unsigned int reg_eq;
- if (ucontrol->value.integer.value[0] != 0
- && ucontrol->value.integer.value[0] != 1)
+ if (ucontrol->value.enumerated.item[0] != 0
+ && ucontrol->value.enumerated.item[0] != 1)
return -EINVAL;
reg_eq = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
switch ((reg_eq & WM8985_EQ3DMODE) >> WM8985_EQ3DMODE_SHIFT) {
case 0:
- if (!ucontrol->value.integer.value[0])
+ if (!ucontrol->value.enumerated.item[0])
return 0;
break;
case 1:
- if (ucontrol->value.integer.value[0])
+ if (ucontrol->value.enumerated.item[0])
return 0;
break;
}
@@ -573,7 +573,7 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
/* set the desired eqmode */
snd_soc_update_bits(codec, WM8985_EQ1_LOW_SHELF,
WM8985_EQ3DMODE_MASK,
- ucontrol->value.integer.value[0]
+ ucontrol->value.enumerated.item[0]
<< WM8985_EQ3DMODE_SHIFT);
/* restore DAC/ADC configuration */
snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, regpwr2);
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 2ccbb322df77..a18aecb49935 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -362,7 +362,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int drc = wm8994_get_drc(kcontrol->id.name);
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
if (drc < 0)
return drc;
@@ -469,7 +469,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct wm8994 *control = wm8994->wm8994;
struct wm8994_pdata *pdata = &control->pdata;
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
if (block < 0)
return block;
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 8d7d6c01a2f7..f99b34f7647b 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -416,7 +416,7 @@ static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
struct wm8996_pdata *pdata = &wm8996->pdata;
int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
if (block < 0)
return block;
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index b4dba3a02aba..52d766efe14f 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -943,7 +943,7 @@ static int wm8997_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
}
-#define WM8997_RATES SNDRV_PCM_RATE_8000_192000
+#define WM8997_RATES SNDRV_PCM_RATE_KNOT
#define WM8997_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c
index 7719bc509e50..012396074a8a 100644
--- a/sound/soc/codecs/wm8998.c
+++ b/sound/soc/codecs/wm8998.c
@@ -1170,7 +1170,7 @@ static const struct snd_soc_dapm_route wm8998_dapm_routes[] = {
{ "DRC1 Signal Activity", NULL, "DRC1R" },
};
-#define WM8998_RATES SNDRV_PCM_RATE_8000_192000
+#define WM8998_RATES SNDRV_PCM_RATE_KNOT
#define WM8998_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index ccb3b15139ad..363b3b667616 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -344,9 +344,9 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol,
reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
if (reg & WM9081_SPK_MODE)
- ucontrol->value.integer.value[0] = 1;
+ ucontrol->value.enumerated.item[0] = 1;
else
- ucontrol->value.integer.value[0] = 0;
+ ucontrol->value.enumerated.item[0] = 0;
return 0;
}
@@ -365,7 +365,7 @@ static int speaker_mode_put(struct snd_kcontrol *kcontrol,
unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
/* Are we changing anything? */
- if (ucontrol->value.integer.value[0] ==
+ if (ucontrol->value.enumerated.item[0] ==
((reg2 & WM9081_SPK_MODE) != 0))
return 0;
@@ -373,7 +373,7 @@ static int speaker_mode_put(struct snd_kcontrol *kcontrol,
if (reg_pwr & WM9081_SPK_ENA)
return -EINVAL;
- if (ucontrol->value.integer.value[0]) {
+ if (ucontrol->value.enumerated.item[0]) {
/* Class AB */
reg2 &= ~(WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL);
reg2 |= WM9081_SPK_MODE;
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 79e143625ac3..9849643ef809 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -1212,7 +1212,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
if (IS_ERR(wm9713->ac97))
return PTR_ERR(wm9713->ac97);
- regmap = devm_regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
+ regmap = regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config);
if (IS_ERR(regmap)) {
snd_soc_free_ac97_codec(wm9713->ac97);
return PTR_ERR(regmap);
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 33806d487b8a..d3b1cb15e7f0 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -32,9 +32,6 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <linux/mfd/arizona/registers.h>
-
-#include "arizona.h"
#include "wm_adsp.h"
#define adsp_crit(_dsp, fmt, ...) \
@@ -295,6 +292,8 @@ struct wm_adsp_compr {
u32 *raw_buf;
unsigned int copied_total;
+
+ unsigned int sample_rate;
};
#define WM_ADSP_DATA_WORD_SIZE 3
@@ -328,7 +327,7 @@ struct wm_adsp_buffer_region_def {
unsigned int size_offset;
};
-static struct wm_adsp_buffer_region_def ez2control_regions[] = {
+static const struct wm_adsp_buffer_region_def default_regions[] = {
{
.mem_type = WMFW_ADSP2_XM,
.base_offset = HOST_BUFFER_FIELD(X_buf_base),
@@ -350,10 +349,10 @@ struct wm_adsp_fw_caps {
u32 id;
struct snd_codec_desc desc;
int num_regions;
- struct wm_adsp_buffer_region_def *region_defs;
+ const struct wm_adsp_buffer_region_def *region_defs;
};
-static const struct wm_adsp_fw_caps ez2control_caps[] = {
+static const struct wm_adsp_fw_caps ctrl_caps[] = {
{
.id = SND_AUDIOCODEC_BESPOKE,
.desc = {
@@ -362,8 +361,26 @@ static const struct wm_adsp_fw_caps ez2control_caps[] = {
.num_sample_rates = 1,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
- .num_regions = ARRAY_SIZE(ez2control_regions),
- .region_defs = ez2control_regions,
+ .num_regions = ARRAY_SIZE(default_regions),
+ .region_defs = default_regions,
+ },
+};
+
+static const struct wm_adsp_fw_caps trace_caps[] = {
+ {
+ .id = SND_AUDIOCODEC_BESPOKE,
+ .desc = {
+ .max_ch = 8,
+ .sample_rates = {
+ 4000, 8000, 11025, 12000, 16000, 22050,
+ 24000, 32000, 44100, 48000, 64000, 88200,
+ 96000, 176400, 192000
+ },
+ .num_sample_rates = 15,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .num_regions = ARRAY_SIZE(default_regions),
+ .region_defs = default_regions,
},
};
@@ -382,11 +399,16 @@ static const struct {
[WM_ADSP_FW_CTRL] = {
.file = "ctrl",
.compr_direction = SND_COMPRESS_CAPTURE,
- .num_caps = ARRAY_SIZE(ez2control_caps),
- .caps = ez2control_caps,
+ .num_caps = ARRAY_SIZE(ctrl_caps),
+ .caps = ctrl_caps,
},
[WM_ADSP_FW_ASR] = { .file = "asr" },
- [WM_ADSP_FW_TRACE] = { .file = "trace" },
+ [WM_ADSP_FW_TRACE] = {
+ .file = "trace",
+ .compr_direction = SND_COMPRESS_CAPTURE,
+ .num_caps = ARRAY_SIZE(trace_caps),
+ .caps = trace_caps,
+ },
[WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
[WM_ADSP_FW_MISC] = { .file = "misc" },
};
@@ -586,7 +608,7 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
- ucontrol->value.integer.value[0] = dsp[e->shift_l].fw;
+ ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw;
return 0;
}
@@ -599,10 +621,10 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw)
+ if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
return 0;
- if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
+ if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
return -EINVAL;
mutex_lock(&dsp[e->shift_l].pwr_lock);
@@ -610,7 +632,7 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
if (dsp[e->shift_l].running || dsp[e->shift_l].compr)
ret = -EBUSY;
else
- dsp[e->shift_l].fw = ucontrol->value.integer.value[0];
+ dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
mutex_unlock(&dsp[e->shift_l].pwr_lock);
@@ -719,19 +741,19 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
reg = ctl->alg_region.base + ctl->offset;
reg = wm_adsp_region_to_reg(mem, reg);
- scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
+ scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA);
if (!scratch)
return -ENOMEM;
ret = regmap_raw_write(dsp->regmap, reg, scratch,
- ctl->len);
+ len);
if (ret) {
adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n",
- ctl->len, reg, ret);
+ len, reg, ret);
kfree(scratch);
return ret;
}
- adsp_dbg(dsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
+ adsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg);
kfree(scratch);
@@ -778,20 +800,20 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
reg = ctl->alg_region.base + ctl->offset;
reg = wm_adsp_region_to_reg(mem, reg);
- scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
+ scratch = kmalloc(len, GFP_KERNEL | GFP_DMA);
if (!scratch)
return -ENOMEM;
- ret = regmap_raw_read(dsp->regmap, reg, scratch, ctl->len);
+ ret = regmap_raw_read(dsp->regmap, reg, scratch, len);
if (ret) {
adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n",
- ctl->len, reg, ret);
+ len, reg, ret);
kfree(scratch);
return ret;
}
- adsp_dbg(dsp, "Read %zu bytes from %x\n", ctl->len, reg);
+ adsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg);
- memcpy(buf, scratch, ctl->len);
+ memcpy(buf, scratch, len);
kfree(scratch);
return 0;
@@ -855,17 +877,18 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+ } else {
+ kcontrol->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+ kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
}
- ret = snd_soc_add_card_controls(dsp->card,
- kcontrol, 1);
+ 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(dsp->card,
- ctl->name);
+ ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, ctl->name);
return 0;
@@ -885,9 +908,7 @@ static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
continue;
- ret = wm_coeff_read_control(ctl,
- ctl->cache,
- ctl->len);
+ ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len);
if (ret < 0)
return ret;
}
@@ -904,9 +925,7 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp)
if (!ctl->enabled)
continue;
if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
- ret = wm_coeff_write_control(ctl,
- ctl->cache,
- ctl->len);
+ ret = wm_coeff_write_control(ctl, ctl->cache, ctl->len);
if (ret < 0)
return ret;
}
@@ -1502,8 +1521,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
if (ret != 0) {
- adsp_err(dsp, "Failed to read algorithm list: %d\n",
- ret);
+ adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
kfree(alg);
return ERR_PTR(ret);
}
@@ -2002,8 +2020,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
goto err_mutex;
}
- val = (val & dsp->sysclk_mask)
- >> dsp->sysclk_shift;
+ val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift;
ret = regmap_update_bits(dsp->regmap,
dsp->base + ADSP1_CONTROL_31,
@@ -2096,8 +2113,7 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
/* Wait for the RAM to start, should be near instantaneous */
for (count = 0; count < 10; ++count) {
- ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
- &val);
+ ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
if (ret != 0)
return ret;
@@ -2123,30 +2139,9 @@ static void wm_adsp2_boot_work(struct work_struct *work)
struct wm_adsp,
boot_work);
int ret;
- unsigned int val;
mutex_lock(&dsp->pwr_lock);
- /*
- * For simplicity set the DSP clock rate to be the
- * SYSCLK rate rather than making it configurable.
- */
- ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
- if (ret != 0) {
- adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
- goto err_mutex;
- }
- val = (val & ARIZONA_SYSCLK_FREQ_MASK)
- >> ARIZONA_SYSCLK_FREQ_SHIFT;
-
- ret = regmap_update_bits_async(dsp->regmap,
- dsp->base + ADSP2_CLOCKING,
- ADSP2_CLK_SEL_MASK, val);
- if (ret != 0) {
- adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
- goto err_mutex;
- }
-
ret = wm_adsp2_ena(dsp);
if (ret != 0)
goto err_mutex;
@@ -2186,8 +2181,21 @@ err_mutex:
mutex_unlock(&dsp->pwr_lock);
}
+static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
+{
+ int ret;
+
+ ret = regmap_update_bits_async(dsp->regmap,
+ dsp->base + ADSP2_CLOCKING,
+ ADSP2_CLK_SEL_MASK,
+ freq << ADSP2_CLK_SEL_SHIFT);
+ if (ret != 0)
+ adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
+}
+
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event,
+ unsigned int freq)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
@@ -2197,6 +2205,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ wm_adsp2_set_dspclk(dsp, freq);
queue_work(system_unbound_wq, &dsp->boot_work);
break;
default:
@@ -2471,6 +2480,8 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream,
if (!compr->raw_buf)
return -ENOMEM;
+ compr->sample_rate = params->codec.sample_rate;
+
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params);
@@ -2810,7 +2821,6 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
mutex_lock(&dsp->pwr_lock);
if (!buf) {
- adsp_err(dsp, "Spurious buffer IRQ\n");
ret = -ENODEV;
goto out;
}
@@ -2841,7 +2851,7 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
goto out;
}
- if (compr->stream)
+ if (compr && compr->stream)
snd_compr_fragment_elapsed(compr->stream);
out:
@@ -2911,6 +2921,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
tstamp->copied_total = compr->copied_total;
tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE;
+ tstamp->sampling_rate = compr->sample_rate;
out:
mutex_unlock(&dsp->pwr_lock);
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 1a928ec54741..b61cb57e600f 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -80,7 +80,7 @@ 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_E(wname, num, event_fn) \
+#define WM_ADSP2(wname, num, event_fn) \
{ .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \
.reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \
@@ -88,9 +88,6 @@ struct wm_adsp {
.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_adsp_fw_controls[];
int wm_adsp1_init(struct wm_adsp *dsp);
@@ -100,7 +97,8 @@ int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec);
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,
- struct snd_kcontrol *kcontrol, int event);
+ struct snd_kcontrol *kcontrol, int event,
+ unsigned int freq);
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index ce664c239be3..bff258d7bcea 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -645,6 +645,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
+ dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
+ dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
if (pdata) {
dev->capability = pdata->cap;
clk_id = NULL;
@@ -652,9 +654,6 @@ static int dw_i2s_probe(struct platform_device *pdev)
if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) {
dev->i2s_reg_comp1 = pdata->i2s_reg_comp1;
dev->i2s_reg_comp2 = pdata->i2s_reg_comp2;
- } else {
- dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
- dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
}
ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
} else {
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
index a407e833c612..fb896b2c9ba3 100644
--- a/sound/soc/fsl/imx-spdif.c
+++ b/sound/soc/fsl/imx-spdif.c
@@ -72,8 +72,6 @@ static int imx_spdif_audio_probe(struct platform_device *pdev)
goto end;
}
- platform_set_drvdata(pdev, data);
-
end:
of_node_put(spdif_np);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 1ded8811598e..2389ab47e25f 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -99,7 +99,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
if (ret && ret != -ENOTSUPP)
goto err;
}
-
+ return 0;
err:
return ret;
}
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 803f95e40679..b3e6c2300457 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -30,11 +30,15 @@ config SND_SST_IPC_ACPI
config SND_SOC_INTEL_SST
tristate
select SND_SOC_INTEL_SST_ACPI if ACPI
+ select SND_SOC_INTEL_SST_MATCH if ACPI
depends on (X86 || COMPILE_TEST)
config SND_SOC_INTEL_SST_ACPI
tristate
+config SND_SOC_INTEL_SST_MATCH
+ tristate
+
config SND_SOC_INTEL_HASWELL
tristate
@@ -57,7 +61,7 @@ config SND_SOC_INTEL_HASWELL_MACH
config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
depends on X86_INTEL_LPSS && I2C
- depends on DW_DMAC_CORE=y && (SND_SOC_INTEL_BYTCR_RT5640_MACH = n)
+ depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n)
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640
@@ -69,7 +73,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
config SND_SOC_INTEL_BYT_MAX98090_MACH
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
depends on X86_INTEL_LPSS && I2C
- depends on DW_DMAC_CORE=y
+ depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n)
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090
@@ -97,6 +101,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
select SND_SOC_RT5640
select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI
+ select SND_SOC_INTEL_SST_MATCH if ACPI
help
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
platforms with RT5640 audio codec.
@@ -109,6 +114,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
select SND_SOC_RT5651
select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI
+ select SND_SOC_INTEL_SST_MATCH if ACPI
help
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
platforms with RT5651 audio codec.
@@ -121,6 +127,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
select SND_SOC_RT5670
select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI
+ select SND_SOC_INTEL_SST_MATCH if ACPI
help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with RT5672 audio codec.
@@ -133,6 +140,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
select SND_SOC_RT5645
select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI
+ select SND_SOC_INTEL_SST_MATCH if ACPI
help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with RT5645/5650 audio codec.
@@ -145,6 +153,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
select SND_SOC_TS3A227E
select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI
+ select SND_SOC_INTEL_SST_MATCH if ACPI
help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
@@ -154,6 +163,7 @@ config SND_SOC_INTEL_SKYLAKE
tristate
select SND_HDA_EXT_CORE
select SND_SOC_TOPOLOGY
+ select SND_HDA_I915
select SND_SOC_INTEL_SST
config SND_SOC_INTEL_SKL_RT286_MACH
@@ -163,6 +173,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT286
select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
help
This adds support for ASoC machine driver for Skylake platforms
with RT286 I2S audio codec.
@@ -177,6 +188,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
select SND_SOC_NAU8825
select SND_SOC_SSM4567
select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + SSM4567.
@@ -191,6 +203,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
select SND_SOC_NAU8825
select SND_SOC_MAX98357A
select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + MAX98357A.
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index 55c33dc76ce4..52ed434cbca6 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -528,6 +528,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
.ops = &sst_compr_dai_ops,
.playback = {
.stream_name = "Compress Playback",
+ .channels_min = 1,
},
},
/* BE CPU Dais */
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c
index 4fce03fc1870..3bc4b63b2f9d 100644
--- a/sound/soc/intel/atom/sst/sst_acpi.c
+++ b/sound/soc/intel/atom/sst/sst_acpi.c
@@ -342,6 +342,10 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
&chv_platform_data },
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data },
+ /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
+ {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL,
+ &chv_platform_data },
+
{},
};
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
index 3dc7358828b3..8afa6fe7b0b0 100644
--- a/sound/soc/intel/atom/sst/sst_ipc.c
+++ b/sound/soc/intel/atom/sst/sst_ipc.c
@@ -318,7 +318,6 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
union ipc_header_high msg_high;
u32 msg_low;
struct ipc_dsp_hdr *dsp_hdr;
- unsigned int cmd_id;
msg_high = msg->mrfld_header.p.header_high;
msg_low = msg->mrfld_header.p.header_low_payload;
@@ -357,7 +356,6 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
return;
/* Copy command id so that we can use to put sst to reset */
dsp_hdr = (struct ipc_dsp_hdr *)data;
- cmd_id = dsp_hdr->cmd_id;
dev_dbg(sst_drv_ctx->dev, "cmd_id %d\n", dsp_hdr->cmd_id);
if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
msg_high.part.drv_id,
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 9a1752df45a9..032a2e753f0b 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -32,6 +32,18 @@
#include "../atom/sst-atom-controls.h"
#include "../common/sst-acpi.h"
+enum {
+ BYT_RT5640_DMIC1_MAP,
+ BYT_RT5640_DMIC2_MAP,
+ BYT_RT5640_IN1_MAP,
+};
+
+#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
+#define BYT_RT5640_DMIC_EN BIT(16)
+
+static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
+ BYT_RT5640_DMIC_EN;
+
static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -70,18 +82,6 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
{"IN1P", NULL, "Internal Mic"},
};
-enum {
- BYT_RT5640_DMIC1_MAP,
- BYT_RT5640_DMIC2_MAP,
- BYT_RT5640_IN1_MAP,
-};
-
-#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
-#define BYT_RT5640_DMIC_EN BIT(16)
-
-static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
- BYT_RT5640_DMIC_EN;
-
static const struct snd_kcontrol_new byt_rt5640_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -174,7 +174,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
return ret;
}
- dmi_check_system(byt_rt5640_quirk_table);
switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
case BYT_RT5640_IN1_MAP:
custom_map = byt_rt5640_intmic_in1_map;
@@ -341,15 +340,34 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
{
int ret_val = 0;
struct sst_acpi_mach *mach;
+ const char *i2c_name = NULL;
+ int i;
+ int dai_index;
/* register the soc card */
byt_rt5640_card.dev = &pdev->dev;
mach = byt_rt5640_card.dev->platform_data;
+ /* fix index of codec dai */
+ dai_index = MERR_DPCM_COMPR + 1;
+ for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) {
+ if (!strcmp(byt_rt5640_dais[i].codec_name, "i2c-10EC5640:00")) {
+ dai_index = i;
+ break;
+ }
+ }
+
/* fixup codec name based on HID */
- snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
- "%s%s%s", "i2c-", mach->id, ":00");
- byt_rt5640_dais[MERR_DPCM_COMPR+1].codec_name = byt_rt5640_codec_name;
+ i2c_name = sst_acpi_find_name_from_hid(mach->id);
+ if (i2c_name != NULL) {
+ snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
+ "%s%s", "i2c-", i2c_name);
+
+ byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name;
+ }
+
+ /* check quirks before creating card */
+ dmi_check_system(byt_rt5640_quirk_table);
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
index 90588d6e64fc..e609f089593a 100644
--- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c
+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c
@@ -287,33 +287,20 @@ static struct snd_soc_card snd_soc_card_cht = {
.num_controls = ARRAY_SIZE(cht_mc_controls),
};
-static acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level,
- void *context, void **ret)
-{
- *(bool *)context = true;
- return AE_OK;
-}
-
static int snd_cht_mc_probe(struct platform_device *pdev)
{
int ret_val = 0;
- bool found = false;
struct cht_mc_private *drv;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
if (!drv)
return -ENOMEM;
- if (ACPI_SUCCESS(acpi_get_devices(
- "104C227E",
- snd_acpi_codec_match,
- &found, NULL)) && found) {
- drv->ts3a227e_present = true;
- } else {
+ drv->ts3a227e_present = acpi_dev_present("104C227E");
+ if (!drv->ts3a227e_present) {
/* no need probe TI jack detection chip */
snd_soc_card_cht.aux_dev = NULL;
snd_soc_card_cht.num_aux_devs = 0;
- drv->ts3a227e_present = false;
}
/* register the soc card */
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 2d3afddb0a2e..2a6f80843bc9 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -147,6 +147,17 @@ static const struct snd_kcontrol_new cht_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Ext Spk"),
};
+static struct snd_soc_jack_pin cht_bsw_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -202,9 +213,9 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
else
jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE;
- ret = snd_soc_card_jack_new(runtime->card, "Headset Jack",
+ ret = snd_soc_card_jack_new(runtime->card, "Headset",
jack_type, &ctx->jack,
- NULL, 0);
+ cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins));
if (ret) {
dev_err(runtime->dev, "Headset jack creation failed %d\n", ret);
return ret;
@@ -333,20 +344,12 @@ static struct cht_acpi_card snd_soc_cards[] = {
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650},
};
-static acpi_status snd_acpi_codec_match(acpi_handle handle, u32 level,
- void *context, void **ret)
-{
- *(bool *)context = true;
- return AE_OK;
-}
-
static int snd_cht_mc_probe(struct platform_device *pdev)
{
int ret_val = 0;
int i;
struct cht_mc_private *drv;
struct snd_soc_card *card = snd_soc_cards[0].soc_card;
- bool found = false;
char codec_name[16];
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
@@ -354,10 +357,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) {
- if (ACPI_SUCCESS(acpi_get_devices(
- snd_soc_cards[i].codec_id,
- snd_acpi_codec_match,
- &found, NULL)) && found) {
+ if (acpi_dev_present(snd_soc_cards[i].codec_id)) {
dev_dbg(&pdev->dev,
"found codec %s\n", snd_soc_cards[i].codec_id);
card = snd_soc_cards[i].soc_card;
@@ -367,8 +367,12 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
}
card->dev = &pdev->dev;
sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
+
/* set correct codec name */
- strcpy((char *)card->dai_link[2].codec_name, codec_name);
+ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)
+ if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00"))
+ card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL);
+
snd_soc_card_set_drvdata(card, drv);
ret_val = devm_snd_soc_register_card(&pdev->dev, card);
if (ret_val) {
diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c
index 49c09a0add79..34f46c72a0e2 100644
--- a/sound/soc/intel/boards/mfld_machine.c
+++ b/sound/soc/intel/boards/mfld_machine.c
@@ -94,7 +94,7 @@ static const struct soc_enum lo_enum =
static int headset_get_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = hs_switch;
+ ucontrol->value.enumerated.item[0] = hs_switch;
return 0;
}
@@ -104,12 +104,12 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol,
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &card->dapm;
- if (ucontrol->value.integer.value[0] == hs_switch)
+ if (ucontrol->value.enumerated.item[0] == hs_switch)
return 0;
snd_soc_dapm_mutex_lock(dapm);
- if (ucontrol->value.integer.value[0]) {
+ if (ucontrol->value.enumerated.item[0]) {
pr_debug("hs_set HS path\n");
snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
@@ -123,7 +123,7 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol,
snd_soc_dapm_mutex_unlock(dapm);
- hs_switch = ucontrol->value.integer.value[0];
+ hs_switch = ucontrol->value.enumerated.item[0];
return 0;
}
@@ -148,7 +148,7 @@ static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
static int lo_get_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = lo_dac;
+ ucontrol->value.enumerated.item[0] = lo_dac;
return 0;
}
@@ -158,7 +158,7 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol,
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_context *dapm = &card->dapm;
- if (ucontrol->value.integer.value[0] == lo_dac)
+ if (ucontrol->value.enumerated.item[0] == lo_dac)
return 0;
snd_soc_dapm_mutex_lock(dapm);
@@ -168,7 +168,7 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol,
*/
lo_enable_out_pins(dapm);
- switch (ucontrol->value.integer.value[0]) {
+ switch (ucontrol->value.enumerated.item[0]) {
case 0:
pr_debug("set vibra path\n");
snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
@@ -202,7 +202,7 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol,
snd_soc_dapm_mutex_unlock(dapm);
- lo_dac = ucontrol->value.integer.value[0];
+ lo_dac = ucontrol->value.enumerated.item[0];
return 0;
}
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index ab7da9c304b2..72176b79a18d 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -22,6 +22,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "../../codecs/nau8825.h"
+#include "../../codecs/hdac_hdmi.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_MAXIM_CODEC_DAI "HiFi"
@@ -29,6 +30,16 @@
static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card;
+enum {
+ SKL_DPCM_AUDIO_PB = 0,
+ SKL_DPCM_AUDIO_CP,
+ SKL_DPCM_AUDIO_REF_CP,
+ SKL_DPCM_AUDIO_DMIC_CP,
+ SKL_DPCM_AUDIO_HDMI1_PB,
+ SKL_DPCM_AUDIO_HDMI2_PB,
+ SKL_DPCM_AUDIO_HDMI3_PB,
+};
+
static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
@@ -87,7 +98,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Spk", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SINK("WoV Sink"),
SND_SOC_DAPM_SPK("DP", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
@@ -107,7 +117,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{ "MIC", NULL, "Headset Mic" },
{ "DMic", NULL, "SoC DMIC" },
- {"WoV Sink", NULL, "hwd_in sink"},
{"HDMI", NULL, "hif5 Output"},
{"DP", NULL, "hif6 Output"},
@@ -124,8 +133,14 @@ static const struct snd_soc_dapm_route skylake_map[] = {
/* DMIC */
{ "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "DMIC AIF" },
- { "hifi1", NULL, "iDisp Tx"},
- { "iDisp Tx", NULL, "iDisp_out"},
+
+ { "hifi3", NULL, "iDisp3 Tx"},
+ { "iDisp3 Tx", NULL, "iDisp3_out"},
+ { "hifi2", NULL, "iDisp2 Tx"},
+ { "iDisp2 Tx", NULL, "iDisp2_out"},
+ { "hifi1", NULL, "iDisp1 Tx"},
+ { "iDisp1 Tx", NULL, "iDisp1_out"},
+
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
};
@@ -171,11 +186,31 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
nau8825_enable_jack_detect(codec, &skylake_headset);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
- snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
return ret;
}
+static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *dai = rtd->codec_dai;
+
+ return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB);
+}
+
+static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *dai = rtd->codec_dai;
+
+ return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB);
+}
+
+static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *dai = rtd->codec_dai;
+
+ return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB);
+}
+
static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dapm_context *dapm;
@@ -318,7 +353,7 @@ static struct snd_soc_ops skylaye_refcap_ops = {
/* skylake digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link skylake_dais[] = {
/* Front End DAI links */
- {
+ [SKL_DPCM_AUDIO_PB] = {
.name = "Skl Audio Port",
.stream_name = "Audio",
.cpu_dai_name = "System Pin",
@@ -333,7 +368,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_playback = 1,
.ops = &skylake_nau8825_fe_ops,
},
- {
+ [SKL_DPCM_AUDIO_CP] = {
.name = "Skl Audio Capture Port",
.stream_name = "Audio Record",
.cpu_dai_name = "System Pin",
@@ -347,7 +382,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1,
.ops = &skylake_nau8825_fe_ops,
},
- {
+ [SKL_DPCM_AUDIO_REF_CP] = {
.name = "Skl Audio Reference cap",
.stream_name = "Wake on Voice",
.cpu_dai_name = "Reference Pin",
@@ -361,7 +396,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dynamic = 1,
.ops = &skylaye_refcap_ops,
},
- {
+ [SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap",
.stream_name = "dmiccap",
.cpu_dai_name = "DMIC Pin",
@@ -374,15 +409,45 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dynamic = 1,
.ops = &skylake_dmic_ops,
},
- {
- .name = "Skl HDMI Port",
- .stream_name = "Hdmi",
- .cpu_dai_name = "HDMI Pin",
+ [SKL_DPCM_AUDIO_HDMI1_PB] = {
+ .name = "Skl HDMI Port1",
+ .stream_name = "Hdmi1",
+ .cpu_dai_name = "HDMI1 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [SKL_DPCM_AUDIO_HDMI2_PB] = {
+ .name = "Skl HDMI Port2",
+ .stream_name = "Hdmi2",
+ .cpu_dai_name = "HDMI2 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [SKL_DPCM_AUDIO_HDMI3_PB] = {
+ .name = "Skl HDMI Port3",
+ .stream_name = "Hdmi3",
+ .cpu_dai_name = "HDMI3 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .init = NULL,
.nonatomic = 1,
.dynamic = 1,
},
@@ -407,7 +472,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
{
/* SSP1 - Codec */
.name = "SSP1-Codec",
- .be_id = 0,
+ .be_id = 1,
.cpu_dai_name = "SSP1 Pin",
.platform_name = "0000:00:1f.3",
.no_pcm = 1,
@@ -424,7 +489,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
},
{
.name = "dmic01",
- .be_id = 1,
+ .be_id = 2,
.cpu_dai_name = "DMIC01 Pin",
.codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi",
@@ -435,13 +500,36 @@ static struct snd_soc_dai_link skylake_dais[] = {
.no_pcm = 1,
},
{
- .name = "iDisp",
+ .name = "iDisp1",
.be_id = 3,
- .cpu_dai_name = "iDisp Pin",
+ .cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
+ .init = skylake_hdmi1_init,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp2",
+ .be_id = 4,
+ .cpu_dai_name = "iDisp2 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi2",
+ .platform_name = "0000:00:1f.3",
+ .init = skylake_hdmi2_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp3",
+ .be_id = 5,
+ .cpu_dai_name = "iDisp3 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi3",
+ .platform_name = "0000:00:1f.3",
+ .init = skylake_hdmi3_init,
+ .dpcm_playback = 1,
.no_pcm = 1,
},
};
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index c071812f31e5..5f1ca99ae9b0 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -26,6 +26,7 @@
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include "../../codecs/nau8825.h"
+#include "../../codecs/hdac_hdmi.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
@@ -33,6 +34,16 @@
static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card;
+enum {
+ SKL_DPCM_AUDIO_PB = 0,
+ SKL_DPCM_AUDIO_CP,
+ SKL_DPCM_AUDIO_REF_CP,
+ SKL_DPCM_AUDIO_DMIC_CP,
+ SKL_DPCM_AUDIO_HDMI1_PB,
+ SKL_DPCM_AUDIO_HDMI2_PB,
+ SKL_DPCM_AUDIO_HDMI3_PB,
+};
+
static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
@@ -92,7 +103,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_SPK("Left Speaker", NULL),
SND_SOC_DAPM_SPK("Right Speaker", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SINK("WoV Sink"),
SND_SOC_DAPM_SPK("DP", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
@@ -113,8 +123,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{"MIC", NULL, "Headset Mic"},
{"DMic", NULL, "SoC DMIC"},
- {"WoV Sink", NULL, "hwd_in sink"},
-
{"HDMI", NULL, "hif5 Output"},
{"DP", NULL, "hif6 Output"},
/* CODEC BE connections */
@@ -122,6 +130,11 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{ "Right Playback", NULL, "ssp0 Tx"},
{ "ssp0 Tx", NULL, "codec0_out"},
+ /* IV feedback path */
+ { "codec0_lp_in", NULL, "ssp0 Rx"},
+ { "ssp0 Rx", NULL, "Left Capture Sense" },
+ { "ssp0 Rx", NULL, "Right Capture Sense" },
+
{ "Playback", NULL, "ssp1 Tx"},
{ "ssp1 Tx", NULL, "codec1_out"},
@@ -131,8 +144,14 @@ static const struct snd_soc_dapm_route skylake_map[] = {
/* DMIC */
{ "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "DMIC AIF" },
- { "hifi1", NULL, "iDisp Tx"},
- { "iDisp Tx", NULL, "iDisp_out"},
+
+ { "hifi3", NULL, "iDisp3 Tx"},
+ { "iDisp3 Tx", NULL, "iDisp3_out"},
+ { "hifi2", NULL, "iDisp2 Tx"},
+ { "iDisp2 Tx", NULL, "iDisp2_out"},
+ { "hifi1", NULL, "iDisp1 Tx"},
+ { "iDisp1 Tx", NULL, "iDisp1_out"},
+
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
};
@@ -197,11 +216,32 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
nau8825_enable_jack_detect(codec, &skylake_headset);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
- snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
return ret;
}
+static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *dai = rtd->codec_dai;
+
+ return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB);
+}
+
+static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *dai = rtd->codec_dai;
+
+ return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB);
+}
+
+
+static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *dai = rtd->codec_dai;
+
+ return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB);
+}
+
static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dapm_context *dapm;
@@ -362,7 +402,7 @@ static struct snd_soc_ops skylaye_refcap_ops = {
/* skylake digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link skylake_dais[] = {
/* Front End DAI links */
- {
+ [SKL_DPCM_AUDIO_PB] = {
.name = "Skl Audio Port",
.stream_name = "Audio",
.cpu_dai_name = "System Pin",
@@ -377,7 +417,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_playback = 1,
.ops = &skylake_nau8825_fe_ops,
},
- {
+ [SKL_DPCM_AUDIO_CP] = {
.name = "Skl Audio Capture Port",
.stream_name = "Audio Record",
.cpu_dai_name = "System Pin",
@@ -391,7 +431,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1,
.ops = &skylake_nau8825_fe_ops,
},
- {
+ [SKL_DPCM_AUDIO_REF_CP] = {
.name = "Skl Audio Reference cap",
.stream_name = "Wake on Voice",
.cpu_dai_name = "Reference Pin",
@@ -405,7 +445,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dynamic = 1,
.ops = &skylaye_refcap_ops,
},
- {
+ [SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap",
.stream_name = "dmiccap",
.cpu_dai_name = "DMIC Pin",
@@ -418,13 +458,43 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dynamic = 1,
.ops = &skylake_dmic_ops,
},
- {
- .name = "Skl HDMI Port",
- .stream_name = "Hdmi",
- .cpu_dai_name = "HDMI Pin",
+ [SKL_DPCM_AUDIO_HDMI1_PB] = {
+ .name = "Skl HDMI Port1",
+ .stream_name = "Hdmi1",
+ .cpu_dai_name = "HDMI1 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [SKL_DPCM_AUDIO_HDMI2_PB] = {
+ .name = "Skl HDMI Port2",
+ .stream_name = "Hdmi2",
+ .cpu_dai_name = "HDMI2 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [SKL_DPCM_AUDIO_HDMI3_PB] = {
+ .name = "Skl HDMI Port3",
+ .stream_name = "Hdmi3",
+ .cpu_dai_name = "HDMI3 Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
.init = NULL,
.nonatomic = 1,
@@ -448,11 +518,12 @@ static struct snd_soc_dai_link skylake_dais[] = {
.ignore_pmdown_time = 1,
.be_hw_params_fixup = skylake_ssp_fixup,
.dpcm_playback = 1,
+ .dpcm_capture = 1,
},
{
/* SSP1 - Codec */
.name = "SSP1-Codec",
- .be_id = 0,
+ .be_id = 1,
.cpu_dai_name = "SSP1 Pin",
.platform_name = "0000:00:1f.3",
.no_pcm = 1,
@@ -469,7 +540,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
},
{
.name = "dmic01",
- .be_id = 1,
+ .be_id = 2,
.cpu_dai_name = "DMIC01 Pin",
.codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi",
@@ -480,13 +551,36 @@ static struct snd_soc_dai_link skylake_dais[] = {
.no_pcm = 1,
},
{
- .name = "iDisp",
+ .name = "iDisp1",
.be_id = 3,
- .cpu_dai_name = "iDisp Pin",
+ .cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
+ .init = skylake_hdmi1_init,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp2",
+ .be_id = 4,
+ .cpu_dai_name = "iDisp2 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi2",
+ .platform_name = "0000:00:1f.3",
+ .init = skylake_hdmi2_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp3",
+ .be_id = 5,
+ .cpu_dai_name = "iDisp3 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi3",
+ .platform_name = "0000:00:1f.3",
+ .init = skylake_hdmi3_init,
+ .dpcm_playback = 1,
.no_pcm = 1,
},
};
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index 7396ddb427d8..2016397a8e75 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -26,8 +26,20 @@
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include "../../codecs/rt286.h"
+#include "../../codecs/hdac_hdmi.h"
static struct snd_soc_jack skylake_headset;
+
+enum {
+ SKL_DPCM_AUDIO_PB = 0,
+ SKL_DPCM_AUDIO_CP,
+ SKL_DPCM_AUDIO_REF_CP,
+ SKL_DPCM_AUDIO_DMIC_CP,
+ SKL_DPCM_AUDIO_HDMI1_PB,
+ SKL_DPCM_AUDIO_HDMI2_PB,
+ SKL_DPCM_AUDIO_HDMI3_PB,
+};
+
/* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin skylake_headset_pins[] = {
{
@@ -52,7 +64,9 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("DMIC2", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
- SND_SOC_DAPM_SINK("WoV Sink"),
+ SND_SOC_DAPM_SPK("HDMI1", NULL),
+ SND_SOC_DAPM_SPK("HDMI2", NULL),
+ SND_SOC_DAPM_SPK("HDMI3", NULL),
};
static const struct snd_soc_dapm_route skylake_rt286_map[] = {
@@ -70,7 +84,9 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
{"DMIC1 Pin", NULL, "DMIC2"},
{"DMic", NULL, "SoC DMIC"},
- {"WoV Sink", NULL, "hwd_in sink"},
+ {"HDMI1", NULL, "hif5 Output"},
+ {"HDMI2", NULL, "hif6 Output"},
+ {"HDMI3", NULL, "hif7 Output"},
/* CODEC BE connections */
{ "AIF1 Playback", NULL, "ssp0 Tx"},
@@ -84,8 +100,12 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
{ "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "DMIC AIF" },
- { "hif1", NULL, "iDisp Tx"},
- { "iDisp Tx", NULL, "iDisp_out"},
+ { "hifi3", NULL, "iDisp3 Tx"},
+ { "iDisp3 Tx", NULL, "iDisp3_out"},
+ { "hifi2", NULL, "iDisp2 Tx"},
+ { "iDisp2 Tx", NULL, "iDisp2_out"},
+ { "hifi1", NULL, "iDisp1 Tx"},
+ { "iDisp1 Tx", NULL, "iDisp1_out"},
};
@@ -116,11 +136,17 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
rt286_mic_detect(codec, &skylake_headset);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
- snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
return 0;
}
+static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *dai = rtd->codec_dai;
+
+ return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB + dai->id);
+}
+
static unsigned int rates[] = {
48000,
};
@@ -212,7 +238,10 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
{
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- channels->min = channels->max = 4;
+ if (params_channels(params) == 2)
+ channels->min = channels->max = 2;
+ else
+ channels->min = channels->max = 4;
return 0;
}
@@ -246,7 +275,7 @@ static struct snd_soc_ops skylake_dmic_ops = {
/* skylake digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link skylake_rt286_dais[] = {
/* Front End DAI links */
- {
+ [SKL_DPCM_AUDIO_PB] = {
.name = "Skl Audio Port",
.stream_name = "Audio",
.cpu_dai_name = "System Pin",
@@ -263,7 +292,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dpcm_playback = 1,
.ops = &skylake_rt286_fe_ops,
},
- {
+ [SKL_DPCM_AUDIO_CP] = {
.name = "Skl Audio Capture Port",
.stream_name = "Audio Record",
.cpu_dai_name = "System Pin",
@@ -279,7 +308,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dpcm_capture = 1,
.ops = &skylake_rt286_fe_ops,
},
- {
+ [SKL_DPCM_AUDIO_REF_CP] = {
.name = "Skl Audio Reference cap",
.stream_name = "refcap",
.cpu_dai_name = "Reference Pin",
@@ -292,7 +321,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.nonatomic = 1,
.dynamic = 1,
},
- {
+ [SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap",
.stream_name = "dmiccap",
.cpu_dai_name = "DMIC Pin",
@@ -305,6 +334,42 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dynamic = 1,
.ops = &skylake_dmic_ops,
},
+ [SKL_DPCM_AUDIO_HDMI1_PB] = {
+ .name = "Skl HDMI Port1",
+ .stream_name = "Hdmi1",
+ .cpu_dai_name = "HDMI1 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [SKL_DPCM_AUDIO_HDMI2_PB] = {
+ .name = "Skl HDMI Port2",
+ .stream_name = "Hdmi2",
+ .cpu_dai_name = "HDMI2 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [SKL_DPCM_AUDIO_HDMI3_PB] = {
+ .name = "Skl HDMI Port3",
+ .stream_name = "Hdmi3",
+ .cpu_dai_name = "HDMI3 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:1f.3",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
/* Back End DAI links */
{
@@ -338,6 +403,39 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dpcm_capture = 1,
.no_pcm = 1,
},
+ {
+ .name = "iDisp1",
+ .be_id = 2,
+ .cpu_dai_name = "iDisp1 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi1",
+ .platform_name = "0000:00:1f.3",
+ .init = skylake_hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp2",
+ .be_id = 3,
+ .cpu_dai_name = "iDisp2 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi2",
+ .platform_name = "0000:00:1f.3",
+ .init = skylake_hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp3",
+ .be_id = 4,
+ .cpu_dai_name = "iDisp3 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi3",
+ .platform_name = "0000:00:1f.3",
+ .init = skylake_hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
};
/* skylake audio machine driver for SPT + RT286S */
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index 668fdeee195e..fbbb25c2ceed 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -1,13 +1,10 @@
snd-soc-sst-dsp-objs := sst-dsp.o
-ifneq ($(CONFIG_SND_SST_IPC_ACPI),)
-snd-soc-sst-acpi-objs := sst-match-acpi.o
-else
-snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o
-endif
-
+snd-soc-sst-acpi-objs := sst-acpi.o
+snd-soc-sst-match-objs := sst-match-acpi.o
snd-soc-sst-ipc-objs := sst-ipc.o
snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
+obj-$(CONFIG_SND_SOC_INTEL_SST_MATCH) += snd-soc-sst-match.o
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c
index 7a85c576dad3..2c5eda14d510 100644
--- a/sound/soc/intel/common/sst-acpi.c
+++ b/sound/soc/intel/common/sst-acpi.c
@@ -215,6 +215,7 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
.dma_size = SST_LPT_DSP_DMA_SIZE,
};
+#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
static struct sst_acpi_mach baytrail_machines[] = {
{ "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
{ "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
@@ -231,11 +232,14 @@ static struct sst_acpi_desc sst_acpi_baytrail_desc = {
.sst_id = SST_DEV_ID_BYT,
.resindex_dma_base = -1,
};
+#endif
static const struct acpi_device_id sst_acpi_match[] = {
{ "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
{ "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
+#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
{ "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
+#endif
{ }
};
MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h
index 3ee3b7ab5d03..4dcfb7e5ed70 100644
--- a/sound/soc/intel/common/sst-acpi.h
+++ b/sound/soc/intel/common/sst-acpi.h
@@ -14,6 +14,9 @@
#include <linux/acpi.h>
+/* translation fron HID to I2C name, needed for DAI codec_name */
+const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]);
+
/* acpi match */
struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines);
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h
index 81aa1ed64201..97dc1ae05e69 100644
--- a/sound/soc/intel/common/sst-dsp-priv.h
+++ b/sound/soc/intel/common/sst-dsp-priv.h
@@ -317,6 +317,7 @@ struct sst_dsp {
struct skl_cl_dev cl_dev;
u32 intr_status;
const struct firmware *fw;
+ struct snd_dma_buffer dmab;
};
/* Size optimised DRAM/IRAM memcpy */
diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c
index dd077e116d25..789843307a49 100644
--- a/sound/soc/intel/common/sst-match-acpi.c
+++ b/sound/soc/intel/common/sst-match-acpi.c
@@ -13,17 +13,53 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
-#include <linux/acpi.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
#include "sst-acpi.h"
+static acpi_status sst_acpi_find_name(acpi_handle handle, u32 level,
+ void *context, void **ret)
+{
+ struct acpi_device *adev;
+ const char *name = NULL;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+
+ if (adev->status.present && adev->status.functional) {
+ name = acpi_dev_name(adev);
+ *(const char **)ret = name;
+ return AE_CTRL_TERMINATE;
+ }
+
+ return AE_OK;
+}
+
+const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
+{
+ const char *name = NULL;
+ acpi_status status;
+
+ status = acpi_get_devices(hid, sst_acpi_find_name, NULL,
+ (void **)&name);
+
+ if (ACPI_FAILURE(status) || name[0] == '\0')
+ return NULL;
+
+ return name;
+}
+EXPORT_SYMBOL_GPL(sst_acpi_find_name_from_hid);
+
static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
void *context, void **ret)
{
+ unsigned long long sta;
+ acpi_status status;
+
*(bool *)context = true;
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
+ *(bool *)context = false;
+
return AE_OK;
}
@@ -37,7 +73,9 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
sst_acpi_mach_match,
&found, NULL)) && found)
return mach;
-
return NULL;
}
EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index de6dac496a0d..79c5089b85d6 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -72,17 +72,47 @@ static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable)
skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)&mask);
}
+static struct skl_dsp_loader_ops skl_get_loader_ops(void)
+{
+ struct skl_dsp_loader_ops loader_ops;
+
+ memset(&loader_ops, 0, sizeof(struct skl_dsp_loader_ops));
+
+ loader_ops.alloc_dma_buf = skl_alloc_dma_buf;
+ loader_ops.free_dma_buf = skl_free_dma_buf;
+
+ return loader_ops;
+};
+
+static const struct skl_dsp_ops dsp_ops[] = {
+ {
+ .id = 0x9d70,
+ .loader_ops = skl_get_loader_ops,
+ .init = skl_sst_dsp_init,
+ .cleanup = skl_sst_dsp_cleanup
+ },
+};
+
+static int skl_get_dsp_ops(int pci_id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) {
+ if (dsp_ops[i].id == pci_id)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
int skl_init_dsp(struct skl *skl)
{
void __iomem *mmio_base;
struct hdac_ext_bus *ebus = &skl->ebus;
struct hdac_bus *bus = ebus_to_hbus(ebus);
- int irq = bus->irq;
struct skl_dsp_loader_ops loader_ops;
- int ret;
-
- loader_ops.alloc_dma_buf = skl_alloc_dma_buf;
- loader_ops.free_dma_buf = skl_free_dma_buf;
+ int irq = bus->irq;
+ int ret, index;
/* enable ppcap interrupt */
snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
@@ -95,8 +125,14 @@ int skl_init_dsp(struct skl *skl)
return -ENXIO;
}
- ret = skl_sst_dsp_init(bus->dev, mmio_base, irq,
+ index = skl_get_dsp_ops(skl->pci->device);
+ if (index < 0)
+ return -EINVAL;
+
+ loader_ops = dsp_ops[index].loader_ops();
+ ret = dsp_ops[index].init(bus->dev, mmio_base, irq,
skl->fw_name, loader_ops, &skl->skl_sst);
+
if (ret < 0)
return ret;
@@ -106,18 +142,26 @@ int skl_init_dsp(struct skl *skl)
return ret;
}
-void skl_free_dsp(struct skl *skl)
+int skl_free_dsp(struct skl *skl)
{
struct hdac_ext_bus *ebus = &skl->ebus;
struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct skl_sst *ctx = skl->skl_sst;
+ struct skl_sst *ctx = skl->skl_sst;
+ int index;
/* disable ppcap interrupt */
snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
- skl_sst_dsp_cleanup(bus->dev, ctx);
+ index = skl_get_dsp_ops(skl->pci->device);
+ if (index < 0)
+ return -EIO;
+
+ dsp_ops[index].cleanup(bus->dev, ctx);
+
if (ctx->dsp->addr.lpe)
iounmap(ctx->dsp->addr.lpe);
+
+ return 0;
}
int skl_suspend_dsp(struct skl *skl)
@@ -238,9 +282,8 @@ static void skl_copy_copier_caps(struct skl_module_cfg *mconfig,
* Calculate the gatewat settings required for copier module, type of
* gateway and index of gateway to use
*/
-static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
- struct skl_module_cfg *mconfig,
- struct skl_cpr_cfg *cpr_mconfig)
+static u32 skl_get_node_id(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig)
{
union skl_connector_node_id node_id = {0};
union skl_ssp_dma_node ssp_node = {0};
@@ -289,13 +332,24 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
break;
default:
- cpr_mconfig->gtw_cfg.node_id = SKL_NON_GATEWAY_CPR_NODE_ID;
+ node_id.val = 0xFFFFFFFF;
+ break;
+ }
+
+ return node_id.val;
+}
+
+static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig,
+ struct skl_cpr_cfg *cpr_mconfig)
+{
+ cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig);
+
+ if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) {
cpr_mconfig->cpr_feature_mask = 0;
return;
}
- cpr_mconfig->gtw_cfg.node_id = node_id.val;
-
if (SKL_CONN_SOURCE == mconfig->hw_conn_type)
cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs;
else
@@ -307,6 +361,46 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
skl_copy_copier_caps(mconfig, cpr_mconfig);
}
+#define DMA_CONTROL_ID 5
+
+int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig)
+{
+ struct skl_dma_control *dma_ctrl;
+ struct skl_i2s_config_blob config_blob;
+ struct skl_ipc_large_config_msg msg = {0};
+ int err = 0;
+
+
+ /*
+ * if blob size is same as capablity size, then no dma control
+ * present so return
+ */
+ if (mconfig->formats_config.caps_size == sizeof(config_blob))
+ return 0;
+
+ msg.large_param_id = DMA_CONTROL_ID;
+ msg.param_data_size = sizeof(struct skl_dma_control) +
+ mconfig->formats_config.caps_size;
+
+ dma_ctrl = kzalloc(msg.param_data_size, GFP_KERNEL);
+ if (dma_ctrl == NULL)
+ return -ENOMEM;
+
+ dma_ctrl->node_id = skl_get_node_id(ctx, mconfig);
+
+ /* size in dwords */
+ dma_ctrl->config_length = sizeof(config_blob) / 4;
+
+ memcpy(dma_ctrl->config_data, mconfig->formats_config.caps,
+ mconfig->formats_config.caps_size);
+
+ err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl);
+
+ kfree(dma_ctrl);
+
+ return err;
+}
+
static void skl_setup_out_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig,
struct skl_audio_data_format *out_fmt)
@@ -688,14 +782,14 @@ int skl_unbind_modules(struct skl_sst *ctx,
/* get src queue index */
src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max);
if (src_index < 0)
- return -EINVAL;
+ return 0;
msg.src_queue = src_index;
/* get dst queue index */
dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max);
if (dst_index < 0)
- return -EINVAL;
+ return 0;
msg.dst_queue = dst_index;
@@ -747,7 +841,7 @@ int skl_bind_modules(struct skl_sst *ctx,
skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
- if (src_mcfg->m_state < SKL_MODULE_INIT_DONE &&
+ if (src_mcfg->m_state < SKL_MODULE_INIT_DONE ||
dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
return 0;
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index 6e4b21cdb1bd..14d1916ea9f8 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -145,3 +145,37 @@ struct nhlt_specific_cfg
return NULL;
}
+
+static void skl_nhlt_trim_space(struct skl *skl)
+{
+ char *s = skl->tplg_name;
+ int cnt;
+ int i;
+
+ cnt = 0;
+ for (i = 0; s[i]; i++) {
+ if (!isspace(s[i]))
+ s[cnt++] = s[i];
+ }
+
+ s[cnt] = '\0';
+}
+
+int skl_nhlt_update_topology_bin(struct skl *skl)
+{
+ struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
+ struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct device *dev = bus->dev;
+
+ dev_dbg(dev, "oem_id %.6s, oem_table_id %8s oem_revision %d\n",
+ nhlt->header.oem_id, nhlt->header.oem_table_id,
+ nhlt->header.oem_revision);
+
+ snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s",
+ skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id,
+ nhlt->header.oem_revision, "-tplg.bin");
+
+ skl_nhlt_trim_space(skl);
+
+ return 0;
+}
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index f3553258091a..dab0900eef26 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -206,6 +206,23 @@ static int skl_get_format(struct snd_pcm_substream *substream,
return format_val;
}
+static int skl_be_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct skl *skl = get_skl_ctx(dai->dev);
+ struct skl_sst *ctx = skl->skl_sst;
+ struct skl_module_cfg *mconfig;
+
+ if ((dai->playback_active > 1) || (dai->capture_active > 1))
+ return 0;
+
+ mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream);
+ if (mconfig == NULL)
+ return -EINVAL;
+
+ return skl_dsp_set_dma_control(ctx, mconfig);
+}
+
static int skl_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -458,7 +475,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *link_dev;
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- struct skl_dma_params *dma_params;
+ struct hdac_ext_dma_params *dma_params;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct skl_pipe_params p_params = {0};
@@ -470,11 +487,9 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
/* set the stream tag in the codec dai dma params */
- dma_params = (struct skl_dma_params *)
- snd_soc_dai_get_dma_data(codec_dai, substream);
+ dma_params = snd_soc_dai_get_dma_data(codec_dai, substream);
if (dma_params)
dma_params->stream_tag = hdac_stream(link_dev)->stream_tag;
- snd_soc_dai_set_dma_data(codec_dai, substream, (void *)dma_params);
p_params.s_fmt = snd_pcm_format_width(params_format(params));
p_params.ch = params_channels(params);
@@ -588,6 +603,7 @@ static struct snd_soc_dai_ops skl_dmic_dai_ops = {
static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
.hw_params = skl_be_hw_params,
+ .prepare = skl_be_prepare,
};
static struct snd_soc_dai_ops skl_link_dai_ops = {
@@ -660,6 +676,51 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
},
+{
+ .name = "HDMI1 Pin",
+ .ops = &skl_pcm_dai_ops,
+ .playback = {
+ .stream_name = "HDMI1 Playback",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+},
+{
+ .name = "HDMI2 Pin",
+ .ops = &skl_pcm_dai_ops,
+ .playback = {
+ .stream_name = "HDMI2 Playback",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+},
+{
+ .name = "HDMI3 Pin",
+ .ops = &skl_pcm_dai_ops,
+ .playback = {
+ .stream_name = "HDMI3 Playback",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+},
/* BE CPU Dais */
{
@@ -699,14 +760,41 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
},
},
{
- .name = "iDisp Pin",
+ .name = "iDisp1 Pin",
.ops = &skl_link_dai_ops,
.playback = {
- .stream_name = "iDisp Tx",
+ .stream_name = "iDisp1 Tx",
.channels_min = HDA_STEREO,
.channels_max = HDA_STEREO,
.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "iDisp2 Pin",
+ .ops = &skl_link_dai_ops,
+ .playback = {
+ .stream_name = "iDisp2 Tx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "iDisp3 Pin",
+ .ops = &skl_link_dai_ops,
+ .playback = {
+ .stream_name = "iDisp3 Tx",
+ .channels_min = HDA_STEREO,
+ .channels_max = HDA_STEREO,
+ .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
},
},
{
@@ -864,6 +952,9 @@ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus,
delay += hstream->bufsize;
}
+ if (hstream->bufsize == delay)
+ delay = 0;
+
if (delay >= hstream->period_bytes) {
dev_info(bus->dev,
"Unstable LPIB (%d >= %d); disabling LPIB delay counting\n",
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c
index 1bfb7f63b572..a5267e8a96e0 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.c
+++ b/sound/soc/intel/skylake/skl-sst-dsp.c
@@ -34,7 +34,7 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state)
mutex_unlock(&ctx->mutex);
}
-static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx)
+static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx)
{
int ret;
@@ -60,7 +60,7 @@ static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx)
return ret;
}
-static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
+static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
{
int ret;
@@ -87,7 +87,7 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
return ret;
}
-static bool is_skl_dsp_core_enable(struct sst_dsp *ctx)
+static bool is_skl_dsp_core_enable(struct sst_dsp *ctx)
{
int val;
bool is_enable;
@@ -140,7 +140,7 @@ static int skl_dsp_start_core(struct sst_dsp *ctx)
return ret;
}
-static int skl_dsp_core_power_up(struct sst_dsp *ctx)
+static int skl_dsp_core_power_up(struct sst_dsp *ctx)
{
int ret;
@@ -166,7 +166,7 @@ static int skl_dsp_core_power_up(struct sst_dsp *ctx)
return ret;
}
-static int skl_dsp_core_power_down(struct sst_dsp *ctx)
+static int skl_dsp_core_power_down(struct sst_dsp *ctx)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
@@ -181,7 +181,7 @@ static int skl_dsp_core_power_down(struct sst_dsp *ctx)
"Power down");
}
-static int skl_dsp_enable_core(struct sst_dsp *ctx)
+int skl_dsp_enable_core(struct sst_dsp *ctx)
{
int ret;
@@ -195,7 +195,7 @@ static int skl_dsp_enable_core(struct sst_dsp *ctx)
return skl_dsp_start_core(ctx);
}
-int skl_dsp_disable_core(struct sst_dsp *ctx)
+int skl_dsp_disable_core(struct sst_dsp *ctx)
{
int ret;
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
index cbb40751c37e..b6e310d49dd6 100644
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
@@ -53,6 +53,10 @@ struct sst_dsp_device;
/* HIPCT */
#define SKL_ADSP_REG_HIPCT_BUSY BIT(31)
+/* FW base IDs */
+#define SKL_INSTANCE_ID 0
+#define SKL_BASE_FW_MODULE_ID 0
+
/* Intel HD Audio SRAM Window 1 */
#define SKL_ADSP_SRAM1_BASE 0xA000
@@ -144,7 +148,8 @@ int skl_cldma_prepare(struct sst_dsp *ctx);
void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
struct sst_dsp_device *sst_dev, int irq);
-int skl_dsp_disable_core(struct sst_dsp *ctx);
+int skl_dsp_enable_core(struct sst_dsp *ctx);
+int skl_dsp_disable_core(struct sst_dsp *ctx);
bool is_skl_dsp_running(struct sst_dsp *ctx);
irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id);
int skl_dsp_wake(struct sst_dsp *ctx);
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index e26f4746afb7..348a734f8e24 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -35,9 +35,6 @@
#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE
#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4)
-#define SKL_INSTANCE_ID 0
-#define SKL_BASE_FW_MODULE_ID 0
-
#define SKL_NUM_MODULES 1
static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status)
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 4624556f486d..545b4e77b8aa 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -54,12 +54,9 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w)
/*
* Each pipelines needs memory to be allocated. Check if we have free memory
- * from available pool. Then only add this to pool
- * This is freed when pipe is deleted
- * Note: DSP does actual memory management we only keep track for complete
- * pool
+ * from available pool.
*/
-static bool skl_tplg_alloc_pipe_mem(struct skl *skl,
+static bool skl_is_pipe_mem_avail(struct skl *skl,
struct skl_module_cfg *mconfig)
{
struct skl_sst *ctx = skl->skl_sst;
@@ -74,10 +71,20 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl,
"exceeds ppl memory available %d mem %d\n",
skl->resource.max_mem, skl->resource.mem);
return false;
+ } else {
+ return true;
}
+}
+/*
+ * Add the mem to the mem pool. This is freed when pipe is deleted.
+ * Note: DSP does actual memory management we only keep track for complete
+ * pool
+ */
+static void skl_tplg_alloc_pipe_mem(struct skl *skl,
+ struct skl_module_cfg *mconfig)
+{
skl->resource.mem += mconfig->pipe->memory_pages;
- return true;
}
/*
@@ -85,10 +92,10 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl,
* quantified in MCPS (Million Clocks Per Second) required for module/pipe
*
* Each pipelines needs mcps to be allocated. Check if we have mcps for this
- * pipe. This adds the mcps to driver counter
- * This is removed on pipeline delete
+ * pipe.
*/
-static bool skl_tplg_alloc_pipe_mcps(struct skl *skl,
+
+static bool skl_is_pipe_mcps_avail(struct skl *skl,
struct skl_module_cfg *mconfig)
{
struct skl_sst *ctx = skl->skl_sst;
@@ -98,13 +105,18 @@ static bool skl_tplg_alloc_pipe_mcps(struct skl *skl,
"%s: module_id %d instance %d\n", __func__,
mconfig->id.module_id, mconfig->id.instance_id);
dev_err(ctx->dev,
- "exceeds ppl memory available %d > mem %d\n",
+ "exceeds ppl mcps available %d > mem %d\n",
skl->resource.max_mcps, skl->resource.mcps);
return false;
+ } else {
+ return true;
}
+}
+static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
+ struct skl_module_cfg *mconfig)
+{
skl->resource.mcps += mconfig->mcps;
- return true;
}
/*
@@ -248,6 +260,65 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
multiplier;
}
+static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
+ struct skl_sst *ctx)
+{
+ struct skl_module_cfg *m_cfg = w->priv;
+ int link_type, dir;
+ u32 ch, s_freq, s_fmt;
+ struct nhlt_specific_cfg *cfg;
+ struct skl *skl = get_skl_ctx(ctx->dev);
+
+ /* check if we already have blob */
+ if (m_cfg->formats_config.caps_size > 0)
+ return 0;
+
+ dev_dbg(ctx->dev, "Applying default cfg blob\n");
+ switch (m_cfg->dev_type) {
+ case SKL_DEVICE_DMIC:
+ link_type = NHLT_LINK_DMIC;
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ s_freq = m_cfg->in_fmt[0].s_freq;
+ s_fmt = m_cfg->in_fmt[0].bit_depth;
+ ch = m_cfg->in_fmt[0].channels;
+ break;
+
+ case SKL_DEVICE_I2S:
+ link_type = NHLT_LINK_SSP;
+ if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
+ dir = SNDRV_PCM_STREAM_PLAYBACK;
+ s_freq = m_cfg->out_fmt[0].s_freq;
+ s_fmt = m_cfg->out_fmt[0].bit_depth;
+ ch = m_cfg->out_fmt[0].channels;
+ } else {
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ s_freq = m_cfg->in_fmt[0].s_freq;
+ s_fmt = m_cfg->in_fmt[0].bit_depth;
+ ch = m_cfg->in_fmt[0].channels;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* update the blob based on virtual bus_id and default params */
+ cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
+ s_fmt, ch, s_freq, dir);
+ if (cfg) {
+ m_cfg->formats_config.caps_size = cfg->size;
+ m_cfg->formats_config.caps = (u32 *) &cfg->caps;
+ } else {
+ dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n",
+ m_cfg->vbus_id, link_type, dir);
+ dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n",
+ ch, s_freq, s_fmt);
+ return -EIO;
+ }
+
+ return 0;
+}
+
static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
struct skl_sst *ctx)
{
@@ -411,7 +482,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
mconfig = w->priv;
/* check resource available */
- if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
+ if (!skl_is_pipe_mcps_avail(skl, mconfig))
return -ENOMEM;
if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
@@ -421,6 +492,9 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
return ret;
}
+ /* update blob if blob is null for be with default value */
+ skl_tplg_update_be_blob(w, ctx);
+
/*
* apply fix/conversion to module params based on
* FE/BE params
@@ -435,6 +509,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
ret = skl_tplg_set_module_params(w, ctx);
if (ret < 0)
return ret;
+ skl_tplg_alloc_pipe_mcps(skl, mconfig);
}
return 0;
@@ -477,10 +552,10 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
struct skl_sst *ctx = skl->skl_sst;
/* check resource available */
- if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
+ if (!skl_is_pipe_mcps_avail(skl, mconfig))
return -EBUSY;
- if (!skl_tplg_alloc_pipe_mem(skl, mconfig))
+ if (!skl_is_pipe_mem_avail(skl, mconfig))
return -ENOMEM;
/*
@@ -526,11 +601,75 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
src_module = dst_module;
}
+ skl_tplg_alloc_pipe_mem(skl, mconfig);
+ skl_tplg_alloc_pipe_mcps(skl, mconfig);
+
+ return 0;
+}
+
+/*
+ * Some modules require params to be set after the module is bound to
+ * all pins connected.
+ *
+ * The module provider initializes set_param flag for such modules and we
+ * send params after binding
+ */
+static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
+ struct skl_module_cfg *mcfg, struct skl_sst *ctx)
+{
+ int i, ret;
+ struct skl_module_cfg *mconfig = w->priv;
+ const struct snd_kcontrol_new *k;
+ struct soc_bytes_ext *sb;
+ struct skl_algo_data *bc;
+ struct skl_specific_cfg *sp_cfg;
+
+ /*
+ * check all out/in pins are in bind state.
+ * if so set the module param
+ */
+ for (i = 0; i < mcfg->max_out_queue; i++) {
+ if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
+ return 0;
+ }
+
+ for (i = 0; i < mcfg->max_in_queue; i++) {
+ if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
+ return 0;
+ }
+
+ if (mconfig->formats_config.caps_size > 0 &&
+ mconfig->formats_config.set_params == SKL_PARAM_BIND) {
+ sp_cfg = &mconfig->formats_config;
+ ret = skl_set_module_params(ctx, sp_cfg->caps,
+ sp_cfg->caps_size,
+ sp_cfg->param_id, mconfig);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < w->num_kcontrols; i++) {
+ k = &w->kcontrol_news[i];
+ if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+ sb = (void *) k->private_value;
+ bc = (struct skl_algo_data *)sb->dobj.private;
+
+ if (bc->set_params == SKL_PARAM_BIND) {
+ ret = skl_set_module_params(ctx,
+ (u32 *)bc->params, bc->max,
+ bc->param_id, mconfig);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+
return 0;
}
static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
struct skl *skl,
+ struct snd_soc_dapm_widget *src_w,
struct skl_module_cfg *src_mconfig)
{
struct snd_soc_dapm_path *p;
@@ -547,6 +686,10 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
next_sink = p->sink;
+
+ if (!is_skl_dsp_widget_type(p->sink))
+ return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
+
/*
* here we will check widgets in sink pipelines, so that
* can be any widgets type and we are only interested if
@@ -558,11 +701,19 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
sink = p->sink;
sink_mconfig = sink->priv;
+ if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
+ sink_mconfig->m_state == SKL_MODULE_UNINIT)
+ continue;
+
/* Bind source to sink, mixin is always source */
ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
if (ret)
return ret;
+ /* set module params after bind */
+ skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx);
+ skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
+
/* Start sinks pipe first */
if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
if (sink_mconfig->pipe->conn_type !=
@@ -576,7 +727,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
}
if (!sink)
- return skl_tplg_bind_sinks(next_sink, skl, src_mconfig);
+ return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
return 0;
}
@@ -605,7 +756,7 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
* if sink is not started, start sink pipe first, then start
* this pipe
*/
- ret = skl_tplg_bind_sinks(w, skl, src_mconfig);
+ ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
if (ret)
return ret;
@@ -693,6 +844,10 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
if (ret)
return ret;
+ /* set module params after bind */
+ skl_tplg_set_module_bind_params(source, src_mconfig, ctx);
+ skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
+
if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
ret = skl_run_pipe(ctx, sink_mconfig->pipe);
}
@@ -773,10 +928,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
continue;
}
- ret = skl_unbind_modules(ctx, src_module, dst_module);
- if (ret < 0)
- return ret;
-
+ skl_unbind_modules(ctx, src_module, dst_module);
src_module = dst_module;
}
@@ -814,9 +966,6 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
* This is a connecter and if path is found that means
* unbind between source and sink has not happened yet
*/
- ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
- if (ret < 0)
- return ret;
ret = skl_unbind_modules(ctx, src_mconfig,
sink_mconfig);
}
@@ -842,6 +991,12 @@ static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_PRE_PMU:
return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
+ case SND_SOC_DAPM_POST_PMU:
+ return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
+
+ case SND_SOC_DAPM_PRE_PMD:
+ return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
+
case SND_SOC_DAPM_POST_PMD:
return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
}
@@ -916,6 +1071,13 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
bc->max, bc->param_id, mconfig);
+ /* decrement size for TLV header */
+ size -= 2 * sizeof(u32);
+
+ /* check size as we don't want to send kernel data */
+ if (size > bc->max)
+ size = bc->max;
+
if (bc->params) {
if (copy_to_user(data, &bc->param_id, sizeof(u32)))
return -EFAULT;
@@ -950,7 +1112,7 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
return -EFAULT;
} else {
if (copy_from_user(ac->params,
- data + 2 * sizeof(u32), size))
+ data + 2, size))
return -EFAULT;
}
@@ -1063,6 +1225,66 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
return NULL;
}
+static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
+ struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p;
+ struct skl_module_cfg *mconfig = NULL;
+
+ snd_soc_dapm_widget_for_each_source_path(w, p) {
+ if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
+ if (p->connect &&
+ (p->sink->id == snd_soc_dapm_aif_out) &&
+ p->source->priv) {
+ mconfig = p->source->priv;
+ return mconfig;
+ }
+ mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
+ if (mconfig)
+ return mconfig;
+ }
+ }
+ return mconfig;
+}
+
+static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
+ struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p;
+ struct skl_module_cfg *mconfig = NULL;
+
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
+ if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
+ if (p->connect &&
+ (p->source->id == snd_soc_dapm_aif_in) &&
+ p->sink->priv) {
+ mconfig = p->sink->priv;
+ return mconfig;
+ }
+ mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
+ if (mconfig)
+ return mconfig;
+ }
+ }
+ return mconfig;
+}
+
+struct skl_module_cfg *
+skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
+{
+ struct snd_soc_dapm_widget *w;
+ struct skl_module_cfg *mconfig;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ w = dai->playback_widget;
+ mconfig = skl_get_mconfig_pb_cpr(dai, w);
+ } else {
+ w = dai->capture_widget;
+ mconfig = skl_get_mconfig_cap_cpr(dai, w);
+ }
+ return mconfig;
+}
+
static u8 skl_tplg_be_link_type(int dev_type)
{
int ret;
@@ -1436,8 +1658,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
if (!ac->params)
return -ENOMEM;
- if (dfw_ac->params)
- memcpy(ac->params, dfw_ac->params, ac->max);
+ memcpy(ac->params, dfw_ac->params, ac->max);
}
be->dobj.private = ac;
@@ -1495,11 +1716,16 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
struct hdac_bus *bus = ebus_to_hbus(ebus);
struct skl *skl = ebus_to_skl(ebus);
- ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
+ ret = request_firmware(&fw, skl->tplg_name, bus->dev);
if (ret < 0) {
dev_err(bus->dev, "tplg fw %s load failed with %d\n",
- "dfw_sst.bin", ret);
- return ret;
+ skl->tplg_name, ret);
+ ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
+ if (ret < 0) {
+ dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
+ "dfw_sst.bin", ret);
+ return ret;
+ }
}
/*
@@ -1510,6 +1736,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
&skl_tplg_ops, fw, 0);
if (ret < 0) {
dev_err(bus->dev, "tplg component load failed%d\n", ret);
+ release_firmware(fw);
return -EINVAL;
}
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 9aa2a2b6598a..de3c401284d9 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -113,6 +113,29 @@ struct skl_cpr_gtw_cfg {
u32 config_data[1];
} __packed;
+struct skl_i2s_config_blob {
+ u32 gateway_attrib;
+ u32 tdm_ts_group[8];
+ u32 ssc0;
+ u32 ssc1;
+ u32 sscto;
+ u32 sspsp;
+ u32 sstsa;
+ u32 ssrsa;
+ u32 ssc2;
+ u32 sspsp2;
+ u32 ssc3;
+ u32 ssioc;
+ u32 mdivc;
+ u32 mdivr;
+} __packed;
+
+struct skl_dma_control {
+ u32 node_id;
+ u32 config_length;
+ u32 config_data[1];
+} __packed;
+
struct skl_cpr_cfg {
struct skl_base_cfg base_cfg;
struct skl_audio_data_format out_fmt;
@@ -313,6 +336,8 @@ static inline struct skl *get_skl_ctx(struct device *dev)
int skl_tplg_be_update_params(struct snd_soc_dai *dai,
struct skl_pipe_params *params);
+int skl_dsp_set_dma_control(struct skl_sst *ctx,
+ struct skl_module_cfg *mconfig);
void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
struct skl_pipe_params *params, int stream);
int skl_tplg_init(struct snd_soc_platform *platform,
@@ -345,5 +370,7 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
u32 param_id, struct skl_module_cfg *mcfg);
+struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai,
+ int stream);
enum skl_bitdepth skl_get_bit_depth(int params);
#endif
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h
index c9ae010b3cc8..1db88a63ac17 100644
--- a/sound/soc/intel/skylake/skl-tplg-interface.h
+++ b/sound/soc/intel/skylake/skl-tplg-interface.h
@@ -144,7 +144,8 @@ enum module_pin_type {
enum skl_module_param_type {
SKL_PARAM_DEFAULT = 0,
SKL_PARAM_INIT,
- SKL_PARAM_SET
+ SKL_PARAM_SET,
+ SKL_PARAM_BIND
};
struct skl_dfw_module_pin {
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 443a15de94b5..ab5e25aaeee3 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -28,6 +28,9 @@
#include <linux/firmware.h>
#include <sound/pcm.h>
#include "../common/sst-acpi.h"
+#include <sound/hda_register.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_i915.h>
#include "skl.h"
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
@@ -243,6 +246,16 @@ static int skl_resume(struct device *dev)
struct hdac_bus *bus = ebus_to_hbus(ebus);
int ret;
+ /* Turned OFF in HDMI codec driver after codec reconfiguration */
+ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
+ ret = snd_hdac_display_power(bus, true);
+ if (ret < 0) {
+ dev_err(bus->dev,
+ "Cannot turn on display power on i915\n");
+ return ret;
+ }
+ }
+
/*
* resume only when we are not in suspend active, otherwise need to
* restore the device
@@ -481,6 +494,27 @@ static int skl_create(struct pci_dev *pci,
return 0;
}
+static int skl_i915_init(struct hdac_bus *bus)
+{
+ int err;
+
+ /*
+ * The HDMI codec is in GPU so we need to ensure that it is powered
+ * up and ready for probe
+ */
+ err = snd_hdac_i915_init(bus);
+ if (err < 0)
+ return err;
+
+ err = snd_hdac_display_power(bus, true);
+ if (err < 0) {
+ dev_err(bus->dev, "Cannot turn on display power on i915\n");
+ return err;
+ }
+
+ return err;
+}
+
static int skl_first_init(struct hdac_ext_bus *ebus)
{
struct skl *skl = ebus_to_skl(ebus);
@@ -543,6 +577,12 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
/* initialize chip */
skl_init_pci(skl);
+ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
+ err = skl_i915_init(bus);
+ if (err < 0)
+ return err;
+ }
+
skl_init_chip(bus, true);
/* codec detection */
@@ -573,11 +613,15 @@ static int skl_probe(struct pci_dev *pci,
if (err < 0)
goto out_free;
+ skl->pci_id = pci->device;
+
skl->nhlt = skl_nhlt_init(bus->dev);
if (skl->nhlt == NULL)
goto out_free;
+ skl_nhlt_update_topology_bin(skl);
+
pci_set_drvdata(skl->pci, ebus);
/* check if dsp is there */
@@ -613,9 +657,15 @@ static int skl_probe(struct pci_dev *pci,
if (err < 0)
goto out_unregister;
+ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
+ err = snd_hdac_display_power(bus, false);
+ if (err < 0) {
+ dev_err(bus->dev, "Cannot turn off display power on i915\n");
+ return err;
+ }
+ }
+
/*configure PM */
- pm_runtime_set_autosuspend_delay(bus->dev, SKL_SUSPEND_DELAY);
- pm_runtime_use_autosuspend(bus->dev);
pm_runtime_put_noidle(bus->dev);
pm_runtime_allow(bus->dev);
@@ -636,6 +686,31 @@ out_free:
return err;
}
+static void skl_shutdown(struct pci_dev *pci)
+{
+ struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+ struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_stream *s;
+ struct hdac_ext_stream *stream;
+ struct skl *skl;
+
+ if (ebus == NULL)
+ return;
+
+ skl = ebus_to_skl(ebus);
+
+ if (skl->init_failed)
+ return;
+
+ snd_hdac_ext_stop_streams(ebus);
+ list_for_each_entry(s, &bus->stream_list, list) {
+ stream = stream_to_hdac_ext_stream(s);
+ snd_hdac_ext_stream_decouple(ebus, stream, false);
+ }
+
+ snd_hdac_bus_stop_chip(bus);
+}
+
static void skl_remove(struct pci_dev *pci)
{
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
@@ -644,6 +719,9 @@ static void skl_remove(struct pci_dev *pci)
if (skl->tplg)
release_firmware(skl->tplg);
+ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
+ snd_hdac_i915_exit(&ebus->bus);
+
if (pci_dev_run_wake(pci))
pm_runtime_get_noresume(&pci->dev);
pci_dev_put(pci);
@@ -664,11 +742,18 @@ static struct sst_acpi_mach sst_skl_devdata[] = {
{}
};
+static struct sst_acpi_mach sst_bxtp_devdata[] = {
+ { "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL },
+};
+
/* PCI IDs */
static const struct pci_device_id skl_ids[] = {
/* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70),
.driver_data = (unsigned long)&sst_skl_devdata},
+ /* BXT-P */
+ { PCI_DEVICE(0x8086, 0x5a98),
+ .driver_data = (unsigned long)&sst_bxtp_devdata},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, skl_ids);
@@ -679,6 +764,7 @@ static struct pci_driver skl_driver = {
.id_table = skl_ids,
.probe = skl_probe,
.remove = skl_remove,
+ .shutdown = skl_shutdown,
.driver = {
.pm = &skl_pm,
},
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 4d18293b5537..39e16fa7a92b 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -73,6 +73,8 @@ struct skl {
struct list_head ppl_list;
const char *fw_name;
+ char tplg_name[64];
+ unsigned short pci_id;
const struct firmware *tplg;
int supend_active;
@@ -88,6 +90,16 @@ struct skl_dma_params {
u8 stream_tag;
};
+struct skl_dsp_ops {
+ int id;
+ struct skl_dsp_loader_ops (*loader_ops)(void);
+ int (*init)(struct device *dev, void __iomem *mmio_base,
+ int irq, const char *fw_name,
+ struct skl_dsp_loader_ops loader_ops,
+ struct skl_sst **skl_sst);
+ void (*cleanup)(struct device *dev, struct skl_sst *ctx);
+};
+
int skl_platform_unregister(struct device *dev);
int skl_platform_register(struct device *dev);
@@ -96,8 +108,9 @@ void skl_nhlt_free(void *addr);
struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance,
u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn);
+int skl_nhlt_update_topology_bin(struct skl *skl);
int skl_init_dsp(struct skl *skl);
-void skl_free_dsp(struct skl *skl);
+int skl_free_dsp(struct skl *skl);
int skl_suspend_dsp(struct skl *skl);
int skl_resume_dsp(struct skl *skl);
#endif /* __SOUND_SOC_SKL_H */
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 15c04e2eae34..976967675387 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -9,7 +9,7 @@ config SND_SOC_MEDIATEK
config SND_SOC_MT8173_MAX98090
tristate "ASoC Audio driver for MT8173 with MAX98090 codec"
- depends on SND_SOC_MEDIATEK
+ depends on SND_SOC_MEDIATEK && I2C
select SND_SOC_MAX98090
help
This adds ASoC driver for Mediatek MT8173 boards
@@ -19,7 +19,7 @@ config SND_SOC_MT8173_MAX98090
config SND_SOC_MT8173_RT5650_RT5676
tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs"
- depends on SND_SOC_MEDIATEK
+ depends on SND_SOC_MEDIATEK && I2C
select SND_SOC_RT5645
select SND_SOC_RT5677
help
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index c866ade28ad0..a6c7b8d87cd2 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -381,9 +381,19 @@ static int mxs_saif_startup(struct snd_pcm_substream *substream,
__raw_writel(BM_SAIF_CTRL_CLKGATE,
saif->base + SAIF_CTRL + MXS_CLR_ADDR);
+ clk_prepare(saif->clk);
+
return 0;
}
+static void mxs_saif_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+ clk_unprepare(saif->clk);
+}
+
/*
* Should only be called when port is inactive.
* although can be called multiple times by upper layers.
@@ -424,8 +434,6 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- /* prepare clk in hw_param, enable in trigger */
- clk_prepare(saif->clk);
if (saif != master_saif) {
/*
* Set an initial clock rate for the saif internal logic to work
@@ -611,6 +619,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
static const struct snd_soc_dai_ops mxs_saif_dai_ops = {
.startup = mxs_saif_startup,
+ .shutdown = mxs_saif_shutdown,
.trigger = mxs_saif_trigger,
.prepare = mxs_saif_prepare,
.hw_params = mxs_saif_hw_params,
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 190f868e78b2..fdecb7043174 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -133,7 +133,7 @@ static struct snd_soc_ops n810_ops = {
static int n810_get_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = n810_spk_func;
+ ucontrol->value.enumerated.item[0] = n810_spk_func;
return 0;
}
@@ -143,10 +143,10 @@ static int n810_set_spk(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (n810_spk_func == ucontrol->value.integer.value[0])
+ if (n810_spk_func == ucontrol->value.enumerated.item[0])
return 0;
- n810_spk_func = ucontrol->value.integer.value[0];
+ n810_spk_func = ucontrol->value.enumerated.item[0];
n810_ext_control(&card->dapm);
return 1;
@@ -155,7 +155,7 @@ static int n810_set_spk(struct snd_kcontrol *kcontrol,
static int n810_get_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = n810_jack_func;
+ ucontrol->value.enumerated.item[0] = n810_jack_func;
return 0;
}
@@ -165,10 +165,10 @@ static int n810_set_jack(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (n810_jack_func == ucontrol->value.integer.value[0])
+ if (n810_jack_func == ucontrol->value.enumerated.item[0])
return 0;
- n810_jack_func = ucontrol->value.integer.value[0];
+ n810_jack_func = ucontrol->value.enumerated.item[0];
n810_ext_control(&card->dapm);
return 1;
@@ -177,7 +177,7 @@ static int n810_set_jack(struct snd_kcontrol *kcontrol,
static int n810_get_input(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = n810_dmic_func;
+ ucontrol->value.enumerated.item[0] = n810_dmic_func;
return 0;
}
@@ -187,10 +187,10 @@ static int n810_set_input(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (n810_dmic_func == ucontrol->value.integer.value[0])
+ if (n810_dmic_func == ucontrol->value.enumerated.item[0])
return 0;
- n810_dmic_func = ucontrol->value.integer.value[0];
+ n810_dmic_func = ucontrol->value.enumerated.item[0];
n810_ext_control(&card->dapm);
return 1;
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 5e21f08579d8..54949242bc70 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -132,7 +132,7 @@ static struct snd_soc_ops rx51_ops = {
static int rx51_get_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = rx51_spk_func;
+ ucontrol->value.enumerated.item[0] = rx51_spk_func;
return 0;
}
@@ -142,10 +142,10 @@ static int rx51_set_spk(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (rx51_spk_func == ucontrol->value.integer.value[0])
+ if (rx51_spk_func == ucontrol->value.enumerated.item[0])
return 0;
- rx51_spk_func = ucontrol->value.integer.value[0];
+ rx51_spk_func = ucontrol->value.enumerated.item[0];
rx51_ext_control(&card->dapm);
return 1;
@@ -180,7 +180,7 @@ static int rx51_hp_event(struct snd_soc_dapm_widget *w,
static int rx51_get_input(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = rx51_dmic_func;
+ ucontrol->value.enumerated.item[0] = rx51_dmic_func;
return 0;
}
@@ -190,10 +190,10 @@ static int rx51_set_input(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (rx51_dmic_func == ucontrol->value.integer.value[0])
+ if (rx51_dmic_func == ucontrol->value.enumerated.item[0])
return 0;
- rx51_dmic_func = ucontrol->value.integer.value[0];
+ rx51_dmic_func = ucontrol->value.enumerated.item[0];
rx51_ext_control(&card->dapm);
return 1;
@@ -202,7 +202,7 @@ static int rx51_set_input(struct snd_kcontrol *kcontrol,
static int rx51_get_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = rx51_jack_func;
+ ucontrol->value.enumerated.item[0] = rx51_jack_func;
return 0;
}
@@ -212,10 +212,10 @@ static int rx51_set_jack(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (rx51_jack_func == ucontrol->value.integer.value[0])
+ if (rx51_jack_func == ucontrol->value.enumerated.item[0])
return 0;
- rx51_jack_func = ucontrol->value.integer.value[0];
+ rx51_jack_func = ucontrol->value.enumerated.item[0];
rx51_ext_control(&card->dapm);
return 1;
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index c97dc13d3608..dcbb7aa9830c 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -163,7 +163,7 @@ static struct snd_soc_ops corgi_ops = {
static int corgi_get_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = corgi_jack_func;
+ ucontrol->value.enumerated.item[0] = corgi_jack_func;
return 0;
}
@@ -172,10 +172,10 @@ static int corgi_set_jack(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (corgi_jack_func == ucontrol->value.integer.value[0])
+ if (corgi_jack_func == ucontrol->value.enumerated.item[0])
return 0;
- corgi_jack_func = ucontrol->value.integer.value[0];
+ corgi_jack_func = ucontrol->value.enumerated.item[0];
corgi_ext_control(&card->dapm);
return 1;
}
@@ -183,7 +183,7 @@ static int corgi_set_jack(struct snd_kcontrol *kcontrol,
static int corgi_get_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = corgi_spk_func;
+ ucontrol->value.enumerated.item[0] = corgi_spk_func;
return 0;
}
@@ -192,10 +192,10 @@ static int corgi_set_spk(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (corgi_spk_func == ucontrol->value.integer.value[0])
+ if (corgi_spk_func == ucontrol->value.enumerated.item[0])
return 0;
- corgi_spk_func = ucontrol->value.integer.value[0];
+ corgi_spk_func = ucontrol->value.enumerated.item[0];
corgi_ext_control(&card->dapm);
return 1;
}
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 241d0be42d7a..62b8377a9d2b 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -308,17 +308,17 @@ static int magician_set_spk(struct snd_kcontrol *kcontrol,
static int magician_get_input(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = magician_in_sel;
+ ucontrol->value.enumerated.item[0] = magician_in_sel;
return 0;
}
static int magician_set_input(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- if (magician_in_sel == ucontrol->value.integer.value[0])
+ if (magician_in_sel == ucontrol->value.enumerated.item[0])
return 0;
- magician_in_sel = ucontrol->value.integer.value[0];
+ magician_in_sel = ucontrol->value.enumerated.item[0];
switch (magician_in_sel) {
case MAGICIAN_MIC:
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index 84d0e2e50808..4b3b714f5ee7 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -138,7 +138,7 @@ static struct snd_soc_ops poodle_ops = {
static int poodle_get_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = poodle_jack_func;
+ ucontrol->value.enumerated.item[0] = poodle_jack_func;
return 0;
}
@@ -147,10 +147,10 @@ static int poodle_set_jack(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (poodle_jack_func == ucontrol->value.integer.value[0])
+ if (poodle_jack_func == ucontrol->value.enumerated.item[0])
return 0;
- poodle_jack_func = ucontrol->value.integer.value[0];
+ poodle_jack_func = ucontrol->value.enumerated.item[0];
poodle_ext_control(&card->dapm);
return 1;
}
@@ -158,7 +158,7 @@ static int poodle_set_jack(struct snd_kcontrol *kcontrol,
static int poodle_get_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = poodle_spk_func;
+ ucontrol->value.enumerated.item[0] = poodle_spk_func;
return 0;
}
@@ -167,10 +167,10 @@ static int poodle_set_spk(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (poodle_spk_func == ucontrol->value.integer.value[0])
+ if (poodle_spk_func == ucontrol->value.enumerated.item[0])
return 0;
- poodle_spk_func = ucontrol->value.integer.value[0];
+ poodle_spk_func = ucontrol->value.enumerated.item[0];
poodle_ext_control(&card->dapm);
return 1;
}
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index b00222620fd0..0e02634c8b7f 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -164,7 +164,7 @@ static struct snd_soc_ops spitz_ops = {
static int spitz_get_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = spitz_jack_func;
+ ucontrol->value.enumerated.item[0] = spitz_jack_func;
return 0;
}
@@ -173,10 +173,10 @@ static int spitz_set_jack(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (spitz_jack_func == ucontrol->value.integer.value[0])
+ if (spitz_jack_func == ucontrol->value.enumerated.item[0])
return 0;
- spitz_jack_func = ucontrol->value.integer.value[0];
+ spitz_jack_func = ucontrol->value.enumerated.item[0];
spitz_ext_control(&card->dapm);
return 1;
}
@@ -184,7 +184,7 @@ static int spitz_set_jack(struct snd_kcontrol *kcontrol,
static int spitz_get_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = spitz_spk_func;
+ ucontrol->value.enumerated.item[0] = spitz_spk_func;
return 0;
}
@@ -193,10 +193,10 @@ static int spitz_set_spk(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (spitz_spk_func == ucontrol->value.integer.value[0])
+ if (spitz_spk_func == ucontrol->value.enumerated.item[0])
return 0;
- spitz_spk_func = ucontrol->value.integer.value[0];
+ spitz_spk_func = ucontrol->value.enumerated.item[0];
spitz_ext_control(&card->dapm);
return 1;
}
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index 49518dd642aa..c508f024ecfb 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -95,7 +95,7 @@ static struct snd_soc_ops tosa_ops = {
static int tosa_get_jack(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = tosa_jack_func;
+ ucontrol->value.enumerated.item[0] = tosa_jack_func;
return 0;
}
@@ -104,10 +104,10 @@ static int tosa_set_jack(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (tosa_jack_func == ucontrol->value.integer.value[0])
+ if (tosa_jack_func == ucontrol->value.enumerated.item[0])
return 0;
- tosa_jack_func = ucontrol->value.integer.value[0];
+ tosa_jack_func = ucontrol->value.enumerated.item[0];
tosa_ext_control(&card->dapm);
return 1;
}
@@ -115,7 +115,7 @@ static int tosa_set_jack(struct snd_kcontrol *kcontrol,
static int tosa_get_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- ucontrol->value.integer.value[0] = tosa_spk_func;
+ ucontrol->value.enumerated.item[0] = tosa_spk_func;
return 0;
}
@@ -124,10 +124,10 @@ static int tosa_set_spk(struct snd_kcontrol *kcontrol,
{
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
- if (tosa_spk_func == ucontrol->value.integer.value[0])
+ if (tosa_spk_func == ucontrol->value.enumerated.item[0])
return 0;
- tosa_spk_func = ucontrol->value.integer.value[0];
+ tosa_spk_func = ucontrol->value.enumerated.item[0];
tosa_ext_control(&card->dapm);
return 1;
}
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 00b6c9d039cf..e5101e0d2d37 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -355,7 +355,6 @@ static struct regmap_config lpass_cpu_regmap_config = {
.readable_reg = lpass_cpu_regmap_readable,
.volatile_reg = lpass_cpu_regmap_volatile,
.cache_type = REGCACHE_FLAT,
- .val_format_endian = REGMAP_ENDIAN_LITTLE,
};
int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 79688aa1941a..4aeb8e1a7160 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -440,18 +440,18 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
}
static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
- struct snd_soc_pcm_runtime *soc_runtime)
+ struct snd_soc_pcm_runtime *rt)
{
struct snd_dma_buffer *buf = &substream->dma_buffer;
size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
- buf->dev.dev = soc_runtime->dev;
+ buf->dev.dev = rt->platform->dev;
buf->private_data = NULL;
- buf->area = dma_alloc_coherent(soc_runtime->dev, size, &buf->addr,
+ buf->area = dma_alloc_coherent(rt->platform->dev, size, &buf->addr,
GFP_KERNEL);
if (!buf->area) {
- dev_err(soc_runtime->dev, "%s: Could not allocate DMA buffer\n",
+ dev_err(rt->platform->dev, "%s: Could not allocate DMA buffer\n",
__func__);
return -ENOMEM;
}
@@ -461,12 +461,12 @@ static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
}
static void lpass_platform_free_buffer(struct snd_pcm_substream *substream,
- struct snd_soc_pcm_runtime *soc_runtime)
+ struct snd_soc_pcm_runtime *rt)
{
struct snd_dma_buffer *buf = &substream->dma_buffer;
if (buf->area) {
- dma_free_coherent(soc_runtime->dev, buf->bytes, buf->area,
+ dma_free_coherent(rt->dev, buf->bytes, buf->area,
buf->addr);
}
buf->area = NULL;
@@ -499,9 +499,6 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
snd_soc_pcm_set_drvdata(soc_runtime, data);
- soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;
-
ret = lpass_platform_alloc_buffer(substream, soc_runtime);
if (ret)
return ret;
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 84d9e77c0fbe..70a2559b63f9 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -481,10 +481,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
u32 mod, mask, val = 0;
+ unsigned long flags;
- spin_lock(i2s->lock);
+ spin_lock_irqsave(i2s->lock, flags);
mod = readl(i2s->addr + I2SMOD);
- spin_unlock(i2s->lock);
+ spin_unlock_irqrestore(i2s->lock, flags);
switch (clk_id) {
case SAMSUNG_I2S_OPCLK:
@@ -575,11 +576,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
return -EINVAL;
}
- spin_lock(i2s->lock);
+ spin_lock_irqsave(i2s->lock, flags);
mod = readl(i2s->addr + I2SMOD);
mod = (mod & ~mask) | val;
writel(mod, i2s->addr + I2SMOD);
- spin_unlock(i2s->lock);
+ spin_unlock_irqrestore(i2s->lock, flags);
return 0;
}
@@ -590,6 +591,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
struct i2s_dai *i2s = to_info(dai);
int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
u32 mod, tmp = 0;
+ unsigned long flags;
lrp_shift = i2s->variant_regs->lrp_off;
sdf_shift = i2s->variant_regs->sdf_off;
@@ -649,7 +651,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
return -EINVAL;
}
- spin_lock(i2s->lock);
+ spin_lock_irqsave(i2s->lock, flags);
mod = readl(i2s->addr + I2SMOD);
/*
* Don't change the I2S mode if any controller is active on this
@@ -657,7 +659,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
*/
if (any_active(i2s) &&
((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
- spin_unlock(i2s->lock);
+ spin_unlock_irqrestore(i2s->lock, flags);
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN;
@@ -666,7 +668,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
mod &= ~(sdf_mask | lrp_rlow | mod_slave);
mod |= tmp;
writel(mod, i2s->addr + I2SMOD);
- spin_unlock(i2s->lock);
+ spin_unlock_irqrestore(i2s->lock, flags);
return 0;
}
@@ -676,6 +678,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
{
struct i2s_dai *i2s = to_info(dai);
u32 mod, mask = 0, val = 0;
+ unsigned long flags;
if (!is_secondary(i2s))
mask |= (MOD_DC2_EN | MOD_DC1_EN);
@@ -744,11 +747,11 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- spin_lock(i2s->lock);
+ spin_lock_irqsave(i2s->lock, flags);
mod = readl(i2s->addr + I2SMOD);
mod = (mod & ~mask) | val;
writel(mod, i2s->addr + I2SMOD);
- spin_unlock(i2s->lock);
+ spin_unlock_irqrestore(i2s->lock, flags);
samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 790ee2bf1a47..d2e62b159610 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -986,16 +986,16 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
- rtd = soc_new_pcm_runtime(card, dai_link);
- if (!rtd)
- return -ENOMEM;
-
if (soc_is_dai_link_bound(card, dai_link)) {
dev_dbg(card->dev, "ASoC: dai link %s already bound\n",
dai_link->name);
return 0;
}
+ rtd = soc_new_pcm_runtime(card, dai_link);
+ if (!rtd)
+ return -ENOMEM;
+
cpu_dai_component.name = dai_link->cpu_name;
cpu_dai_component.of_node = dai_link->cpu_of_node;
cpu_dai_component.dai_name = dai_link->cpu_dai_name;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 5a2812fa8946..801ae1a81dfd 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -310,7 +310,7 @@ struct dapm_kcontrol_data {
};
static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
- struct snd_kcontrol *kcontrol)
+ struct snd_kcontrol *kcontrol, const char *ctrl_name)
{
struct dapm_kcontrol_data *data;
struct soc_mixer_control *mc;
@@ -333,7 +333,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
if (mc->autodisable) {
struct snd_soc_dapm_widget template;
- name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+ name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
"Autodisable");
if (!name) {
ret = -ENOMEM;
@@ -371,7 +371,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
if (e->autodisable) {
struct snd_soc_dapm_widget template;
- name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+ name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
"Autodisable");
if (!name) {
ret = -ENOMEM;
@@ -871,7 +871,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
kcontrol->private_free = dapm_kcontrol_free;
- ret = dapm_kcontrol_data_alloc(w, kcontrol);
+ ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
if (ret) {
snd_ctl_free_one(kcontrol);
goto exit_free;
@@ -2805,7 +2805,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num)
{
- int i, ret = 0;
+ int i;
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
@@ -2814,7 +2814,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
}
mutex_unlock(&dapm->card->dapm_mutex);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
@@ -3573,7 +3573,7 @@ static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = w->params_select;
+ ucontrol->value.enumerated.item[0] = w->params_select;
return 0;
}
@@ -3587,13 +3587,13 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
if (w->power)
return -EBUSY;
- if (ucontrol->value.integer.value[0] == w->params_select)
+ if (ucontrol->value.enumerated.item[0] == w->params_select)
return 0;
- if (ucontrol->value.integer.value[0] >= w->num_params)
+ if (ucontrol->value.enumerated.item[0] >= w->num_params)
return -EINVAL;
- w->params_select = ucontrol->value.integer.value[0];
+ w->params_select = ucontrol->value.enumerated.item[0];
return 0;
}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index e898b427be7e..aa99dac31b3b 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1810,7 +1810,8 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
(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))
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
continue;
dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
@@ -1866,18 +1867,6 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
if (!snd_soc_dpcm_be_can_update(fe, be, stream))
continue;
- /* only allow hw_params() if no connected FEs are running */
- if (!snd_soc_dpcm_can_be_params(fe, be, stream))
- continue;
-
- if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
- (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
- (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
- continue;
-
- dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
- dpcm->fe->dai_link->name);
-
/* copy params for each dpcm */
memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
sizeof(struct snd_pcm_hw_params));
@@ -1894,6 +1883,18 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
}
}
+ /* only allow hw_params() if no connected FEs are running */
+ if (!snd_soc_dpcm_can_be_params(fe, be, stream))
+ continue;
+
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
+ continue;
+
+ dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
+ dpcm->fe->dai_link->name);
+
ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
if (ret < 0) {
dev_err(dpcm->be->dev,