summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/Kconfig6
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ab8500-codec.c73
-rw-r--r--sound/soc/codecs/ac97.c15
-rw-r--r--sound/soc/codecs/adau1373.c21
-rw-r--r--sound/soc/codecs/adau1761.c2
-rw-r--r--sound/soc/codecs/adau1781.c2
-rw-r--r--sound/soc/codecs/adau17x1.c8
-rw-r--r--sound/soc/codecs/adau17x1.h1
-rw-r--r--sound/soc/codecs/adav80x.c23
-rw-r--r--sound/soc/codecs/arizona.c6
-rw-r--r--sound/soc/codecs/cs35l32.c631
-rw-r--r--sound/soc/codecs/cs35l32.h93
-rw-r--r--sound/soc/codecs/cs4265.c19
-rw-r--r--sound/soc/codecs/cs42l52.c4
-rw-r--r--sound/soc/codecs/cs42l56.c7
-rw-r--r--sound/soc/codecs/da732x.c2
-rw-r--r--sound/soc/codecs/da732x.h2
-rw-r--r--sound/soc/codecs/es8328.c6
-rw-r--r--sound/soc/codecs/lm49453.c14
-rw-r--r--sound/soc/codecs/max98090.c115
-rw-r--r--sound/soc/codecs/max98090.h3
-rw-r--r--sound/soc/codecs/pcm512x.c4
-rw-r--r--sound/soc/codecs/rt286.c7
-rw-r--r--sound/soc/codecs/rt5640.c50
-rw-r--r--sound/soc/codecs/rt5640.h3
-rw-r--r--sound/soc/codecs/rt5677.c195
-rw-r--r--sound/soc/codecs/rt5677.h166
-rw-r--r--sound/soc/codecs/ssm2518.c13
-rw-r--r--sound/soc/codecs/ssm2602.c26
-rw-r--r--sound/soc/codecs/sta529.c4
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c51
-rw-r--r--sound/soc/codecs/tlv320aic3x.c16
-rw-r--r--sound/soc/codecs/wm5100.c5
-rw-r--r--sound/soc/codecs/wm8350.c2
-rw-r--r--sound/soc/codecs/wm8753.c2
-rw-r--r--sound/soc/codecs/wm8804.c19
-rw-r--r--sound/soc/codecs/wm8903.c6
-rw-r--r--sound/soc/codecs/wm8962.c5
-rw-r--r--sound/soc/codecs/wm8971.c2
-rw-r--r--sound/soc/codecs/wm8995.c19
-rw-r--r--sound/soc/codecs/wm8996.c6
-rw-r--r--sound/soc/davinci/Kconfig3
-rw-r--r--sound/soc/davinci/davinci-mcasp.c104
-rw-r--r--sound/soc/davinci/edma-pcm.c2
-rw-r--r--sound/soc/dwc/designware_i2s.c4
-rw-r--r--sound/soc/fsl/Kconfig4
-rw-r--r--sound/soc/fsl/fsl_esai.c16
-rw-r--r--sound/soc/fsl/fsl_esai.h8
-rw-r--r--sound/soc/fsl/fsl_ssi.c101
-rw-r--r--sound/soc/generic/simple-card.c8
-rw-r--r--sound/soc/intel/Makefile3
-rw-r--r--sound/soc/intel/byt-max98090.c1
-rw-r--r--sound/soc/intel/byt-rt5640.c83
-rw-r--r--sound/soc/intel/sst-acpi.c4
-rw-r--r--sound/soc/intel/sst-atom-controls.c218
-rw-r--r--sound/soc/intel/sst-atom-controls.h416
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.c10
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.h1
-rw-r--r--sound/soc/intel/sst-baytrail-pcm.c43
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c56
-rw-r--r--sound/soc/intel/sst-mfld-platform-compress.c38
-rw-r--r--sound/soc/intel/sst-mfld-platform-pcm.c106
-rw-r--r--sound/soc/intel/sst-mfld-platform.h58
-rw-r--r--sound/soc/omap/omap-twl4030.c2
-rw-r--r--sound/soc/omap/rx51.c2
-rw-r--r--sound/soc/pxa/pxa-ssp.c4
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c13
-rw-r--r--sound/soc/samsung/i2s.c5
-rw-r--r--sound/soc/samsung/speyside.c6
-rw-r--r--sound/soc/sh/rcar/gen.c2
-rw-r--r--sound/soc/soc-compress.c6
-rw-r--r--sound/soc/soc-core.c673
-rw-r--r--sound/soc/soc-dapm.c38
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c4
-rw-r--r--sound/soc/soc-io.c28
-rw-r--r--sound/soc/soc-pcm.c6
-rw-r--r--sound/soc/spear/spear_pcm.c4
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h2
79 files changed, 2744 insertions, 994 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 8bca6343d8a3..7678122f8fe0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ALC5623 if I2C
select SND_SOC_ALC5632 if I2C
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
+ select SND_SOC_CS35L32 if I2C
select SND_SOC_CS42L51_I2C if I2C
select SND_SOC_CS42L52 if I2C && INPUT
select SND_SOC_CS42L56 if I2C && INPUT
@@ -56,6 +57,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_DA7213 if I2C
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
+ select SND_SOC_DMIC
select SND_SOC_BT_SCO
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
@@ -325,6 +327,10 @@ config SND_SOC_ALC5632
config SND_SOC_CQ0093VC
tristate
+config SND_SOC_CS35L32
+ tristate "Cirrus Logic CS35L32 CODEC"
+ depends on I2C
+
config SND_SOC_CS42L51
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 31a8283006d1..afba944657bc 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -32,6 +32,7 @@ snd-soc-ak4671-objs := ak4671.o
snd-soc-ak5386-objs := ak5386.o
snd-soc-arizona-objs := arizona.o
snd-soc-cq93vc-objs := cq93vc.o
+snd-soc-cs35l32-objs := cs35l32.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
snd-soc-cs42l52-objs := cs42l52.o
@@ -206,6 +207,7 @@ obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 1fb4402bf72d..fd43827bb856 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -56,8 +56,7 @@
#define GPIO31_DIR_OUTPUT 0x40
/* Macrocell register definitions */
-#define AB8500_CTRL3_REG 0x0200
-#define AB8500_GPIO_DIR4_REG 0x1013
+#define AB8500_GPIO_DIR4_REG 0x13 /* Bank AB8500_MISC */
/* Nr of FIR/IIR-coeff banks in ANC-block */
#define AB8500_NR_OF_ANC_COEFF_BANKS 2
@@ -126,6 +125,8 @@ struct ab8500_codec_drvdata_dbg {
/* Private data for AB8500 device-driver */
struct ab8500_codec_drvdata {
+ struct regmap *regmap;
+
/* Sidetone */
long *sid_fir_values;
enum sid_state sid_status;
@@ -166,49 +167,35 @@ static inline const char *amic_type_str(enum amic_type type)
*/
/* Read a register from the audio-bank of AB8500 */
-static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec,
- unsigned int reg)
+static int ab8500_codec_read_reg(void *context, unsigned int reg,
+ unsigned int *value)
{
+ struct device *dev = context;
int status;
- unsigned int value = 0;
u8 value8;
- status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO,
- reg, &value8);
- if (status < 0) {
- dev_err(codec->dev,
- "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n",
- __func__, (u8)AB8500_AUDIO, (u8)reg, status);
- } else {
- dev_dbg(codec->dev,
- "%s: Read 0x%02x from register 0x%02x:0x%02x\n",
- __func__, value8, (u8)AB8500_AUDIO, (u8)reg);
- value = (unsigned int)value8;
- }
+ status = abx500_get_register_interruptible(dev, AB8500_AUDIO,
+ reg, &value8);
+ *value = (unsigned int)value8;
- return value;
+ return status;
}
/* Write to a register in the audio-bank of AB8500 */
-static int ab8500_codec_write_reg(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
+static int ab8500_codec_write_reg(void *context, unsigned int reg,
+ unsigned int value)
{
- int status;
-
- status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO,
- reg, value);
- if (status < 0)
- dev_err(codec->dev,
- "%s: ERROR: Register (%02x:%02x) write failed (%d).\n",
- __func__, (u8)AB8500_AUDIO, (u8)reg, status);
- else
- dev_dbg(codec->dev,
- "%s: Wrote 0x%02x into register %02x:%02x\n",
- __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg);
+ struct device *dev = context;
- return status;
+ return abx500_set_register_interruptible(dev, AB8500_AUDIO,
+ reg, value);
}
+static const struct regmap_config ab8500_codec_regmap = {
+ .reg_read = ab8500_codec_read_reg,
+ .reg_write = ab8500_codec_write_reg,
+};
+
/*
* Controls - DAPM
*/
@@ -1968,16 +1955,16 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec,
dev_dbg(codec->dev, "%s: Enter.\n", __func__);
/* Set DMic-clocks to outputs */
- status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC,
- (u8)AB8500_GPIO_DIR4_REG,
+ status = abx500_get_register_interruptible(codec->dev, AB8500_MISC,
+ AB8500_GPIO_DIR4_REG,
&value8);
if (status < 0)
return status;
value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT |
GPIO31_DIR_OUTPUT;
status = abx500_set_register_interruptible(codec->dev,
- (u8)AB8500_MISC,
- (u8)AB8500_GPIO_DIR4_REG,
+ AB8500_MISC,
+ AB8500_GPIO_DIR4_REG,
value);
if (status < 0)
return status;
@@ -2565,9 +2552,6 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver ab8500_codec_driver = {
.probe = ab8500_codec_probe,
- .read = ab8500_codec_read_reg,
- .write = ab8500_codec_write_reg,
- .reg_word_size = sizeof(u8),
.controls = ab8500_ctrls,
.num_controls = ARRAY_SIZE(ab8500_ctrls),
.dapm_widgets = ab8500_dapm_widgets,
@@ -2592,6 +2576,15 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)
drvdata->anc_status = ANC_UNCONFIGURED;
dev_set_drvdata(&pdev->dev, drvdata);
+ drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev,
+ &ab8500_codec_regmap);
+ if (IS_ERR(drvdata->regmap)) {
+ status = PTR_ERR(drvdata->regmap);
+ dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n",
+ __func__, status);
+ return status;
+ }
+
dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__);
status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver,
ab8500_codec_dai,
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index e889e1b84192..bd9b1839c8b0 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -69,19 +69,6 @@ static struct snd_soc_dai_driver ac97_dai = {
.ops = &ac97_dai_ops,
};
-static unsigned int ac97_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- return soc_ac97_ops->read(codec->ac97, reg);
-}
-
-static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int val)
-{
- soc_ac97_ops->write(codec->ac97, reg, val);
- return 0;
-}
-
static int ac97_soc_probe(struct snd_soc_codec *codec)
{
struct snd_ac97_bus *ac97_bus;
@@ -122,8 +109,6 @@ static int ac97_soc_resume(struct snd_soc_codec *codec)
#endif
static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
- .write = ac97_write,
- .read = ac97_read,
.probe = ac97_soc_probe,
.suspend = ac97_soc_suspend,
.resume = ac97_soc_resume,
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 1ff7d4d027e9..7c784ad3e8b2 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -1448,29 +1448,10 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int adau1373_remove(struct snd_soc_codec *codec)
-{
- adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int adau1373_suspend(struct snd_soc_codec *codec)
-{
- struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
- regcache_cache_only(adau1373->regmap, true);
-
- return ret;
-}
-
static int adau1373_resume(struct snd_soc_codec *codec)
{
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
- regcache_cache_only(adau1373->regmap, false);
- adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
regcache_sync(adau1373->regmap);
return 0;
@@ -1501,8 +1482,6 @@ static const struct regmap_config adau1373_regmap_config = {
static struct snd_soc_codec_driver adau1373_codec_driver = {
.probe = adau1373_probe,
- .remove = adau1373_remove,
- .suspend = adau1373_suspend,
.resume = adau1373_resume,
.set_bias_level = adau1373_set_bias_level,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index 848cab839553..5518ebd6947c 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -714,9 +714,9 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
static const struct snd_soc_codec_driver adau1761_codec_driver = {
.probe = adau1761_codec_probe,
- .suspend = adau17x1_suspend,
.resume = adau17x1_resume,
.set_bias_level = adau1761_set_bias_level,
+ .suspend_bias_off = true,
.controls = adau1761_controls,
.num_controls = ARRAY_SIZE(adau1761_controls),
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
index 045a61413840..e9fc00fb13dd 100644
--- a/sound/soc/codecs/adau1781.c
+++ b/sound/soc/codecs/adau1781.c
@@ -446,9 +446,9 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
static const struct snd_soc_codec_driver adau1781_codec_driver = {
.probe = adau1781_codec_probe,
- .suspend = adau17x1_suspend,
.resume = adau17x1_resume,
.set_bias_level = adau1781_set_bias_level,
+ .suspend_bias_off = true,
.controls = adau1781_controls,
.num_controls = ARRAY_SIZE(adau1781_controls),
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 0b659704e60c..3e16c1c64115 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -815,13 +815,6 @@ int adau17x1_add_routes(struct snd_soc_codec *codec)
}
EXPORT_SYMBOL_GPL(adau17x1_add_routes);
-int adau17x1_suspend(struct snd_soc_codec *codec)
-{
- codec->driver->set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-EXPORT_SYMBOL_GPL(adau17x1_suspend);
-
int adau17x1_resume(struct snd_soc_codec *codec)
{
struct adau *adau = snd_soc_codec_get_drvdata(codec);
@@ -829,7 +822,6 @@ int adau17x1_resume(struct snd_soc_codec *codec)
if (adau->switch_mode)
adau->switch_mode(codec->dev);
- codec->driver->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
regcache_sync(adau->regmap);
return 0;
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h
index 3ffabaf4c7a8..e4a557fd7155 100644
--- a/sound/soc/codecs/adau17x1.h
+++ b/sound/soc/codecs/adau17x1.h
@@ -52,7 +52,6 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
enum adau17x1_micbias_voltage micbias);
bool adau17x1_readable_register(struct device *dev, unsigned int reg);
bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
-int adau17x1_suspend(struct snd_soc_codec *codec);
int adau17x1_resume(struct snd_soc_codec *codec);
extern const struct snd_soc_dai_ops adau17x1_dai_ops;
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index c43b93fdf0df..ce3cdca9fc62 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -812,42 +812,23 @@ static int adav80x_probe(struct snd_soc_codec *codec)
/* Disable DAC zero flag */
regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6);
- return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-}
-
-static int adav80x_suspend(struct snd_soc_codec *codec)
-{
- struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
- regcache_cache_only(adav80x->regmap, true);
-
- return ret;
+ return 0;
}
static int adav80x_resume(struct snd_soc_codec *codec)
{
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- regcache_cache_only(adav80x->regmap, false);
- adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
regcache_sync(adav80x->regmap);
return 0;
}
-static int adav80x_remove(struct snd_soc_codec *codec)
-{
- return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-}
-
static struct snd_soc_codec_driver adav80x_codec_driver = {
.probe = adav80x_probe,
- .remove = adav80x_remove,
- .suspend = adav80x_suspend,
.resume = adav80x_resume,
.set_bias_level = adav80x_set_bias_level,
+ .suspend_bias_off = true,
.set_pll = adav80x_set_pll,
.set_sysclk = adav80x_set_sysclk,
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index bd41ee4da078..2c71f16bd661 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -1278,6 +1278,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
else
rates = &arizona_48k_bclk_rates[0];
+ wl = snd_pcm_format_width(params_format(params));
+
if (tdm_slots) {
arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
tdm_slots, tdm_width);
@@ -1285,6 +1287,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
channels = tdm_slots;
} else {
bclk_target = snd_soc_params_to_bclk(params);
+ tdm_width = wl;
}
if (chan_limit && chan_limit < channels) {
@@ -1319,8 +1322,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
rates[bclk], rates[bclk] / lrclk);
- wl = snd_pcm_format_width(params_format(params));
- frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
+ frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
new file mode 100644
index 000000000000..c125925da92e
--- /dev/null
+++ b/sound/soc/codecs/cs35l32.c
@@ -0,0 +1,631 @@
+/*
+ * cs35l32.c -- CS35L32 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <dt-bindings/sound/cs35l32.h>
+
+#include "cs35l32.h"
+
+#define CS35L32_NUM_SUPPLIES 2
+static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = {
+ "VA",
+ "VP",
+};
+
+struct cs35l32_private {
+ struct regmap *regmap;
+ struct snd_soc_codec *codec;
+ struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES];
+ struct cs35l32_platform_data pdata;
+ struct gpio_desc *reset_gpio;
+};
+
+static const struct reg_default cs35l32_reg_defaults[] = {
+
+ { 0x06, 0x04 }, /* Power Ctl 1 */
+ { 0x07, 0xE8 }, /* Power Ctl 2 */
+ { 0x08, 0x40 }, /* Clock Ctl */
+ { 0x09, 0x20 }, /* Low Battery Threshold */
+ { 0x0A, 0x00 }, /* Voltage Monitor [RO] */
+ { 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */
+ { 0x0C, 0x07 }, /* IMON Scaling */
+ { 0x0D, 0x03 }, /* Audio/LED Pwr Manager */
+ { 0x0F, 0x20 }, /* Serial Port Control */
+ { 0x10, 0x14 }, /* Class D Amp CTL */
+ { 0x11, 0x00 }, /* Protection Release CTL */
+ { 0x12, 0xFF }, /* Interrupt Mask 1 */
+ { 0x13, 0xFF }, /* Interrupt Mask 2 */
+ { 0x14, 0xFF }, /* Interrupt Mask 3 */
+ { 0x19, 0x00 }, /* LED Flash Mode Current */
+ { 0x1A, 0x00 }, /* LED Movie Mode Current */
+ { 0x1B, 0x20 }, /* LED Flash Timer */
+ { 0x1C, 0x00 }, /* LED Flash Inhibit Current */
+};
+
+static bool cs35l32_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L32_DEVID_AB:
+ case CS35L32_DEVID_CD:
+ case CS35L32_DEVID_E:
+ case CS35L32_FAB_ID:
+ case CS35L32_REV_ID:
+ case CS35L32_PWRCTL1:
+ case CS35L32_PWRCTL2:
+ case CS35L32_CLK_CTL:
+ case CS35L32_BATT_THRESHOLD:
+ case CS35L32_VMON:
+ case CS35L32_BST_CPCP_CTL:
+ case CS35L32_IMON_SCALING:
+ case CS35L32_AUDIO_LED_MNGR:
+ case CS35L32_ADSP_CTL:
+ case CS35L32_CLASSD_CTL:
+ case CS35L32_PROTECT_CTL:
+ case CS35L32_INT_MASK_1:
+ case CS35L32_INT_MASK_2:
+ case CS35L32_INT_MASK_3:
+ case CS35L32_INT_STATUS_1:
+ case CS35L32_INT_STATUS_2:
+ case CS35L32_INT_STATUS_3:
+ case CS35L32_LED_STATUS:
+ case CS35L32_FLASH_MODE:
+ case CS35L32_MOVIE_MODE:
+ case CS35L32_FLASH_TIMER:
+ case CS35L32_FLASH_INHIBIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs35l32_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L32_DEVID_AB:
+ case CS35L32_DEVID_CD:
+ case CS35L32_DEVID_E:
+ case CS35L32_FAB_ID:
+ case CS35L32_REV_ID:
+ case CS35L32_INT_STATUS_1:
+ case CS35L32_INT_STATUS_2:
+ case CS35L32_INT_STATUS_3:
+ case CS35L32_LED_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs35l32_precious_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L32_INT_STATUS_1:
+ case CS35L32_INT_STATUS_2:
+ case CS35L32_INT_STATUS_3:
+ case CS35L32_LED_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0);
+
+static const struct snd_kcontrol_new imon_ctl =
+ SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1);
+
+static const struct snd_kcontrol_new vmon_ctl =
+ SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1);
+
+static const struct snd_kcontrol_new vpmon_ctl =
+ SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1);
+
+static const struct snd_kcontrol_new cs35l32_snd_controls[] = {
+ SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL,
+ 3, 0x04, 1, classd_ctl_tlv),
+ SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0),
+ SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0),
+
+ SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1),
+
+ SND_SOC_DAPM_INPUT("VP"),
+ SND_SOC_DAPM_INPUT("ISENSE"),
+ SND_SOC_DAPM_INPUT("VSENSE"),
+
+ SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl),
+ SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl),
+ SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl),
+};
+
+static const struct snd_soc_dapm_route cs35l32_audio_map[] = {
+
+ {"Speaker", NULL, "BOOST"},
+
+ {"VMON ADC", NULL, "VSENSE"},
+ {"IMON ADC", NULL, "ISENSE"},
+ {"VPMON ADC", NULL, "VP"},
+
+ {"SDOUT", "Switch", "VMON ADC"},
+ {"SDOUT", "Switch", "IMON ADC"},
+ {"SDOUT", "Switch", "VPMON ADC"},
+
+ {"Capture", NULL, "SDOUT"},
+};
+
+static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
+ CS35L32_ADSP_MASTER_MASK,
+ CS35L32_ADSP_MASTER_MASK);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ snd_soc_update_bits(codec, CS35L32_ADSP_CTL,
+ CS35L32_ADSP_MASTER_MASK, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ return snd_soc_update_bits(codec, CS35L32_PWRCTL2,
+ CS35L32_SDOUT_3ST, tristate << 3);
+}
+
+static const struct snd_soc_dai_ops cs35l32_ops = {
+ .set_fmt = cs35l32_set_dai_fmt,
+ .set_tristate = cs35l32_set_tristate,
+};
+
+static struct snd_soc_dai_driver cs35l32_dai[] = {
+ {
+ .name = "cs35l32-monitor",
+ .id = 0,
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = CS35L32_RATES,
+ .formats = CS35L32_FORMATS,
+ },
+ .ops = &cs35l32_ops,
+ .symmetric_rates = 1,
+ }
+};
+
+static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
+ int clk_id, int source, unsigned int freq, int dir)
+{
+ unsigned int val;
+
+ switch (freq) {
+ case 6000000:
+ val = CS35L32_MCLK_RATIO;
+ break;
+ case 12000000:
+ val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO;
+ break;
+ case 6144000:
+ val = 0;
+ break;
+ case 12288000:
+ val = CS35L32_MCLK_DIV2_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return snd_soc_update_bits(codec, CS35L32_CLK_CTL,
+ CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
+ .set_sysclk = cs35l32_codec_set_sysclk,
+
+ .dapm_widgets = cs35l32_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets),
+ .dapm_routes = cs35l32_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map),
+
+ .controls = cs35l32_snd_controls,
+ .num_controls = ARRAY_SIZE(cs35l32_snd_controls),
+};
+
+/* Current and threshold powerup sequence Pg37 in datasheet */
+static const struct reg_default cs35l32_monitor_patch[] = {
+
+ { 0x00, 0x99 },
+ { 0x48, 0x17 },
+ { 0x49, 0x56 },
+ { 0x43, 0x01 },
+ { 0x3B, 0x62 },
+ { 0x3C, 0x80 },
+ { 0x00, 0x00 },
+};
+
+static struct regmap_config cs35l32_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CS35L32_MAX_REGISTER,
+ .reg_defaults = cs35l32_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults),
+ .volatile_reg = cs35l32_volatile_register,
+ .readable_reg = cs35l32_readable_register,
+ .precious_reg = cs35l32_precious_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int cs35l32_handle_of_data(struct i2c_client *i2c_client,
+ struct cs35l32_platform_data *pdata)
+{
+ struct device_node *np = i2c_client->dev.of_node;
+ unsigned int val;
+
+ if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0)
+ pdata->sdout_share = val;
+
+ of_property_read_u32(np, "cirrus,boost-manager", &val);
+ switch (val) {
+ case CS35L32_BOOST_MGR_AUTO:
+ case CS35L32_BOOST_MGR_AUTO_AUDIO:
+ case CS35L32_BOOST_MGR_BYPASS:
+ case CS35L32_BOOST_MGR_FIXED:
+ pdata->boost_mng = val;
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,boost-manager DT value %d\n", val);
+ pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS;
+ }
+
+ of_property_read_u32(np, "cirrus,sdout-datacfg", &val);
+ switch (val) {
+ case CS35L32_DATA_CFG_LR_VP:
+ case CS35L32_DATA_CFG_LR_STAT:
+ case CS35L32_DATA_CFG_LR:
+ case CS35L32_DATA_CFG_LR_VPSTAT:
+ pdata->sdout_datacfg = val;
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,sdout-datacfg DT value %d\n", val);
+ pdata->sdout_datacfg = CS35L32_DATA_CFG_LR;
+ }
+
+ of_property_read_u32(np, "cirrus,battery-threshold", &val);
+ switch (val) {
+ case CS35L32_BATT_THRESH_3_1V:
+ case CS35L32_BATT_THRESH_3_2V:
+ case CS35L32_BATT_THRESH_3_3V:
+ case CS35L32_BATT_THRESH_3_4V:
+ pdata->batt_thresh = val;
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,battery-threshold DT value %d\n", val);
+ pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V;
+ }
+
+ of_property_read_u32(np, "cirrus,battery-recovery", &val);
+ switch (val) {
+ case CS35L32_BATT_RECOV_3_1V:
+ case CS35L32_BATT_RECOV_3_2V:
+ case CS35L32_BATT_RECOV_3_3V:
+ case CS35L32_BATT_RECOV_3_4V:
+ case CS35L32_BATT_RECOV_3_5V:
+ case CS35L32_BATT_RECOV_3_6V:
+ pdata->batt_recov = val;
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "Wrong cirrus,battery-recovery DT value %d\n", val);
+ pdata->batt_recov = CS35L32_BATT_RECOV_3_4V;
+ }
+
+ return 0;
+}
+
+static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct cs35l32_private *cs35l32;
+ struct cs35l32_platform_data *pdata =
+ dev_get_platdata(&i2c_client->dev);
+ int ret, i;
+ unsigned int devid = 0;
+ unsigned int reg;
+
+
+ cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private),
+ GFP_KERNEL);
+ if (!cs35l32) {
+ dev_err(&i2c_client->dev, "could not allocate codec\n");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(i2c_client, cs35l32);
+
+ cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap);
+ if (IS_ERR(cs35l32->regmap)) {
+ ret = PTR_ERR(cs35l32->regmap);
+ dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ if (pdata) {
+ cs35l32->pdata = *pdata;
+ } else {
+ pdata = devm_kzalloc(&i2c_client->dev,
+ sizeof(struct cs35l32_platform_data),
+ GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&i2c_client->dev, "could not allocate pdata\n");
+ return -ENOMEM;
+ }
+ if (i2c_client->dev.of_node) {
+ ret = cs35l32_handle_of_data(i2c_client,
+ &cs35l32->pdata);
+ if (ret != 0)
+ return ret;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++)
+ cs35l32->supplies[i].supply = cs35l32_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c_client->dev,
+ ARRAY_SIZE(cs35l32->supplies),
+ cs35l32->supplies);
+ if (ret != 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
+ cs35l32->supplies);
+ if (ret != 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ /* Reset the Device */
+ cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev,
+ "reset-gpios");
+ if (IS_ERR(cs35l32->reset_gpio)) {
+ ret = PTR_ERR(cs35l32->reset_gpio);
+ if (ret != -ENOENT && ret != -ENOSYS)
+ return ret;
+
+ cs35l32->reset_gpio = NULL;
+ } else {
+ ret = gpiod_direction_output(cs35l32->reset_gpio, 0);
+ if (ret)
+ return ret;
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+ }
+
+ /* initialize codec */
+ ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, &reg);
+ devid = (reg & 0xFF) << 12;
+
+ ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, &reg);
+ devid |= (reg & 0xFF) << 4;
+
+ ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, &reg);
+ devid |= (reg & 0xF0) >> 4;
+
+ if (devid != CS35L32_CHIP_ID) {
+ ret = -ENODEV;
+ dev_err(&i2c_client->dev,
+ "CS35L32 Device ID (%X). Expected %X\n",
+ devid, CS35L32_CHIP_ID);
+ return ret;
+ }
+
+ ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, &reg);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+ return ret;
+ }
+
+ ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch,
+ ARRAY_SIZE(cs35l32_monitor_patch));
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "Failed to apply errata patch\n");
+ return ret;
+ }
+
+ dev_info(&i2c_client->dev,
+ "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF);
+
+ /* Setup VBOOST Management */
+ if (cs35l32->pdata.boost_mng)
+ regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR,
+ CS35L32_BOOST_MASK,
+ cs35l32->pdata.boost_mng);
+
+ /* Setup ADSP Format Config */
+ if (cs35l32->pdata.sdout_share)
+ regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
+ CS35L32_ADSP_SHARE_MASK,
+ cs35l32->pdata.sdout_share << 3);
+
+ /* Setup ADSP Data Configuration */
+ if (cs35l32->pdata.sdout_datacfg)
+ regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL,
+ CS35L32_ADSP_DATACFG_MASK,
+ cs35l32->pdata.sdout_datacfg << 4);
+
+ /* Setup Low Battery Recovery */
+ if (cs35l32->pdata.batt_recov)
+ regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
+ CS35L32_BATT_REC_MASK,
+ cs35l32->pdata.batt_recov << 1);
+
+ /* Setup Low Battery Threshold */
+ if (cs35l32->pdata.batt_thresh)
+ regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD,
+ CS35L32_BATT_THRESH_MASK,
+ cs35l32->pdata.batt_thresh << 4);
+
+ /* Power down the AMP */
+ regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP,
+ CS35L32_PDN_AMP);
+
+ /* Clear MCLK Error Bit since we don't have the clock yet */
+ ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, &reg);
+
+ ret = snd_soc_register_codec(&i2c_client->dev,
+ &soc_codec_dev_cs35l32, cs35l32_dai,
+ ARRAY_SIZE(cs35l32_dai));
+ if (ret < 0)
+ goto err_disable;
+
+ return 0;
+
+err_disable:
+ regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+ cs35l32->supplies);
+ return ret;
+}
+
+static int cs35l32_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client);
+
+ snd_soc_unregister_codec(&i2c_client->dev);
+
+ /* Hold down reset */
+ if (cs35l32->reset_gpio)
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int cs35l32_runtime_suspend(struct device *dev)
+{
+ struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
+
+ regcache_cache_only(cs35l32->regmap, true);
+ regcache_mark_dirty(cs35l32->regmap);
+
+ /* Hold down reset */
+ if (cs35l32->reset_gpio)
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+
+ /* remove power */
+ regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+ cs35l32->supplies);
+
+ return 0;
+}
+
+static int cs35l32_runtime_resume(struct device *dev)
+{
+ struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
+ int ret;
+
+ /* Enable power */
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies),
+ cs35l32->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ if (cs35l32->reset_gpio)
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
+
+ regcache_cache_only(cs35l32->regmap, false);
+ regcache_sync(cs35l32->regmap);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs35l32_runtime_pm = {
+ SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id cs35l32_of_match[] = {
+ { .compatible = "cirrus,cs35l32", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cs35l32_of_match);
+
+
+static const struct i2c_device_id cs35l32_id[] = {
+ {"cs35l32", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs35l32_id);
+
+static struct i2c_driver cs35l32_i2c_driver = {
+ .driver = {
+ .name = "cs35l32",
+ .owner = THIS_MODULE,
+ .pm = &cs35l32_runtime_pm,
+ .of_match_table = cs35l32_of_match,
+ },
+ .id_table = cs35l32_id,
+ .probe = cs35l32_i2c_probe,
+ .remove = cs35l32_i2c_remove,
+};
+
+module_i2c_driver(cs35l32_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS35L32 driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h
new file mode 100644
index 000000000000..31ab804a22bc
--- /dev/null
+++ b/sound/soc/codecs/cs35l32.h
@@ -0,0 +1,93 @@
+/*
+ * cs35l32.h -- CS35L32 ALSA SoC audio driver
+ *
+ * Copyright 2014 CirrusLogic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS35L32_H__
+#define __CS35L32_H__
+
+struct cs35l32_platform_data {
+ /* Low Battery Threshold */
+ unsigned int batt_thresh;
+ /* Low Battery Recovery */
+ unsigned int batt_recov;
+ /* LED Current Management*/
+ unsigned int led_mng;
+ /* Audio Gain w/ LED */
+ unsigned int audiogain_mng;
+ /* Boost Management */
+ unsigned int boost_mng;
+ /* Data CFG for DUAL device */
+ unsigned int sdout_datacfg;
+ /* SDOUT Sharing */
+ unsigned int sdout_share;
+};
+
+#define CS35L32_CHIP_ID 0x00035A32
+#define CS35L32_DEVID_AB 0x01 /* Device ID A & B [RO] */
+#define CS35L32_DEVID_CD 0x02 /* Device ID C & D [RO] */
+#define CS35L32_DEVID_E 0x03 /* Device ID E [RO] */
+#define CS35L32_FAB_ID 0x04 /* Fab ID [RO] */
+#define CS35L32_REV_ID 0x05 /* Revision ID [RO] */
+#define CS35L32_PWRCTL1 0x06 /* Power Ctl 1 */
+#define CS35L32_PWRCTL2 0x07 /* Power Ctl 2 */
+#define CS35L32_CLK_CTL 0x08 /* Clock Ctl */
+#define CS35L32_BATT_THRESHOLD 0x09 /* Low Battery Threshold */
+#define CS35L32_VMON 0x0A /* Voltage Monitor [RO] */
+#define CS35L32_BST_CPCP_CTL 0x0B /* Conv Peak Curr Protection CTL */
+#define CS35L32_IMON_SCALING 0x0C /* IMON Scaling */
+#define CS35L32_AUDIO_LED_MNGR 0x0D /* Audio/LED Pwr Manager */
+#define CS35L32_ADSP_CTL 0x0F /* Serial Port Control */
+#define CS35L32_CLASSD_CTL 0x10 /* Class D Amp CTL */
+#define CS35L32_PROTECT_CTL 0x11 /* Protection Release CTL */
+#define CS35L32_INT_MASK_1 0x12 /* Interrupt Mask 1 */
+#define CS35L32_INT_MASK_2 0x13 /* Interrupt Mask 2 */
+#define CS35L32_INT_MASK_3 0x14 /* Interrupt Mask 3 */
+#define CS35L32_INT_STATUS_1 0x15 /* Interrupt Status 1 [RO] */
+#define CS35L32_INT_STATUS_2 0x16 /* Interrupt Status 2 [RO] */
+#define CS35L32_INT_STATUS_3 0x17 /* Interrupt Status 3 [RO] */
+#define CS35L32_LED_STATUS 0x18 /* LED Lighting Status [RO] */
+#define CS35L32_FLASH_MODE 0x19 /* LED Flash Mode Current */
+#define CS35L32_MOVIE_MODE 0x1A /* LED Movie Mode Current */
+#define CS35L32_FLASH_TIMER 0x1B /* LED Flash Timer */
+#define CS35L32_FLASH_INHIBIT 0x1C /* LED Flash Inhibit Current */
+#define CS35L32_MAX_REGISTER 0x1C
+
+#define CS35L32_MCLK_DIV2 0x01
+#define CS35L32_MCLK_RATIO 0x01
+#define CS35L32_MCLKDIS 0x80
+#define CS35L32_PDN_ALL 0x01
+#define CS35L32_PDN_AMP 0x80
+#define CS35L32_PDN_BOOST 0x04
+#define CS35L32_PDN_IMON 0x40
+#define CS35L32_PDN_VMON 0x80
+#define CS35L32_PDN_VPMON 0x20
+#define CS35L32_PDN_ADSP 0x08
+
+#define CS35L32_MCLK_DIV2_MASK 0x40
+#define CS35L32_MCLK_RATIO_MASK 0x01
+#define CS35L32_MCLK_MASK 0x41
+#define CS35L32_ADSP_MASTER_MASK 0x40
+#define CS35L32_BOOST_MASK 0x03
+#define CS35L32_GAIN_MGR_MASK 0x08
+#define CS35L32_ADSP_SHARE_MASK 0x08
+#define CS35L32_ADSP_DATACFG_MASK 0x30
+#define CS35L32_SDOUT_3ST 0x80
+#define CS35L32_BATT_REC_MASK 0x0E
+#define CS35L32_BATT_THRESH_MASK 0x30
+
+#define CS35L32_RATES (SNDRV_PCM_RATE_48000)
+#define CS35L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+
+#endif
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index a20b30ca52c0..4fdd47d700e3 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -77,6 +77,7 @@ static bool cs4265_readable_register(struct device *dev, unsigned int reg)
case CS4265_INT_MASK:
case CS4265_STATUS_MODE_MSB:
case CS4265_STATUS_MODE_LSB:
+ case CS4265_CHIP_ID:
return true;
default:
return false;
@@ -282,10 +283,10 @@ static const struct cs4265_clk_para clk_map_table[] = {
/*64k*/
{8192000, 64000, 1, 0},
- {1228800, 64000, 1, 1},
- {1693440, 64000, 1, 2},
- {2457600, 64000, 1, 3},
- {3276800, 64000, 1, 4},
+ {12288000, 64000, 1, 1},
+ {16934400, 64000, 1, 2},
+ {24576000, 64000, 1, 3},
+ {32768000, 64000, 1, 4},
/* 88.2k */
{11289600, 88200, 1, 0},
@@ -435,10 +436,10 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params));
if (index >= 0) {
snd_soc_update_bits(codec, CS4265_ADC_CTL,
- CS4265_ADC_FM, clk_map_table[index].fm_mode);
+ CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
snd_soc_update_bits(codec, CS4265_MCLK_FREQ,
CS4265_MCLK_FREQ_MASK,
- clk_map_table[index].mclkdiv);
+ clk_map_table[index].mclkdiv << 4);
} else {
dev_err(codec->dev, "can't get correct mclk\n");
@@ -458,12 +459,12 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
if (params_width(params) == 16) {
snd_soc_update_bits(codec, CS4265_DAC_CTL,
CS4265_DAC_CTL_DIF, (1 << 5));
- snd_soc_update_bits(codec, CS4265_ADC_CTL,
+ snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
CS4265_SPDIF_CTL2_DIF, (1 << 7));
} else {
snd_soc_update_bits(codec, CS4265_DAC_CTL,
CS4265_DAC_CTL_DIF, (3 << 5));
- snd_soc_update_bits(codec, CS4265_ADC_CTL,
+ snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
CS4265_SPDIF_CTL2_DIF, (1 << 7));
}
break;
@@ -472,7 +473,7 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
CS4265_DAC_CTL_DIF, 0);
snd_soc_update_bits(codec, CS4265_ADC_CTL,
CS4265_ADC_DIF, 0);
- snd_soc_update_bits(codec, CS4265_ADC_CTL,
+ snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
CS4265_SPDIF_CTL2_DIF, (1 << 6));
break;
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 969167d8b71e..da4f758cd12a 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -176,9 +176,9 @@ static bool cs42l52_volatile_register(struct device *dev, unsigned int reg)
case CS42L52_BATT_LEVEL:
case CS42L52_SPK_STATUS:
case CS42L52_CHARGE_PUMP:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index c766a5a9ce80..bb74dd17fa26 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -171,9 +171,9 @@ static bool cs42l56_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS42L56_INT_STATUS:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
@@ -1175,11 +1175,8 @@ static int cs42l56_probe(struct snd_soc_codec *codec)
static int cs42l56_remove(struct snd_soc_codec *codec)
{
- struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec);
-
cs42l56_free_beep(codec);
cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF);
- regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies);
return 0;
}
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index 2fae31cb0067..fa15fa1c0516 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -217,7 +217,7 @@ static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state)
snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS);
break;
default:
- pr_err(KERN_ERR "Wrong charge pump state\n");
+ pr_err("Wrong charge pump state\n");
break;
}
}
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h
index 1dceafeec415..f586cbd30b77 100644
--- a/sound/soc/codecs/da732x.h
+++ b/sound/soc/codecs/da732x.h
@@ -11,7 +11,7 @@
*/
#ifndef __DA732X_H_
-#define __DA732X_H
+#define __DA732X_H_
#include <sound/soc.h>
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 7a9f65ad183d..f27325155ace 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -602,8 +602,6 @@ static int es8328_suspend(struct snd_soc_codec *codec)
es8328 = snd_soc_codec_get_drvdata(codec);
- es8328_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
clk_disable_unprepare(es8328->clk);
ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
@@ -643,7 +641,6 @@ static int es8328_resume(struct snd_soc_codec *codec)
return ret;
}
- es8328_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -665,6 +662,7 @@ static int es8328_codec_probe(struct snd_soc_codec *codec)
es8328->clk = devm_clk_get(codec->dev, NULL);
if (IS_ERR(es8328->clk)) {
dev_err(codec->dev, "codec clock missing or invalid\n");
+ ret = PTR_ERR(es8328->clk);
goto clk_fail;
}
@@ -711,6 +709,8 @@ static struct snd_soc_codec_driver es8328_codec_driver = {
.resume = es8328_resume,
.remove = es8328_remove,
.set_bias_level = es8328_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = es8328_snd_controls,
.num_controls = ARRAY_SIZE(es8328_snd_controls),
.dapm_widgets = es8328_dapm_widgets,
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index 275b3f72f3f4..c1ae5764983f 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1395,18 +1395,6 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
},
};
-static int lm49453_suspend(struct snd_soc_codec *codec)
-{
- lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int lm49453_resume(struct snd_soc_codec *codec)
-{
- lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
/* power down chip */
static int lm49453_remove(struct snd_soc_codec *codec)
{
@@ -1416,8 +1404,6 @@ static int lm49453_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
.remove = lm49453_remove,
- .suspend = lm49453_suspend,
- .resume = lm49453_resume,
.set_bias_level = lm49453_set_bias_level,
.controls = lm49453_snd_controls,
.num_controls = ARRAY_SIZE(lm49453_snd_controls),
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 4a063fa88526..7e111865946a 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -1311,8 +1311,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
{"MIC1 Input", NULL, "MIC1"},
{"MIC2 Input", NULL, "MIC2"},
- {"DMICL", NULL, "DMICL_ENA"},
- {"DMICR", NULL, "DMICR_ENA"},
{"DMICL", NULL, "AHPF"},
{"DMICR", NULL, "AHPF"},
@@ -1370,6 +1368,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
{"DMIC Mux", "ADC", "ADCR"},
{"DMIC Mux", "DMIC", "DMICL"},
{"DMIC Mux", "DMIC", "DMICR"},
+ {"DMIC Mux", "DMIC", "DMICL_ENA"},
+ {"DMIC Mux", "DMIC", "DMICR_ENA"},
{"LBENL Mux", "Normal", "DMIC Mux"},
{"LBENL Mux", "Loopback", "LTENL Mux"},
@@ -1972,6 +1972,102 @@ static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute)
return 0;
}
+static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!max98090->master && dai->active == 1)
+ queue_delayed_work(system_power_efficient_wq,
+ &max98090->pll_det_enable_work,
+ msecs_to_jiffies(10));
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (!max98090->master && dai->active == 1)
+ schedule_work(&max98090->pll_det_disable_work);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void max98090_pll_det_enable_work(struct work_struct *work)
+{
+ struct max98090_priv *max98090 =
+ container_of(work, struct max98090_priv,
+ pll_det_enable_work.work);
+ struct snd_soc_codec *codec = max98090->codec;
+ unsigned int status, mask;
+
+ /*
+ * Clear status register in order to clear possibly already occurred
+ * PLL unlock. If PLL hasn't still locked, the status will be set
+ * again and PLL unlock interrupt will occur.
+ * Note this will clear all status bits
+ */
+ regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status);
+
+ /*
+ * Queue jack work in case jack state has just changed but handler
+ * hasn't run yet
+ */
+ regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask);
+ status &= mask;
+ if (status & M98090_JDET_MASK)
+ queue_delayed_work(system_power_efficient_wq,
+ &max98090->jack_work,
+ msecs_to_jiffies(100));
+
+ /* Enable PLL unlock interrupt */
+ snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+ M98090_IULK_MASK,
+ 1 << M98090_IULK_SHIFT);
+}
+
+static void max98090_pll_det_disable_work(struct work_struct *work)
+{
+ struct max98090_priv *max98090 =
+ container_of(work, struct max98090_priv, pll_det_disable_work);
+ struct snd_soc_codec *codec = max98090->codec;
+
+ cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+
+ /* Disable PLL unlock interrupt */
+ snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S,
+ M98090_IULK_MASK, 0);
+}
+
+static void max98090_pll_work(struct work_struct *work)
+{
+ struct max98090_priv *max98090 =
+ container_of(work, struct max98090_priv, pll_work);
+ struct snd_soc_codec *codec = max98090->codec;
+
+ if (!snd_soc_codec_is_active(codec))
+ return;
+
+ dev_info(codec->dev, "PLL unlocked\n");
+
+ /* Toggle shutdown OFF then ON */
+ snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK, 0);
+ msleep(10);
+ snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN,
+ M98090_SHDNN_MASK, M98090_SHDNN_MASK);
+
+ /* Give PLL time to lock */
+ msleep(10);
+}
+
static void max98090_jack_work(struct work_struct *work)
{
struct max98090_priv *max98090 = container_of(work,
@@ -2103,8 +2199,10 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
if (active & M98090_SLD_MASK)
dev_dbg(codec->dev, "M98090_SLD_MASK\n");
- if (active & M98090_ULK_MASK)
- dev_err(codec->dev, "M98090_ULK_MASK\n");
+ if (active & M98090_ULK_MASK) {
+ dev_dbg(codec->dev, "M98090_ULK_MASK\n");
+ schedule_work(&max98090->pll_work);
+ }
if (active & M98090_JDET_MASK) {
dev_dbg(codec->dev, "M98090_JDET_MASK\n");
@@ -2177,6 +2275,7 @@ static struct snd_soc_dai_ops max98090_dai_ops = {
.set_tdm_slot = max98090_set_tdm_slot,
.hw_params = max98090_dai_hw_params,
.digital_mute = max98090_dai_digital_mute,
+ .trigger = max98090_dai_trigger,
};
static struct snd_soc_dai_driver max98090_dai[] = {
@@ -2258,6 +2357,11 @@ static int max98090_probe(struct snd_soc_codec *codec)
max98090->jack_state = M98090_JACK_STATE_NO_HEADSET;
INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work);
+ INIT_DELAYED_WORK(&max98090->pll_det_enable_work,
+ max98090_pll_det_enable_work);
+ INIT_WORK(&max98090->pll_det_disable_work,
+ max98090_pll_det_disable_work);
+ INIT_WORK(&max98090->pll_work, max98090_pll_work);
/* Enable jack detection */
snd_soc_write(codec, M98090_REG_JACK_DETECT,
@@ -2310,6 +2414,9 @@ static int max98090_remove(struct snd_soc_codec *codec)
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
cancel_delayed_work_sync(&max98090->jack_work);
+ cancel_delayed_work_sync(&max98090->pll_det_enable_work);
+ cancel_work_sync(&max98090->pll_det_disable_work);
+ cancel_work_sync(&max98090->pll_work);
return 0;
}
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index cf1b6062ba8c..14427a566f41 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -1532,6 +1532,9 @@ struct max98090_priv {
int irq;
int jack_state;
struct delayed_work jack_work;
+ struct delayed_work pll_det_enable_work;
+ struct work_struct pll_det_disable_work;
+ struct work_struct pll_work;
struct snd_soc_jack *jack;
unsigned int dai_fmt;
int tdm_slots;
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 163ec3855fd4..0c8aefab404c 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -259,13 +259,13 @@ static const struct soc_enum pcm512x_veds =
pcm512x_ramp_step_text);
static const struct snd_kcontrol_new pcm512x_controls[] = {
-SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2,
+SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
-SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
+SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
PCM512x_RQMR_SHIFT, 1, 1),
SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index e4f6102efc1a..b86b426f159d 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -51,7 +51,7 @@ static struct reg_default rt286_index_def[] = {
{ 0x04, 0xaf01 },
{ 0x08, 0x000d },
{ 0x09, 0xd810 },
- { 0x0a, 0x0060 },
+ { 0x0a, 0x0120 },
{ 0x0b, 0x0000 },
{ 0x0d, 0x2800 },
{ 0x0f, 0x0000 },
@@ -60,7 +60,7 @@ static struct reg_default rt286_index_def[] = {
{ 0x33, 0x0208 },
{ 0x49, 0x0004 },
{ 0x4f, 0x50e9 },
- { 0x50, 0x2c00 },
+ { 0x50, 0x2000 },
{ 0x63, 0x2902 },
{ 0x67, 0x1111 },
{ 0x68, 0x1016 },
@@ -104,7 +104,6 @@ static const struct reg_default rt286_reg[] = {
{ 0x02170700, 0x00000000 },
{ 0x02270100, 0x00000000 },
{ 0x02370100, 0x00000000 },
- { 0x02040000, 0x00004002 },
{ 0x01870700, 0x00000020 },
{ 0x00830000, 0x000000c3 },
{ 0x00930000, 0x000000c3 },
@@ -192,7 +191,6 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value)
/*handle index registers*/
if (reg <= 0xff) {
rt286_hw_write(client, RT286_COEF_INDEX, reg);
- reg = RT286_PROC_COEF;
for (i = 0; i < INDEX_CACHE_SIZE; i++) {
if (reg == rt286->index_cache[i].reg) {
rt286->index_cache[i].def = value;
@@ -200,6 +198,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value)
}
}
+ reg = RT286_PROC_COEF;
}
data[0] = (reg >> 24) & 0xff;
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 6bc6efdec550..c3f2decd643c 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1906,6 +1906,32 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
+int rt5640_dmic_enable(struct snd_soc_codec *codec,
+ bool dmic1_data_pin, bool dmic2_data_pin)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+ regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+ RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
+
+ if (dmic1_data_pin) {
+ regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+ RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
+ regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+ RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
+ }
+
+ if (dmic2_data_pin) {
+ regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+ RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
+ regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+ RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
+
static int rt5640_probe(struct snd_soc_codec *codec)
{
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
@@ -1945,6 +1971,10 @@ static int rt5640_probe(struct snd_soc_codec *codec)
return -ENODEV;
}
+ if (rt5640->pdata.dmic_en)
+ rt5640_dmic_enable(codec, rt5640->pdata.dmic1_data_pin,
+ rt5640->pdata.dmic2_data_pin);
+
return 0;
}
@@ -2059,6 +2089,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
static const struct regmap_config rt5640_regmap = {
.reg_bits = 8,
.val_bits = 16,
+ .use_single_rw = true,
.max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) *
RT5640_PR_SPACING),
@@ -2194,25 +2225,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
RT5640_IN_DF2, RT5640_IN_DF2);
- if (rt5640->pdata.dmic_en) {
- regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
- RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
-
- if (rt5640->pdata.dmic1_data_pin) {
- regmap_update_bits(rt5640->regmap, RT5640_DMIC,
- RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
- regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
- RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
- }
-
- if (rt5640->pdata.dmic2_data_pin) {
- regmap_update_bits(rt5640->regmap, RT5640_DMIC,
- RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
- regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
- RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
- }
- }
-
rt5640->hp_mute = 1;
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 58ebe96b86da..3deb8babeabb 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -2097,4 +2097,7 @@ struct rt5640_priv {
bool hp_mute;
};
+int rt5640_dmic_enable(struct snd_soc_codec *codec,
+ bool dmic1_data_pin, bool dmic2_data_pin);
+
#endif
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 67f14556462f..dc978ad59fc7 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -19,6 +19,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
+#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -1700,14 +1701,19 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("Haptic Generator"),
- SND_SOC_DAPM_PGA("DMIC1", RT5677_DMIC_CTRL1, RT5677_DMIC_1_EN_SFT, 0,
- NULL, 0),
- SND_SOC_DAPM_PGA("DMIC2", RT5677_DMIC_CTRL1, RT5677_DMIC_2_EN_SFT, 0,
- NULL, 0),
- SND_SOC_DAPM_PGA("DMIC3", RT5677_DMIC_CTRL1, RT5677_DMIC_3_EN_SFT, 0,
- NULL, 0),
- SND_SOC_DAPM_PGA("DMIC4", RT5677_DMIC_CTRL2, RT5677_DMIC_4_EN_SFT, 0,
- NULL, 0),
+ SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("DMIC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("DMIC1 power", RT5677_DMIC_CTRL1,
+ RT5677_DMIC_1_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC2 power", RT5677_DMIC_CTRL1,
+ RT5677_DMIC_2_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC3 power", RT5677_DMIC_CTRL1,
+ RT5677_DMIC_3_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC4 power", RT5677_DMIC_CTRL2,
+ RT5677_DMIC_4_EN_SFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
@@ -2130,15 +2136,22 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "DMIC L4", NULL, "DMIC CLK" },
{ "DMIC R4", NULL, "DMIC CLK" },
+ { "DMIC L1", NULL, "DMIC1 power" },
+ { "DMIC R1", NULL, "DMIC1 power" },
+ { "DMIC L3", NULL, "DMIC3 power" },
+ { "DMIC R3", NULL, "DMIC3 power" },
+ { "DMIC L4", NULL, "DMIC4 power" },
+ { "DMIC R4", NULL, "DMIC4 power" },
+
{ "BST1", NULL, "IN1P" },
{ "BST1", NULL, "IN1N" },
{ "BST2", NULL, "IN2P" },
{ "BST2", NULL, "IN2N" },
- { "IN1P", NULL, "micbias1" },
- { "IN1N", NULL, "micbias1" },
- { "IN2P", NULL, "micbias1" },
- { "IN2N", NULL, "micbias1" },
+ { "IN1P", NULL, "MICBIAS1" },
+ { "IN1N", NULL, "MICBIAS1" },
+ { "IN2P", NULL, "MICBIAS1" },
+ { "IN2N", NULL, "MICBIAS1" },
{ "ADC 1", NULL, "BST1" },
{ "ADC 1", NULL, "ADC 1 power" },
@@ -2793,6 +2806,16 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "PDM2R", NULL, "PDM2 R Mux" },
};
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_1[] = {
+ { "DMIC L2", NULL, "DMIC1 power" },
+ { "DMIC R2", NULL, "DMIC1 power" },
+};
+
+static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = {
+ { "DMIC L2", NULL, "DMIC2 power" },
+ { "DMIC R2", NULL, "DMIC2 power" },
+};
+
static int rt5677_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
@@ -3138,12 +3161,148 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
+#ifdef CONFIG_GPIOLIB
+static inline struct rt5677_priv *gpio_to_rt5677(struct gpio_chip *chip)
+{
+ return container_of(chip, struct rt5677_priv, gpio_chip);
+}
+
+static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+
+ switch (offset) {
+ case RT5677_GPIO1 ... RT5677_GPIO5:
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+ 0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1));
+ break;
+
+ case RT5677_GPIO6:
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+ RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int rt5677_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+
+ switch (offset) {
+ case RT5677_GPIO1 ... RT5677_GPIO5:
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+ 0x3 << (offset * 3 + 1),
+ (0x2 | !!value) << (offset * 3 + 1));
+ break;
+
+ case RT5677_GPIO6:
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+ RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK,
+ RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+ int value, ret;
+
+ ret = regmap_read(rt5677->regmap, RT5677_GPIO_ST, &value);
+ if (ret < 0)
+ return ret;
+
+ return (value & (0x1 << offset)) >> offset;
+}
+
+static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+
+ switch (offset) {
+ case RT5677_GPIO1 ... RT5677_GPIO5:
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+ 0x1 << (offset * 3 + 2), 0x0);
+ break;
+
+ case RT5677_GPIO6:
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
+ RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct gpio_chip rt5677_template_chip = {
+ .label = "rt5677",
+ .owner = THIS_MODULE,
+ .direction_output = rt5677_gpio_direction_out,
+ .set = rt5677_gpio_set,
+ .direction_input = rt5677_gpio_direction_in,
+ .get = rt5677_gpio_get,
+ .can_sleep = 1,
+};
+
+static void rt5677_init_gpio(struct i2c_client *i2c)
+{
+ struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+ int ret;
+
+ rt5677->gpio_chip = rt5677_template_chip;
+ rt5677->gpio_chip.ngpio = RT5677_GPIO_NUM;
+ rt5677->gpio_chip.dev = &i2c->dev;
+ rt5677->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&rt5677->gpio_chip);
+ if (ret != 0)
+ dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void rt5677_free_gpio(struct i2c_client *i2c)
+{
+ struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+ gpiochip_remove(&rt5677->gpio_chip);
+}
+#else
+static void rt5677_init_gpio(struct i2c_client *i2c)
+{
+}
+
+static void rt5677_free_gpio(struct i2c_client *i2c)
+{
+}
+#endif
+
static int rt5677_probe(struct snd_soc_codec *codec)
{
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
rt5677->codec = codec;
+ if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+ snd_soc_dapm_add_routes(&codec->dapm,
+ rt5677_dmic2_clk_2,
+ ARRAY_SIZE(rt5677_dmic2_clk_2));
+ } else { /*use dmic1 clock by default*/
+ snd_soc_dapm_add_routes(&codec->dapm,
+ rt5677_dmic2_clk_1,
+ ARRAY_SIZE(rt5677_dmic2_clk_1));
+ }
+
rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF);
regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
@@ -3381,6 +3540,17 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
regmap_update_bits(rt5677->regmap, RT5677_IN1,
RT5677_IN_DF2, RT5677_IN_DF2);
+ if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
+ regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2,
+ RT5677_GPIO5_FUNC_MASK,
+ RT5677_GPIO5_FUNC_DMIC);
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
+ RT5677_GPIO5_DIR_MASK,
+ RT5677_GPIO5_DIR_OUT);
+ }
+
+ rt5677_init_gpio(i2c);
+
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
rt5677_dai, ARRAY_SIZE(rt5677_dai));
}
@@ -3388,6 +3558,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
static int rt5677_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
+ rt5677_free_gpio(i2c);
return 0;
}
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index 863393e62096..b61b72cfcbd7 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -1287,16 +1287,16 @@
#define RT5677_PLL1_PD_SFT 8
#define RT5677_PLL1_PD_1 (0x0 << 8)
#define RT5677_PLL1_PD_2 (0x1 << 8)
-#define RT5671_DAC_OSR_MASK (0x3 << 6)
-#define RT5671_DAC_OSR_SFT 6
-#define RT5671_DAC_OSR_128 (0x0 << 6)
-#define RT5671_DAC_OSR_64 (0x1 << 6)
-#define RT5671_DAC_OSR_32 (0x2 << 6)
-#define RT5671_ADC_OSR_MASK (0x3 << 4)
-#define RT5671_ADC_OSR_SFT 4
-#define RT5671_ADC_OSR_128 (0x0 << 4)
-#define RT5671_ADC_OSR_64 (0x1 << 4)
-#define RT5671_ADC_OSR_32 (0x2 << 4)
+#define RT5677_DAC_OSR_MASK (0x3 << 6)
+#define RT5677_DAC_OSR_SFT 6
+#define RT5677_DAC_OSR_128 (0x0 << 6)
+#define RT5677_DAC_OSR_64 (0x1 << 6)
+#define RT5677_DAC_OSR_32 (0x2 << 6)
+#define RT5677_ADC_OSR_MASK (0x3 << 4)
+#define RT5677_ADC_OSR_SFT 4
+#define RT5677_ADC_OSR_128 (0x0 << 4)
+#define RT5677_ADC_OSR_64 (0x1 << 4)
+#define RT5677_ADC_OSR_32 (0x2 << 4)
/* Global Clock Control 2 (0x81) */
#define RT5677_PLL2_PR_SRC_MASK (0x1 << 15)
@@ -1312,18 +1312,18 @@
#define RT5677_PLL2_SRC_BCLK4 (0x4 << 12)
#define RT5677_PLL2_SRC_RCCLK (0x5 << 12)
#define RT5677_PLL2_SRC_SLIM (0x6 << 12)
-#define RT5671_DSP_ASRC_O_SRC (0x3 << 10)
-#define RT5671_DSP_ASRC_O_SRC_SFT 10
-#define RT5671_DSP_ASRC_O_MCLK (0x0 << 10)
-#define RT5671_DSP_ASRC_O_PLL1 (0x1 << 10)
-#define RT5671_DSP_ASRC_O_SLIM (0x2 << 10)
-#define RT5671_DSP_ASRC_O_RCCLK (0x3 << 10)
-#define RT5671_DSP_ASRC_I_SRC (0x3 << 8)
-#define RT5671_DSP_ASRC_I_SRC_SFT 8
-#define RT5671_DSP_ASRC_I_MCLK (0x0 << 8)
-#define RT5671_DSP_ASRC_I_PLL1 (0x1 << 8)
-#define RT5671_DSP_ASRC_I_SLIM (0x2 << 8)
-#define RT5671_DSP_ASRC_I_RCCLK (0x3 << 8)
+#define RT5677_DSP_ASRC_O_SRC (0x3 << 10)
+#define RT5677_DSP_ASRC_O_SRC_SFT 10
+#define RT5677_DSP_ASRC_O_MCLK (0x0 << 10)
+#define RT5677_DSP_ASRC_O_PLL1 (0x1 << 10)
+#define RT5677_DSP_ASRC_O_SLIM (0x2 << 10)
+#define RT5677_DSP_ASRC_O_RCCLK (0x3 << 10)
+#define RT5677_DSP_ASRC_I_SRC (0x3 << 8)
+#define RT5677_DSP_ASRC_I_SRC_SFT 8
+#define RT5677_DSP_ASRC_I_MCLK (0x0 << 8)
+#define RT5677_DSP_ASRC_I_PLL1 (0x1 << 8)
+#define RT5677_DSP_ASRC_I_SLIM (0x2 << 8)
+#define RT5677_DSP_ASRC_I_RCCLK (0x3 << 8)
#define RT5677_DSP_CLK_SRC_MASK (0x1 << 7)
#define RT5677_DSP_CLK_SRC_SFT 7
#define RT5677_DSP_CLK_SRC_PLL2 (0x0 << 7)
@@ -1363,6 +1363,110 @@
#define RT5677_SEL_SRC_IB01 (0x1 << 0)
#define RT5677_SEL_SRC_IB01_SFT 0
+/* GPIO status (0xbf) */
+#define RT5677_GPIO6_STATUS_MASK (0x1 << 5)
+#define RT5677_GPIO6_STATUS_SFT 5
+#define RT5677_GPIO5_STATUS_MASK (0x1 << 4)
+#define RT5677_GPIO5_STATUS_SFT 4
+#define RT5677_GPIO4_STATUS_MASK (0x1 << 3)
+#define RT5677_GPIO4_STATUS_SFT 3
+#define RT5677_GPIO3_STATUS_MASK (0x1 << 2)
+#define RT5677_GPIO3_STATUS_SFT 2
+#define RT5677_GPIO2_STATUS_MASK (0x1 << 1)
+#define RT5677_GPIO2_STATUS_SFT 1
+#define RT5677_GPIO1_STATUS_MASK (0x1 << 0)
+#define RT5677_GPIO1_STATUS_SFT 0
+
+/* GPIO Control 1 (0xc0) */
+#define RT5677_GPIO1_PIN_MASK (0x1 << 15)
+#define RT5677_GPIO1_PIN_SFT 15
+#define RT5677_GPIO1_PIN_GPIO1 (0x0 << 15)
+#define RT5677_GPIO1_PIN_IRQ (0x1 << 15)
+#define RT5677_IPTV_MODE_MASK (0x1 << 14)
+#define RT5677_IPTV_MODE_SFT 14
+#define RT5677_IPTV_MODE_GPIO (0x0 << 14)
+#define RT5677_IPTV_MODE_IPTV (0x1 << 14)
+#define RT5677_FUNC_MODE_MASK (0x1 << 13)
+#define RT5677_FUNC_MODE_SFT 13
+#define RT5677_FUNC_MODE_DMIC_GPIO (0x0 << 13)
+#define RT5677_FUNC_MODE_JTAG (0x1 << 13)
+
+/* GPIO Control 2 (0xc1) */
+#define RT5677_GPIO5_DIR_MASK (0x1 << 14)
+#define RT5677_GPIO5_DIR_SFT 14
+#define RT5677_GPIO5_DIR_IN (0x0 << 14)
+#define RT5677_GPIO5_DIR_OUT (0x1 << 14)
+#define RT5677_GPIO5_OUT_MASK (0x1 << 13)
+#define RT5677_GPIO5_OUT_SFT 13
+#define RT5677_GPIO5_OUT_LO (0x0 << 13)
+#define RT5677_GPIO5_OUT_HI (0x1 << 13)
+#define RT5677_GPIO5_P_MASK (0x1 << 12)
+#define RT5677_GPIO5_P_SFT 12
+#define RT5677_GPIO5_P_NOR (0x0 << 12)
+#define RT5677_GPIO5_P_INV (0x1 << 12)
+#define RT5677_GPIO4_DIR_MASK (0x1 << 11)
+#define RT5677_GPIO4_DIR_SFT 11
+#define RT5677_GPIO4_DIR_IN (0x0 << 11)
+#define RT5677_GPIO4_DIR_OUT (0x1 << 11)
+#define RT5677_GPIO4_OUT_MASK (0x1 << 10)
+#define RT5677_GPIO4_OUT_SFT 10
+#define RT5677_GPIO4_OUT_LO (0x0 << 10)
+#define RT5677_GPIO4_OUT_HI (0x1 << 10)
+#define RT5677_GPIO4_P_MASK (0x1 << 9)
+#define RT5677_GPIO4_P_SFT 9
+#define RT5677_GPIO4_P_NOR (0x0 << 9)
+#define RT5677_GPIO4_P_INV (0x1 << 9)
+#define RT5677_GPIO3_DIR_MASK (0x1 << 8)
+#define RT5677_GPIO3_DIR_SFT 8
+#define RT5677_GPIO3_DIR_IN (0x0 << 8)
+#define RT5677_GPIO3_DIR_OUT (0x1 << 8)
+#define RT5677_GPIO3_OUT_MASK (0x1 << 7)
+#define RT5677_GPIO3_OUT_SFT 7
+#define RT5677_GPIO3_OUT_LO (0x0 << 7)
+#define RT5677_GPIO3_OUT_HI (0x1 << 7)
+#define RT5677_GPIO3_P_MASK (0x1 << 6)
+#define RT5677_GPIO3_P_SFT 6
+#define RT5677_GPIO3_P_NOR (0x0 << 6)
+#define RT5677_GPIO3_P_INV (0x1 << 6)
+#define RT5677_GPIO2_DIR_MASK (0x1 << 5)
+#define RT5677_GPIO2_DIR_SFT 5
+#define RT5677_GPIO2_DIR_IN (0x0 << 5)
+#define RT5677_GPIO2_DIR_OUT (0x1 << 5)
+#define RT5677_GPIO2_OUT_MASK (0x1 << 4)
+#define RT5677_GPIO2_OUT_SFT 4
+#define RT5677_GPIO2_OUT_LO (0x0 << 4)
+#define RT5677_GPIO2_OUT_HI (0x1 << 4)
+#define RT5677_GPIO2_P_MASK (0x1 << 3)
+#define RT5677_GPIO2_P_SFT 3
+#define RT5677_GPIO2_P_NOR (0x0 << 3)
+#define RT5677_GPIO2_P_INV (0x1 << 3)
+#define RT5677_GPIO1_DIR_MASK (0x1 << 2)
+#define RT5677_GPIO1_DIR_SFT 2
+#define RT5677_GPIO1_DIR_IN (0x0 << 2)
+#define RT5677_GPIO1_DIR_OUT (0x1 << 2)
+#define RT5677_GPIO1_OUT_MASK (0x1 << 1)
+#define RT5677_GPIO1_OUT_SFT 1
+#define RT5677_GPIO1_OUT_LO (0x0 << 1)
+#define RT5677_GPIO1_OUT_HI (0x1 << 1)
+#define RT5677_GPIO1_P_MASK (0x1 << 0)
+#define RT5677_GPIO1_P_SFT 0
+#define RT5677_GPIO1_P_NOR (0x0 << 0)
+#define RT5677_GPIO1_P_INV (0x1 << 0)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5677_GPIO6_DIR_MASK (0x1 << 2)
+#define RT5677_GPIO6_DIR_SFT 2
+#define RT5677_GPIO6_DIR_IN (0x0 << 2)
+#define RT5677_GPIO6_DIR_OUT (0x1 << 2)
+#define RT5677_GPIO6_OUT_MASK (0x1 << 1)
+#define RT5677_GPIO6_OUT_SFT 1
+#define RT5677_GPIO6_OUT_LO (0x0 << 1)
+#define RT5677_GPIO6_OUT_HI (0x1 << 1)
+#define RT5677_GPIO6_P_MASK (0x1 << 0)
+#define RT5677_GPIO6_P_SFT 0
+#define RT5677_GPIO6_P_NOR (0x0 << 0)
+#define RT5677_GPIO6_P_INV (0x1 << 0)
+
/* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */
#define RT5677_DSP_IB_01_H (0x1 << 15)
#define RT5677_DSP_IB_01_H_SFT 15
@@ -1393,6 +1497,11 @@
#define RT5677_DSP_IB_9_L (0x1 << 1)
#define RT5677_DSP_IB_9_L_SFT 1
+/* General Control2 (0xfc)*/
+#define RT5677_GPIO5_FUNC_MASK (0x1 << 9)
+#define RT5677_GPIO5_FUNC_GPIO (0x0 << 9)
+#define RT5677_GPIO5_FUNC_DMIC (0x1 << 9)
+
/* System Clock Source */
enum {
RT5677_SCLK_S_MCLK,
@@ -1418,6 +1527,16 @@ enum {
RT5677_AIFS,
};
+enum {
+ RT5677_GPIO1,
+ RT5677_GPIO2,
+ RT5677_GPIO3,
+ RT5677_GPIO4,
+ RT5677_GPIO5,
+ RT5677_GPIO6,
+ RT5677_GPIO_NUM,
+};
+
struct rt5677_priv {
struct snd_soc_codec *codec;
struct rt5677_platform_data pdata;
@@ -1431,6 +1550,9 @@ struct rt5677_priv {
int pll_src;
int pll_in;
int pll_out;
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio_chip;
+#endif
};
#endif /* __RT5677_H__ */
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index e8680bea5f86..67ea55adb307 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -646,17 +646,6 @@ static struct snd_soc_dai_driver ssm2518_dai = {
.ops = &ssm2518_dai_ops,
};
-static int ssm2518_probe(struct snd_soc_codec *codec)
-{
- return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
-}
-
-static int ssm2518_remove(struct snd_soc_codec *codec)
-{
- ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir)
{
@@ -727,8 +716,6 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
}
static struct snd_soc_codec_driver ssm2518_codec_driver = {
- .probe = ssm2518_probe,
- .remove = ssm2518_remove,
.set_bias_level = ssm2518_set_bias_level,
.set_sysclk = ssm2518_set_sysclk,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 484b3bbe8624..527de0463548 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -502,18 +502,11 @@ static struct snd_soc_dai_driver ssm2602_dai = {
.symmetric_samplebits = 1,
};
-static int ssm2602_suspend(struct snd_soc_codec *codec)
-{
- ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static int ssm2602_resume(struct snd_soc_codec *codec)
{
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
regcache_sync(ssm2602->regmap);
- ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -586,27 +579,14 @@ static int ssm260x_codec_probe(struct snd_soc_codec *codec)
break;
}
- if (ret)
- return ret;
-
- ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-/* remove everything here */
-static int ssm2602_remove(struct snd_soc_codec *codec)
-{
- ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
+ return ret;
}
static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
.probe = ssm260x_codec_probe,
- .remove = ssm2602_remove,
- .suspend = ssm2602_suspend,
.resume = ssm2602_resume,
.set_bias_level = ssm2602_set_bias_level,
+ .suspend_bias_off = true,
.controls = ssm260x_snd_controls,
.num_controls = ARRAY_SIZE(ssm260x_snd_controls),
@@ -647,7 +627,7 @@ int ssm2602_probe(struct device *dev, enum ssm2602_type type,
return -ENOMEM;
dev_set_drvdata(dev, ssm2602);
- ssm2602->type = SSM2602;
+ ssm2602->type = type;
ssm2602->regmap = regmap;
return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602,
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 9aa1323fb2ab..89c748dd3d6e 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -4,7 +4,7 @@
* sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver
*
* Copyright (C) 2012 ST Microelectronics
- * Rajeev Kumar <rajeev-dlh.kumar@st.com>
+ * Rajeev Kumar <rajeevkumar.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -426,5 +426,5 @@ static struct i2c_driver sta529_i2c_driver = {
module_i2c_driver(sta529_i2c_driver);
MODULE_DESCRIPTION("ASoC STA529 codec driver");
-MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 0f64c7890eed..aea9e1ff9126 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -189,46 +189,57 @@ static const struct aic31xx_rate_divs aic31xx_divs[] = {
/* mclk rate pll: p j d dosr ndac mdac aors nadc madc */
/* 8k rate */
{12000000, 8000, 1, 8, 1920, 128, 48, 2, 128, 48, 2},
+ {12000000, 8000, 1, 8, 1920, 128, 32, 3, 128, 32, 3},
{24000000, 8000, 2, 8, 1920, 128, 48, 2, 128, 48, 2},
{25000000, 8000, 2, 7, 8643, 128, 48, 2, 128, 48, 2},
/* 11.025k rate */
{12000000, 11025, 1, 7, 5264, 128, 32, 2, 128, 32, 2},
+ {12000000, 11025, 1, 8, 4672, 128, 24, 3, 128, 24, 3},
{24000000, 11025, 2, 7, 5264, 128, 32, 2, 128, 32, 2},
{25000000, 11025, 2, 7, 2253, 128, 32, 2, 128, 32, 2},
/* 16k rate */
{12000000, 16000, 1, 8, 1920, 128, 24, 2, 128, 24, 2},
+ {12000000, 16000, 1, 8, 1920, 128, 16, 3, 128, 16, 3},
{24000000, 16000, 2, 8, 1920, 128, 24, 2, 128, 24, 2},
{25000000, 16000, 2, 7, 8643, 128, 24, 2, 128, 24, 2},
/* 22.05k rate */
{12000000, 22050, 1, 7, 5264, 128, 16, 2, 128, 16, 2},
+ {12000000, 22050, 1, 8, 4672, 128, 12, 3, 128, 12, 3},
{24000000, 22050, 2, 7, 5264, 128, 16, 2, 128, 16, 2},
{25000000, 22050, 2, 7, 2253, 128, 16, 2, 128, 16, 2},
/* 32k rate */
{12000000, 32000, 1, 8, 1920, 128, 12, 2, 128, 12, 2},
+ {12000000, 32000, 1, 8, 1920, 128, 8, 3, 128, 8, 3},
{24000000, 32000, 2, 8, 1920, 128, 12, 2, 128, 12, 2},
{25000000, 32000, 2, 7, 8643, 128, 12, 2, 128, 12, 2},
/* 44.1k rate */
{12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2},
+ {12000000, 44100, 1, 8, 4672, 128, 6, 3, 128, 6, 3},
{24000000, 44100, 2, 7, 5264, 128, 8, 2, 128, 8, 2},
{25000000, 44100, 2, 7, 2253, 128, 8, 2, 128, 8, 2},
/* 48k rate */
{12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2},
+ {12000000, 48000, 1, 7, 6800, 96, 5, 4, 96, 5, 4},
{24000000, 48000, 2, 8, 1920, 128, 8, 2, 128, 8, 2},
{25000000, 48000, 2, 7, 8643, 128, 8, 2, 128, 8, 2},
/* 88.2k rate */
{12000000, 88200, 1, 7, 5264, 64, 8, 2, 64, 8, 2},
+ {12000000, 88200, 1, 8, 4672, 64, 6, 3, 64, 6, 3},
{24000000, 88200, 2, 7, 5264, 64, 8, 2, 64, 8, 2},
{25000000, 88200, 2, 7, 2253, 64, 8, 2, 64, 8, 2},
/* 96k rate */
{12000000, 96000, 1, 8, 1920, 64, 8, 2, 64, 8, 2},
+ {12000000, 96000, 1, 7, 6800, 48, 5, 4, 48, 5, 4},
{24000000, 96000, 2, 8, 1920, 64, 8, 2, 64, 8, 2},
{25000000, 96000, 2, 7, 8643, 64, 8, 2, 64, 8, 2},
/* 176.4k rate */
{12000000, 176400, 1, 7, 5264, 32, 8, 2, 32, 8, 2},
+ {12000000, 176400, 1, 8, 4672, 32, 6, 3, 32, 6, 3},
{24000000, 176400, 2, 7, 5264, 32, 8, 2, 32, 8, 2},
{25000000, 176400, 2, 7, 2253, 32, 8, 2, 32, 8, 2},
/* 192k rate */
{12000000, 192000, 1, 8, 1920, 32, 8, 2, 32, 8, 2},
+ {12000000, 192000, 1, 7, 6800, 24, 5, 4, 24, 5, 4},
{24000000, 192000, 2, 8, 1920, 32, 8, 2, 32, 8, 2},
{25000000, 192000, 2, 7, 8643, 32, 8, 2, 32, 8, 2},
};
@@ -680,7 +691,9 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
struct snd_pcm_hw_params *params)
{
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+ int bclk_score = snd_soc_params_to_frame_size(params);
int bclk_n = 0;
+ int match = -1;
int i;
/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
@@ -691,15 +704,37 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
if (aic31xx_divs[i].rate == params_rate(params) &&
- aic31xx_divs[i].mclk == aic31xx->sysclk)
- break;
+ aic31xx_divs[i].mclk == aic31xx->sysclk) {
+ int s = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) %
+ snd_soc_params_to_frame_size(params);
+ int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) /
+ snd_soc_params_to_frame_size(params);
+ if (s < bclk_score && bn > 0) {
+ match = i;
+ bclk_n = bn;
+ bclk_score = s;
+ }
+ }
}
- if (i == ARRAY_SIZE(aic31xx_divs)) {
- dev_err(codec->dev, "%s: Sampling rate %u not supported\n",
+ if (match == -1) {
+ dev_err(codec->dev,
+ "%s: Sample rate (%u) and format not supported\n",
__func__, params_rate(params));
+ /* See bellow for details how fix this. */
return -EINVAL;
}
+ if (bclk_score != 0) {
+ dev_warn(codec->dev, "Can not produce exact bitclock");
+ /* This is fine if using dsp format, but if using i2s
+ there may be trouble. To fix the issue edit the
+ aic31xx_divs table for your mclk and sample
+ rate. Details can be found from:
+ http://www.ti.com/lit/ds/symlink/tlv320aic3100.pdf
+ Section: 5.6 CLOCK Generation and PLL
+ */
+ }
+ i = match;
/* PLL configuration */
snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
@@ -729,14 +764,6 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);
/* Bit clock divider configuration. */
- bclk_n = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac)
- / snd_soc_params_to_frame_size(params);
- if (bclk_n == 0) {
- dev_err(codec->dev, "%s: Not enough BLCK bandwidth\n",
- __func__);
- return -EINVAL;
- }
-
snd_soc_update_bits(codec, AIC31XX_BCLKN,
AIC31XX_PLL_MASK, bclk_n);
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 64f179ee9834..f2c416d16b6c 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1222,20 +1222,6 @@ static struct snd_soc_dai_driver aic3x_dai = {
.symmetric_rates = 1,
};
-static int aic3x_suspend(struct snd_soc_codec *codec)
-{
- aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int aic3x_resume(struct snd_soc_codec *codec)
-{
- aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
static void aic3x_mono_init(struct snd_soc_codec *codec)
{
/* DAC to Mono Line Out default volume and route to Output mixer */
@@ -1429,8 +1415,6 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
.idle_bias_off = true,
.probe = aic3x_probe,
.remove = aic3x_remove,
- .suspend = aic3x_suspend,
- .resume = aic3x_resume,
.controls = aic3x_snd_controls,
.num_controls = ARRAY_SIZE(aic3x_snd_controls),
.dapm_widgets = aic3x_dapm_widgets,
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 7bb0d36d4c54..a01ad629ed61 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2319,11 +2319,8 @@ static void wm5100_init_gpio(struct i2c_client *i2c)
static void wm5100_free_gpio(struct i2c_client *i2c)
{
struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
- int ret;
- ret = gpiochip_remove(&wm5100->gpio_chip);
- if (ret != 0)
- dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret);
+ gpiochip_remove(&wm5100->gpio_chip);
}
#else
static void wm5100_init_gpio(struct i2c_client *i2c)
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 3dfdcc4197fa..628ec774cf22 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -212,7 +212,7 @@ static void wm8350_pga_work(struct work_struct *work)
{
struct snd_soc_dapm_context *dapm =
container_of(work, struct snd_soc_dapm_context, delayed_work.work);
- struct snd_soc_codec *codec = dapm->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
struct wm8350_output *out1 = &wm8350_data->out1,
*out2 = &wm8350_data->out2;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index e54e097f4fcb..21ca3a94fc96 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1433,7 +1433,7 @@ static void wm8753_work(struct work_struct *work)
struct snd_soc_dapm_context *dapm =
container_of(work, struct snd_soc_dapm_context,
delayed_work.work);
- struct snd_soc_codec *codec = dapm->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
wm8753_set_bias_level(codec, dapm->bias_level);
}
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 0ea01dfcb6e1..3addc5fe5cb2 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -518,23 +518,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-#ifdef CONFIG_PM
-static int wm8804_suspend(struct snd_soc_codec *codec)
-{
- wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8804_resume(struct snd_soc_codec *codec)
-{
- wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define wm8804_suspend NULL
-#define wm8804_resume NULL
-#endif
-
static int wm8804_remove(struct snd_soc_codec *codec)
{
struct wm8804_priv *wm8804;
@@ -671,8 +654,6 @@ static struct snd_soc_dai_driver wm8804_dai = {
static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
.probe = wm8804_probe,
.remove = wm8804_remove,
- .suspend = wm8804_suspend,
- .resume = wm8804_resume,
.set_bias_level = wm8804_set_bias_level,
.idle_bias_off = true,
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index aa0984864e76..c038b3e04398 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1877,11 +1877,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903)
static void wm8903_free_gpio(struct wm8903_priv *wm8903)
{
- int ret;
-
- ret = gpiochip_remove(&wm8903->gpio_chip);
- if (ret != 0)
- dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret);
+ gpiochip_remove(&wm8903->gpio_chip);
}
#else
static void wm8903_init_gpio(struct wm8903_priv *wm8903)
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 1098ae32f1f9..9077411e62ce 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -3398,11 +3398,8 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec)
static void wm8962_free_gpio(struct snd_soc_codec *codec)
{
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
- int ret;
- ret = gpiochip_remove(&wm8962->gpio_chip);
- if (ret != 0)
- dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+ gpiochip_remove(&wm8962->gpio_chip);
}
#else
static void wm8962_init_gpio(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 0499cd4cfb71..39ddb9b8834c 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -615,7 +615,7 @@ static void wm8971_work(struct work_struct *work)
struct snd_soc_dapm_context *dapm =
container_of(work, struct snd_soc_dapm_context,
delayed_work.work);
- struct snd_soc_codec *codec = dapm->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
wm8971_set_bias_level(codec, codec->dapm.bias_level);
}
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index cae4ac5a5730..1288edeb8c7d 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -1998,23 +1998,6 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-#ifdef CONFIG_PM
-static int wm8995_suspend(struct snd_soc_codec *codec)
-{
- wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8995_resume(struct snd_soc_codec *codec)
-{
- wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define wm8995_suspend NULL
-#define wm8995_resume NULL
-#endif
-
static int wm8995_remove(struct snd_soc_codec *codec)
{
struct wm8995_priv *wm8995;
@@ -2220,8 +2203,6 @@ static struct snd_soc_dai_driver wm8995_dai[] = {
static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
.probe = wm8995_probe,
.remove = wm8995_remove,
- .suspend = wm8995_suspend,
- .resume = wm8995_resume,
.set_bias_level = wm8995_set_bias_level,
.idle_bias_off = true,
};
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index f16ff4f56923..b1dcc11c1b23 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -2216,11 +2216,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996)
static void wm8996_free_gpio(struct wm8996_priv *wm8996)
{
- int ret;
-
- ret = gpiochip_remove(&wm8996->gpio_chip);
- if (ret != 0)
- dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret);
+ gpiochip_remove(&wm8996->gpio_chip);
}
#else
static void wm8996_init_gpio(struct wm8996_priv *wm8996)
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index d69510c53239..8e948c63f3d9 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -63,7 +63,8 @@ config SND_DM365_AIC3X_CODEC
Say Y if you want to add support for AIC3101 audio codec
config SND_DM365_VOICE_CODEC
- bool "Voice Codec - CQ93VC"
+ tristate "Voice Codec - CQ93VC"
+ depends on SND_DAVINCI_SOC
select MFD_DAVINCI_VOICECODEC
select SND_DAVINCI_SOC_VCIF
select SND_SOC_CQ0093VC
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index c28508da34cf..0eed9b1b24e1 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -42,14 +42,26 @@
#define MCASP_MAX_AFIFO_DEPTH 64
+static u32 context_regs[] = {
+ DAVINCI_MCASP_TXFMCTL_REG,
+ DAVINCI_MCASP_RXFMCTL_REG,
+ DAVINCI_MCASP_TXFMT_REG,
+ DAVINCI_MCASP_RXFMT_REG,
+ DAVINCI_MCASP_ACLKXCTL_REG,
+ DAVINCI_MCASP_ACLKRCTL_REG,
+ DAVINCI_MCASP_AHCLKXCTL_REG,
+ DAVINCI_MCASP_AHCLKRCTL_REG,
+ DAVINCI_MCASP_PDIR_REG,
+ DAVINCI_MCASP_RXMASK_REG,
+ DAVINCI_MCASP_TXMASK_REG,
+ DAVINCI_MCASP_RXTDM_REG,
+ DAVINCI_MCASP_TXTDM_REG,
+};
+
struct davinci_mcasp_context {
- u32 txfmtctl;
- u32 rxfmtctl;
- u32 txfmt;
- u32 rxfmt;
- u32 aclkxctl;
- u32 aclkrctl;
- u32 pdir;
+ u32 config_regs[ARRAY_SIZE(context_regs)];
+ u32 afifo_regs[2]; /* for read/write fifo control registers */
+ u32 *xrsr_regs; /* for serializer configuration */
};
struct davinci_mcasp {
@@ -403,7 +415,8 @@ out:
return ret;
}
-static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
+ int div, bool explicit)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
@@ -420,7 +433,8 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div
ACLKXDIV(div - 1), ACLKXDIV_MASK);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
ACLKRDIV(div - 1), ACLKRDIV_MASK);
- mcasp->bclk_div = div;
+ if (explicit)
+ mcasp->bclk_div = div;
break;
case 2: /* BCLK/LRCLK ratio */
@@ -434,6 +448,12 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div
return 0;
}
+static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
+ int div)
+{
+ return __davinci_mcasp_set_clkdiv(dai, div_id, div, 1);
+}
+
static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
@@ -459,8 +479,17 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
{
u32 fmt;
u32 tx_rotate = (word_length / 4) & 0x7;
- u32 rx_rotate = (32 - word_length) / 4;
u32 mask = (1ULL << word_length) - 1;
+ /*
+ * For captured data we should not rotate, inversion and masking is
+ * enoguh to get the data to the right position:
+ * Format data from bus after reverse (XRBUF)
+ * S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB|
+ * S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB|
+ * S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB|
+ * S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB|
+ */
+ u32 rx_rotate = 0;
/*
* if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv()
@@ -738,7 +767,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
"Inaccurate BCLK: %u Hz / %u != %u Hz\n",
mcasp->sysclk_freq, div, bclk_freq);
}
- davinci_mcasp_set_clkdiv(cpu_dai, 1, div);
+ __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0);
}
ret = mcasp_common_hw_param(mcasp, substream->stream,
@@ -857,14 +886,24 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
struct davinci_mcasp_context *context = &mcasp->context;
+ u32 reg;
+ int i;
- context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
- context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
- context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
- context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
- context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
- context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
- context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
+ for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+ context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]);
+
+ if (mcasp->txnumevt) {
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ context->afifo_regs[0] = mcasp_get_reg(mcasp, reg);
+ }
+ if (mcasp->rxnumevt) {
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ context->afifo_regs[1] = mcasp_get_reg(mcasp, reg);
+ }
+
+ for (i = 0; i < mcasp->num_serializer; i++)
+ context->xrsr_regs[i] = mcasp_get_reg(mcasp,
+ DAVINCI_MCASP_XRSRCTL_REG(i));
return 0;
}
@@ -873,14 +912,24 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
struct davinci_mcasp_context *context = &mcasp->context;
+ u32 reg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(context_regs); i++)
+ mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]);
+
+ if (mcasp->txnumevt) {
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ mcasp_set_reg(mcasp, reg, context->afifo_regs[0]);
+ }
+ if (mcasp->rxnumevt) {
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ mcasp_set_reg(mcasp, reg, context->afifo_regs[1]);
+ }
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir);
+ for (i = 0; i < mcasp->num_serializer; i++)
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+ context->xrsr_regs[i]);
return 0;
}
@@ -1199,6 +1248,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->op_mode = pdata->op_mode;
mcasp->tdm_slots = pdata->tdm_slots;
mcasp->num_serializer = pdata->num_serializer;
+#ifdef CONFIG_PM_SLEEP
+ mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev,
+ sizeof(u32) * mcasp->num_serializer,
+ GFP_KERNEL);
+#endif
mcasp->serial_dir = pdata->serial_dir;
mcasp->version = pdata->version;
mcasp->txnumevt = pdata->txnumevt;
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c
index 605e643133db..59e588abe54b 100644
--- a/sound/soc/davinci/edma-pcm.c
+++ b/sound/soc/davinci/edma-pcm.c
@@ -25,6 +25,8 @@
#include <sound/dmaengine_pcm.h>
#include <linux/edma.h>
+#include "edma-pcm.h"
+
static const struct snd_pcm_hardware edma_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index 25c31f1655f6..e961388e6e9c 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -4,7 +4,7 @@
* sound/soc/dwc/designware_i2s.c
*
* Copyright (C) 2010 ST Microelectronics
- * Rajeev Kumar <rajeev-dlh.kumar@st.com>
+ * Rajeev Kumar <rajeevkumar.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -455,7 +455,7 @@ static struct platform_driver dw_i2s_driver = {
module_platform_driver(dw_i2s_driver);
-MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>");
MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:designware_i2s");
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 7c1da8ede975..081e406b3713 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -49,7 +49,6 @@ config SND_SOC_FSL_ESAI
tristate "Enhanced Serial Audio Interface (ESAI) module support"
select REGMAP_MMIO
select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
- select SND_SOC_FSL_UTILS
help
Say Y if you want to add Enhanced Synchronous Audio Interface
(ESAI) support for the Freescale CPUs.
@@ -289,9 +288,6 @@ config SND_SOC_FSL_ASOC_CARD
select SND_SOC_FSL_ESAI
select SND_SOC_FSL_SAI
select SND_SOC_FSL_SSI
- select SND_SOC_CS42XX8_I2C
- select SND_SOC_SGTL5000
- select SND_SOC_WM8962
help
ALSA SoC Audio support with ASRC feature for Freescale SoCs that have
ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 2882fc66a10d..8bcdfda09d7a 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -18,7 +18,6 @@
#include "fsl_esai.h"
#include "imx-pcm.h"
-#include "fsl_utils.h"
#define FSL_ESAI_RATES SNDRV_PCM_RATE_8000_192000
#define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
@@ -38,6 +37,7 @@
* @fsysclk: system clock source to derive HCK, SCK and FS
* @fifo_depth: depth of tx/rx FIFO
* @slot_width: width of each DAI slot
+ * @slots: number of slots
* @hck_rate: clock rate of desired HCKx clock
* @sck_rate: clock rate of desired SCKx clock
* @hck_dir: the direction of HCKx pads
@@ -56,6 +56,7 @@ struct fsl_esai {
struct clk *fsysclk;
u32 fifo_depth;
u32 slot_width;
+ u32 slots;
u32 hck_rate[2];
u32 sck_rate[2];
bool hck_dir[2];
@@ -363,6 +364,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
esai_priv->slot_width = slot_width;
+ esai_priv->slots = slots;
return 0;
}
@@ -510,10 +512,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 width = snd_pcm_format_width(params_format(params));
u32 channels = params_channels(params);
+ u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
u32 bclk, mask, val;
int ret;
- bclk = params_rate(params) * esai_priv->slot_width * 2;
+ bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots;
ret = fsl_esai_set_bclk(dai, tx, bclk);
if (ret)
@@ -530,7 +533,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
(tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) |
- (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
+ (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins));
regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
@@ -565,6 +568,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u8 i, channels = substream->runtime->channels;
+ u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -579,7 +583,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
- tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
+ tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins));
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
@@ -607,7 +611,6 @@ static struct snd_soc_dai_ops fsl_esai_dai_ops = {
.hw_params = fsl_esai_hw_params,
.set_sysclk = fsl_esai_set_dai_sysclk,
.set_fmt = fsl_esai_set_dai_fmt,
- .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
.set_tdm_slot = fsl_esai_set_dai_tdm_slot,
};
@@ -780,6 +783,9 @@ static int fsl_esai_probe(struct platform_device *pdev)
/* Set a default slot size */
esai_priv->slot_width = 32;
+ /* Set a default slot number */
+ esai_priv->slots = 2;
+
/* Set a default master/slave state */
esai_priv->slave_mode = true;
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
index 75e14033e8d8..91a550f4a10d 100644
--- a/sound/soc/fsl/fsl_esai.h
+++ b/sound/soc/fsl/fsl_esai.h
@@ -130,8 +130,8 @@
#define ESAI_xFCR_RE_WIDTH 4
#define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
#define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
-#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK)
-#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK)
+#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK)
+#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK)
#define ESAI_xFCR_xFR_SHIFT 1
#define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT)
#define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT)
@@ -272,8 +272,8 @@
#define ESAI_xCR_RE_WIDTH 4
#define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
#define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
-#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK)
-#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK)
+#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK)
+#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK)
/*
* Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 87eb5776a39b..e6955170dc42 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -169,6 +169,7 @@ struct fsl_ssi_private {
u8 i2s_mode;
bool use_dma;
bool use_dual_fifo;
+ bool has_ipg_clk_name;
unsigned int fifo_depth;
struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
@@ -259,6 +260,11 @@ static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private)
SND_SOC_DAIFMT_CBS_CFS;
}
+static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private)
+{
+ return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+ SND_SOC_DAIFMT_CBM_CFS;
+}
/**
* fsl_ssi_isr: SSI interrupt handler
*
@@ -525,6 +531,11 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_ssi_private *ssi_private =
snd_soc_dai_get_drvdata(rtd->cpu_dai);
+ int ret;
+
+ ret = clk_prepare_enable(ssi_private->clk);
+ if (ret)
+ return ret;
/* When using dual fifo mode, it is safer to ensure an even period
* size. If appearing to an odd number while DMA always starts its
@@ -539,6 +550,21 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
}
/**
+ * fsl_ssi_shutdown: shutdown the SSI
+ *
+ */
+static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct fsl_ssi_private *ssi_private =
+ snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+ clk_disable_unprepare(ssi_private->clk);
+
+}
+
+/**
* fsl_ssi_set_bclk - configure Digital Audio Interface bit clock
*
* Note: This function can be only called when using SSI as DAI master
@@ -705,6 +731,23 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
}
}
+ if (!fsl_ssi_is_ac97(ssi_private)) {
+ u8 i2smode;
+ /*
+ * Switch to normal net mode in order to have a frame sync
+ * signal every 32 bits instead of 16 bits
+ */
+ if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16)
+ i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL |
+ CCSR_SSI_SCR_NET;
+ else
+ i2smode = ssi_private->i2s_mode;
+
+ regmap_update_bits(regs, CCSR_SSI_SCR,
+ CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
+ channels == 1 ? 0 : i2smode);
+ }
+
/*
* FIXME: The documentation says that SxCCR[WL] should not be
* modified while the SSI is enabled. The only time this can
@@ -724,11 +767,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK,
wl);
- if (!fsl_ssi_is_ac97(ssi_private))
- regmap_update_bits(regs, CCSR_SSI_SCR,
- CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
- channels == 1 ? 0 : ssi_private->i2s_mode);
-
return 0;
}
@@ -748,8 +786,9 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream,
return 0;
}
-static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private,
- unsigned int fmt)
+static int _fsl_ssi_set_dai_fmt(struct device *dev,
+ struct fsl_ssi_private *ssi_private,
+ unsigned int fmt)
{
struct regmap *regs = ssi_private->regs;
u32 strcr = 0, stcr, srcr, scr, mask;
@@ -758,7 +797,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private,
ssi_private->dai_fmt = fmt;
if (fsl_ssi_is_i2s_master(ssi_private) && IS_ERR(ssi_private->baudclk)) {
- dev_err(&ssi_private->pdev->dev, "baudclk is missing which is necessary for master mode\n");
+ dev_err(dev, "baudclk is missing which is necessary for master mode\n");
return -EINVAL;
}
@@ -780,6 +819,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFS:
case SND_SOC_DAIFMT_CBS_CFS:
ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER;
regmap_update_bits(regs, CCSR_SSI_STCCR,
@@ -853,6 +893,11 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private,
case SND_SOC_DAIFMT_CBM_CFM:
scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ strcr &= ~CCSR_SSI_STCR_TXDIR;
+ strcr |= CCSR_SSI_STCR_TFDIR;
+ scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
+ break;
default:
return -EINVAL;
}
@@ -913,7 +958,7 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
- return _fsl_ssi_set_dai_fmt(ssi_private, fmt);
+ return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi_private, fmt);
}
/**
@@ -1020,6 +1065,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
.startup = fsl_ssi_startup,
+ .shutdown = fsl_ssi_shutdown,
.hw_params = fsl_ssi_hw_params,
.hw_free = fsl_ssi_hw_free,
.set_fmt = fsl_ssi_set_dai_fmt,
@@ -1145,17 +1191,22 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
u32 dmas[4];
int ret;
- ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
+ if (ssi_private->has_ipg_clk_name)
+ ssi_private->clk = devm_clk_get(&pdev->dev, "ipg");
+ else
+ ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ssi_private->clk)) {
ret = PTR_ERR(ssi_private->clk);
dev_err(&pdev->dev, "could not get clock: %d\n", ret);
return ret;
}
- ret = clk_prepare_enable(ssi_private->clk);
- if (ret) {
- dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
- return ret;
+ if (!ssi_private->has_ipg_clk_name) {
+ ret = clk_prepare_enable(ssi_private->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
}
/* For those SLAVE implementations, we ingore non-baudclk cases
@@ -1213,8 +1264,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
return 0;
error_pcm:
- clk_disable_unprepare(ssi_private->clk);
+ if (!ssi_private->has_ipg_clk_name)
+ clk_disable_unprepare(ssi_private->clk);
return ret;
}
@@ -1223,7 +1275,8 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev,
{
if (!ssi_private->use_dma)
imx_pcm_fiq_exit(pdev);
- clk_disable_unprepare(ssi_private->clk);
+ if (!ssi_private->has_ipg_clk_name)
+ clk_disable_unprepare(ssi_private->clk);
}
static int fsl_ssi_probe(struct platform_device *pdev)
@@ -1262,9 +1315,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
if (sprop) {
if (!strcmp(sprop, "ac97-slave"))
ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97;
- else if (!strcmp(sprop, "i2s-slave"))
- ssi_private->dai_fmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_CBM_CFM;
}
ssi_private->use_dma = !of_property_read_bool(np,
@@ -1298,8 +1348,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
return -ENOMEM;
}
- ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
+ ret = of_property_match_string(np, "clock-names", "ipg");
+ if (ret < 0) {
+ ssi_private->has_ipg_clk_name = false;
+ ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
&fsl_ssi_regconfig);
+ } else {
+ ssi_private->has_ipg_clk_name = true;
+ ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev,
+ "ipg", iomem, &fsl_ssi_regconfig);
+ }
if (IS_ERR(ssi_private->regs)) {
dev_err(&pdev->dev, "Failed to init register map\n");
return PTR_ERR(ssi_private->regs);
@@ -1387,7 +1445,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
done:
if (ssi_private->dai_fmt)
- _fsl_ssi_set_dai_fmt(ssi_private, ssi_private->dai_fmt);
+ _fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private,
+ ssi_private->dai_fmt);
return 0;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 159e517fa09a..cef7776b712c 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -481,12 +481,19 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&priv->snd_card, priv);
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+ if (ret >= 0)
+ return ret;
err:
asoc_simple_card_unref(pdev);
return ret;
}
+static int asoc_simple_card_remove(struct platform_device *pdev)
+{
+ return asoc_simple_card_unref(pdev);
+}
+
static const struct of_device_id asoc_simple_of_match[] = {
{ .compatible = "simple-audio-card", },
{},
@@ -500,6 +507,7 @@ static struct platform_driver asoc_simple_card = {
.of_match_table = asoc_simple_of_match,
},
.probe = asoc_simple_card_probe,
+ .remove = asoc_simple_card_remove,
};
module_platform_driver(asoc_simple_card);
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 7acbfc43a0c6..f841786dad15 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -2,7 +2,8 @@
snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
snd-soc-sst-acpi-objs := sst-acpi.o
-snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o
+snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \
+ sst-mfld-platform-compress.o sst-atom-controls.o
snd-soc-mfld-machine-objs := mfld_machine.o
obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c
index b8b8af571ef1..d52681e7225e 100644
--- a/sound/soc/intel/byt-max98090.c
+++ b/sound/soc/intel/byt-max98090.c
@@ -139,6 +139,7 @@ static struct snd_soc_card byt_max98090_card = {
.num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map),
.controls = byt_max98090_controls,
.num_controls = ARRAY_SIZE(byt_max98090_controls),
+ .fully_routed = true,
};
static int byt_max98090_probe(struct platform_device *pdev)
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c
index 234a58de3c53..e03abdf21c1b 100644
--- a/sound/soc/intel/byt-rt5640.c
+++ b/sound/soc/intel/byt-rt5640.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/device.h>
+#include <linux/dmi.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -36,8 +37,6 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
{"Headset Mic", NULL, "MICBIAS1"},
{"IN2P", NULL, "Headset Mic"},
- {"IN2N", NULL, "Headset Mic"},
- {"DMIC1", NULL, "Internal Mic"},
{"Headphone", NULL, "HPOL"},
{"Headphone", NULL, "HPOR"},
{"Speaker", NULL, "SPOLP"},
@@ -46,6 +45,31 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
{"Speaker", NULL, "SPORN"},
};
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
+ {"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
+ {"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
+ {"Internal Mic", NULL, "MICBIAS1"},
+ {"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"),
@@ -77,12 +101,41 @@ static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
+{
+ byt_rt5640_quirk = (unsigned long)id->driver_data;
+ return 1;
+}
+
+static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+ {
+ .callback = byt_rt5640_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+ },
+ .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+ },
+ {
+ .callback = byt_rt5640_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
+ },
+ .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
+ BYT_RT5640_DMIC_EN),
+ },
+ {}
+};
+
static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
{
int ret;
struct snd_soc_codec *codec = runtime->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_card *card = runtime->card;
+ const struct snd_soc_dapm_route *custom_map;
+ int num_routes;
card->dapm.idle_bias_off = true;
@@ -93,6 +146,31 @@ 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;
+ num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
+ break;
+ case BYT_RT5640_DMIC2_MAP:
+ custom_map = byt_rt5640_intmic_dmic2_map;
+ num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
+ break;
+ default:
+ custom_map = byt_rt5640_intmic_dmic1_map;
+ num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
+ }
+
+ ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+ if (ret)
+ return ret;
+
+ if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
+ ret = rt5640_dmic_enable(codec, 0, 0);
+ if (ret)
+ return ret;
+ }
+
snd_soc_dapm_ignore_suspend(dapm, "HPOL");
snd_soc_dapm_ignore_suspend(dapm, "HPOR");
@@ -131,6 +209,7 @@ static struct snd_soc_card byt_rt5640_card = {
.num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
.dapm_routes = byt_rt5640_audio_map,
.num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
+ .fully_routed = true,
};
static int byt_rt5640_probe(struct platform_device *pdev)
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c
index 42edc6f4fc4a..03d0a166b635 100644
--- a/sound/soc/intel/sst-acpi.c
+++ b/sound/soc/intel/sst-acpi.c
@@ -246,8 +246,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
};
static struct sst_acpi_mach baytrail_machines[] = {
- { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" },
- { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-i2s_master" },
+ { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
+ { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
{}
};
diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c
new file mode 100644
index 000000000000..7104a34181a9
--- /dev/null
+++ b/sound/soc/intel/sst-atom-controls.c
@@ -0,0 +1,218 @@
+/*
+ * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld
+ *
+ * Copyright (C) 2013-14 Intel Corp
+ * Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
+ * Vinod Koul <vinod.koul@intel.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; version 2 of the License.
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "sst-mfld-platform.h"
+#include "sst-atom-controls.h"
+
+static int sst_fill_byte_control(struct sst_data *drv,
+ u8 ipc_msg, u8 block,
+ u8 task_id, u8 pipe_id,
+ u16 len, void *cmd_data)
+{
+ struct snd_sst_bytes_v2 *byte_data = drv->byte_stream;
+
+ byte_data->type = SST_CMD_BYTES_SET;
+ byte_data->ipc_msg = ipc_msg;
+ byte_data->block = block;
+ byte_data->task_id = task_id;
+ byte_data->pipe_id = pipe_id;
+
+ if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) {
+ dev_err(&drv->pdev->dev, "command length too big (%u)", len);
+ return -EINVAL;
+ }
+ byte_data->len = len;
+ memcpy(byte_data->bytes, cmd_data, len);
+ print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET,
+ byte_data, len + sizeof(*byte_data));
+ return 0;
+}
+
+static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
+ u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+ void *cmd_data, u16 len)
+{
+ int ret = 0;
+
+ ret = sst_fill_byte_control(drv, ipc_msg,
+ block, task_id, pipe_id, len, cmd_data);
+ if (ret < 0)
+ return ret;
+ return sst->ops->send_byte_stream(sst->dev, drv->byte_stream);
+}
+
+/**
+ * sst_fill_and_send_cmd - generate the IPC message and send it to the FW
+ * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS)
+ * @cmd_data: the IPC payload
+ */
+static int sst_fill_and_send_cmd(struct sst_data *drv,
+ u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+ void *cmd_data, u16 len)
+{
+ int ret;
+
+ mutex_lock(&drv->lock);
+ ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
+ task_id, pipe_id, cmd_data, len);
+ mutex_unlock(&drv->lock);
+
+ return ret;
+}
+
+static int sst_send_algo_cmd(struct sst_data *drv,
+ struct sst_algo_control *bc)
+{
+ int len, ret = 0;
+ struct sst_cmd_set_params *cmd;
+
+ /*bc->max includes sizeof algos + length field*/
+ len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max;
+
+ cmd = kzalloc(len, GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id);
+ cmd->command_id = bc->cmd_id;
+ memcpy(cmd->params, bc->params, bc->max);
+
+ ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
+ SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len);
+ kfree(cmd);
+ return ret;
+}
+
+static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = bc->max;
+
+ return 0;
+}
+
+static int sst_algo_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sst_algo_control *bc = (void *)kcontrol->private_value;
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+
+ switch (bc->type) {
+ case SST_ALGO_PARAMS:
+ memcpy(ucontrol->value.bytes.data, bc->params, bc->max);
+ break;
+ default:
+ dev_err(component->dev, "Invalid Input- algo type:%d\n",
+ bc->type);
+ return -EINVAL;
+
+ }
+ return 0;
+}
+
+static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
+ struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+ dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
+ mutex_lock(&drv->lock);
+ switch (bc->type) {
+ case SST_ALGO_PARAMS:
+ memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
+ break;
+ default:
+ mutex_unlock(&drv->lock);
+ dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
+ bc->type);
+ return -EINVAL;
+ }
+ /*if pipe is enabled, need to send the algo params from here*/
+ if (bc->w && bc->w->power)
+ ret = sst_send_algo_cmd(drv, bc);
+ mutex_unlock(&drv->lock);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new sst_algo_controls[] = {
+ SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24,
+ SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+ SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24,
+ SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+ SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+ SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+ SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24,
+ SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+ SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24,
+ SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+ SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+ SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+ SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT,
+ SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO),
+ SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+ SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+ SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+ SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+
+};
+
+static int sst_algo_control_init(struct device *dev)
+{
+ int i = 0;
+ struct sst_algo_control *bc;
+ /*allocate space to cache the algo parameters in the driver*/
+ for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) {
+ bc = (struct sst_algo_control *)sst_algo_controls[i].private_value;
+ bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL);
+ if (bc->params == NULL)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
+{
+ int ret = 0;
+ struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
+
+ drv->byte_stream = devm_kzalloc(platform->dev,
+ SST_MAX_BIN_BYTES, GFP_KERNEL);
+ if (!drv->byte_stream)
+ return -ENOMEM;
+
+ /*Initialize algo control params*/
+ ret = sst_algo_control_init(platform->dev);
+ if (ret)
+ return ret;
+ ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
+ ARRAY_SIZE(sst_algo_controls));
+ return ret;
+}
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h
index 14063ab8c7c5..a73e894b175c 100644
--- a/sound/soc/intel/sst-atom-controls.h
+++ b/sound/soc/intel/sst-atom-controls.h
@@ -1,4 +1,6 @@
/*
+ * sst-atom-controls.h - Intel MID Platform driver header file
+ *
* Copyright (C) 2013-14 Intel Corp
* Author: Ramesh Babu <ramesh.babu.koul@intel.com>
* Omair M Abdullah <omair.m.abdullah@intel.com>
@@ -18,13 +20,423 @@
*
*/
-#ifndef __SST_CONTROLS_V2_H__
-#define __SST_CONTROLS_V2_H__
+#ifndef __SST_ATOM_CONTROLS_H__
+#define __SST_ATOM_CONTROLS_H__
enum {
MERR_DPCM_AUDIO = 0,
MERR_DPCM_COMPR,
};
+/* define a bit for each mixer input */
+#define SST_MIX_IP(x) (x)
+
+#define SST_IP_CODEC0 SST_MIX_IP(2)
+#define SST_IP_CODEC1 SST_MIX_IP(3)
+#define SST_IP_LOOP0 SST_MIX_IP(4)
+#define SST_IP_LOOP1 SST_MIX_IP(5)
+#define SST_IP_LOOP2 SST_MIX_IP(6)
+#define SST_IP_PROBE SST_MIX_IP(7)
+#define SST_IP_VOIP SST_MIX_IP(12)
+#define SST_IP_PCM0 SST_MIX_IP(13)
+#define SST_IP_PCM1 SST_MIX_IP(14)
+#define SST_IP_MEDIA0 SST_MIX_IP(17)
+#define SST_IP_MEDIA1 SST_MIX_IP(18)
+#define SST_IP_MEDIA2 SST_MIX_IP(19)
+#define SST_IP_MEDIA3 SST_MIX_IP(20)
+
+#define SST_IP_LAST SST_IP_MEDIA3
+
+#define SST_SWM_INPUT_COUNT (SST_IP_LAST + 1)
+#define SST_CMD_SWM_MAX_INPUTS 6
+
+#define SST_PATH_ID_SHIFT 8
+#define SST_DEFAULT_LOCATION_ID 0xFFFF
+#define SST_DEFAULT_CELL_NBR 0xFF
+#define SST_DEFAULT_MODULE_ID 0xFFFF
+
+/*
+ * Audio DSP Path Ids. Specified by the audio DSP FW
+ */
+enum sst_path_index {
+ SST_PATH_INDEX_CODEC_OUT0 = (0x02 << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_CODEC_OUT1 = (0x03 << SST_PATH_ID_SHIFT),
+
+ SST_PATH_INDEX_SPROT_LOOP_OUT = (0x04 << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_MEDIA_LOOP1_OUT = (0x05 << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_MEDIA_LOOP2_OUT = (0x06 << SST_PATH_ID_SHIFT),
+
+ SST_PATH_INDEX_VOIP_OUT = (0x0C << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_PCM0_OUT = (0x0D << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_PCM1_OUT = (0x0E << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_PCM2_OUT = (0x0F << SST_PATH_ID_SHIFT),
+
+ SST_PATH_INDEX_MEDIA0_OUT = (0x12 << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_MEDIA1_OUT = (0x13 << SST_PATH_ID_SHIFT),
+
+
+ /* Start of input paths */
+ SST_PATH_INDEX_CODEC_IN0 = (0x82 << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_CODEC_IN1 = (0x83 << SST_PATH_ID_SHIFT),
+
+ SST_PATH_INDEX_SPROT_LOOP_IN = (0x84 << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_MEDIA_LOOP1_IN = (0x85 << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_MEDIA_LOOP2_IN = (0x86 << SST_PATH_ID_SHIFT),
+
+ SST_PATH_INDEX_VOIP_IN = (0x8C << SST_PATH_ID_SHIFT),
+
+ SST_PATH_INDEX_PCM0_IN = (0x8D << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_PCM1_IN = (0x8E << SST_PATH_ID_SHIFT),
+
+ SST_PATH_INDEX_MEDIA0_IN = (0x8F << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_MEDIA1_IN = (0x90 << SST_PATH_ID_SHIFT),
+ SST_PATH_INDEX_MEDIA2_IN = (0x91 << SST_PATH_ID_SHIFT),
+
+ SST_PATH_INDEX_MEDIA3_IN = (0x9C << SST_PATH_ID_SHIFT),
+
+ SST_PATH_INDEX_RESERVED = (0xFF << SST_PATH_ID_SHIFT),
+};
+
+/*
+ * path IDs
+ */
+enum sst_swm_inputs {
+ SST_SWM_IN_CODEC0 = (SST_PATH_INDEX_CODEC_IN0 | SST_DEFAULT_CELL_NBR),
+ SST_SWM_IN_CODEC1 = (SST_PATH_INDEX_CODEC_IN1 | SST_DEFAULT_CELL_NBR),
+ SST_SWM_IN_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_IN | SST_DEFAULT_CELL_NBR),
+ SST_SWM_IN_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_IN | SST_DEFAULT_CELL_NBR),
+ SST_SWM_IN_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_IN | SST_DEFAULT_CELL_NBR),
+ SST_SWM_IN_VOIP = (SST_PATH_INDEX_VOIP_IN | SST_DEFAULT_CELL_NBR),
+ SST_SWM_IN_PCM0 = (SST_PATH_INDEX_PCM0_IN | SST_DEFAULT_CELL_NBR),
+ SST_SWM_IN_PCM1 = (SST_PATH_INDEX_PCM1_IN | SST_DEFAULT_CELL_NBR),
+ SST_SWM_IN_MEDIA0 = (SST_PATH_INDEX_MEDIA0_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+ SST_SWM_IN_MEDIA1 = (SST_PATH_INDEX_MEDIA1_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+ SST_SWM_IN_MEDIA2 = (SST_PATH_INDEX_MEDIA2_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+ SST_SWM_IN_MEDIA3 = (SST_PATH_INDEX_MEDIA3_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+ SST_SWM_IN_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR)
+};
+
+/*
+ * path IDs
+ */
+enum sst_swm_outputs {
+ SST_SWM_OUT_CODEC0 = (SST_PATH_INDEX_CODEC_OUT0 | SST_DEFAULT_CELL_NBR),
+ SST_SWM_OUT_CODEC1 = (SST_PATH_INDEX_CODEC_OUT1 | SST_DEFAULT_CELL_NBR),
+ SST_SWM_OUT_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_OUT | SST_DEFAULT_CELL_NBR),
+ SST_SWM_OUT_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR),
+ SST_SWM_OUT_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR),
+ SST_SWM_OUT_VOIP = (SST_PATH_INDEX_VOIP_OUT | SST_DEFAULT_CELL_NBR),
+ SST_SWM_OUT_PCM0 = (SST_PATH_INDEX_PCM0_OUT | SST_DEFAULT_CELL_NBR),
+ SST_SWM_OUT_PCM1 = (SST_PATH_INDEX_PCM1_OUT | SST_DEFAULT_CELL_NBR),
+ SST_SWM_OUT_PCM2 = (SST_PATH_INDEX_PCM2_OUT | SST_DEFAULT_CELL_NBR),
+ SST_SWM_OUT_MEDIA0 = (SST_PATH_INDEX_MEDIA0_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+ SST_SWM_OUT_MEDIA1 = (SST_PATH_INDEX_MEDIA1_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */
+ SST_SWM_OUT_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR),
+};
+
+enum sst_ipc_msg {
+ SST_IPC_IA_CMD = 1,
+ SST_IPC_IA_SET_PARAMS,
+ SST_IPC_IA_GET_PARAMS,
+};
+
+enum sst_cmd_type {
+ SST_CMD_BYTES_SET = 1,
+ SST_CMD_BYTES_GET = 2,
+};
+
+enum sst_task {
+ SST_TASK_SBA = 1,
+ SST_TASK_MMX,
+};
+
+enum sst_type {
+ SST_TYPE_CMD = 1,
+ SST_TYPE_PARAMS,
+};
+
+enum sst_flag {
+ SST_FLAG_BLOCKED = 1,
+ SST_FLAG_NONBLOCK,
+};
+
+/*
+ * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command
+ */
+enum sst_gain_index {
+ /* GAIN IDs for SB task start here */
+ SST_GAIN_INDEX_CODEC_OUT0,
+ SST_GAIN_INDEX_CODEC_OUT1,
+ SST_GAIN_INDEX_CODEC_IN0,
+ SST_GAIN_INDEX_CODEC_IN1,
+
+ SST_GAIN_INDEX_SPROT_LOOP_OUT,
+ SST_GAIN_INDEX_MEDIA_LOOP1_OUT,
+ SST_GAIN_INDEX_MEDIA_LOOP2_OUT,
+
+ SST_GAIN_INDEX_PCM0_IN_LEFT,
+ SST_GAIN_INDEX_PCM0_IN_RIGHT,
+
+ SST_GAIN_INDEX_PCM1_OUT_LEFT,
+ SST_GAIN_INDEX_PCM1_OUT_RIGHT,
+ SST_GAIN_INDEX_PCM1_IN_LEFT,
+ SST_GAIN_INDEX_PCM1_IN_RIGHT,
+ SST_GAIN_INDEX_PCM2_OUT_LEFT,
+
+ SST_GAIN_INDEX_PCM2_OUT_RIGHT,
+ SST_GAIN_INDEX_VOIP_OUT,
+ SST_GAIN_INDEX_VOIP_IN,
+
+ /* Gain IDs for MMX task start here */
+ SST_GAIN_INDEX_MEDIA0_IN_LEFT,
+ SST_GAIN_INDEX_MEDIA0_IN_RIGHT,
+ SST_GAIN_INDEX_MEDIA1_IN_LEFT,
+ SST_GAIN_INDEX_MEDIA1_IN_RIGHT,
+
+ SST_GAIN_INDEX_MEDIA2_IN_LEFT,
+ SST_GAIN_INDEX_MEDIA2_IN_RIGHT,
+
+ SST_GAIN_INDEX_GAIN_END
+};
+
+/*
+ * Audio DSP module IDs specified by FW spec
+ * TODO: Update with all modules
+ */
+enum sst_module_id {
+ SST_MODULE_ID_PCM = 0x0001,
+ SST_MODULE_ID_MP3 = 0x0002,
+ SST_MODULE_ID_MP24 = 0x0003,
+ SST_MODULE_ID_AAC = 0x0004,
+ SST_MODULE_ID_AACP = 0x0005,
+ SST_MODULE_ID_EAACP = 0x0006,
+ SST_MODULE_ID_WMA9 = 0x0007,
+ SST_MODULE_ID_WMA10 = 0x0008,
+ SST_MODULE_ID_WMA10P = 0x0009,
+ SST_MODULE_ID_RA = 0x000A,
+ SST_MODULE_ID_DDAC3 = 0x000B,
+ SST_MODULE_ID_TRUE_HD = 0x000C,
+ SST_MODULE_ID_HD_PLUS = 0x000D,
+
+ SST_MODULE_ID_SRC = 0x0064,
+ SST_MODULE_ID_DOWNMIX = 0x0066,
+ SST_MODULE_ID_GAIN_CELL = 0x0067,
+ SST_MODULE_ID_SPROT = 0x006D,
+ SST_MODULE_ID_BASS_BOOST = 0x006E,
+ SST_MODULE_ID_STEREO_WDNG = 0x006F,
+ SST_MODULE_ID_AV_REMOVAL = 0x0070,
+ SST_MODULE_ID_MIC_EQ = 0x0071,
+ SST_MODULE_ID_SPL = 0x0072,
+ SST_MODULE_ID_ALGO_VTSV = 0x0073,
+ SST_MODULE_ID_NR = 0x0076,
+ SST_MODULE_ID_BWX = 0x0077,
+ SST_MODULE_ID_DRP = 0x0078,
+ SST_MODULE_ID_MDRP = 0x0079,
+
+ SST_MODULE_ID_ANA = 0x007A,
+ SST_MODULE_ID_AEC = 0x007B,
+ SST_MODULE_ID_NR_SNS = 0x007C,
+ SST_MODULE_ID_SER = 0x007D,
+ SST_MODULE_ID_AGC = 0x007E,
+
+ SST_MODULE_ID_CNI = 0x007F,
+ SST_MODULE_ID_CONTEXT_ALGO_AWARE = 0x0080,
+ SST_MODULE_ID_FIR_24 = 0x0081,
+ SST_MODULE_ID_IIR_24 = 0x0082,
+
+ SST_MODULE_ID_ASRC = 0x0083,
+ SST_MODULE_ID_TONE_GEN = 0x0084,
+ SST_MODULE_ID_BMF = 0x0086,
+ SST_MODULE_ID_EDL = 0x0087,
+ SST_MODULE_ID_GLC = 0x0088,
+
+ SST_MODULE_ID_FIR_16 = 0x0089,
+ SST_MODULE_ID_IIR_16 = 0x008A,
+ SST_MODULE_ID_DNR = 0x008B,
+
+ SST_MODULE_ID_VIRTUALIZER = 0x008C,
+ SST_MODULE_ID_VISUALIZATION = 0x008D,
+ SST_MODULE_ID_LOUDNESS_OPTIMIZER = 0x008E,
+ SST_MODULE_ID_REVERBERATION = 0x008F,
+
+ SST_MODULE_ID_CNI_TX = 0x0090,
+ SST_MODULE_ID_REF_LINE = 0x0091,
+ SST_MODULE_ID_VOLUME = 0x0092,
+ SST_MODULE_ID_FILT_DCR = 0x0094,
+ SST_MODULE_ID_SLV = 0x009A,
+ SST_MODULE_ID_NLF = 0x009B,
+ SST_MODULE_ID_TNR = 0x009C,
+ SST_MODULE_ID_WNR = 0x009D,
+
+ SST_MODULE_ID_LOG = 0xFF00,
+
+ SST_MODULE_ID_TASK = 0xFFFF,
+};
+
+enum sst_cmd {
+ SBA_IDLE = 14,
+ SBA_VB_SET_SPEECH_PATH = 26,
+ MMX_SET_GAIN = 33,
+ SBA_VB_SET_GAIN = 33,
+ FBA_VB_RX_CNI = 35,
+ MMX_SET_GAIN_TIMECONST = 36,
+ SBA_VB_SET_TIMECONST = 36,
+ SBA_VB_START = 85,
+ SBA_SET_SWM = 114,
+ SBA_SET_MDRP = 116,
+ SBA_HW_SET_SSP = 117,
+ SBA_SET_MEDIA_LOOP_MAP = 118,
+ SBA_SET_MEDIA_PATH = 119,
+ MMX_SET_MEDIA_PATH = 119,
+ SBA_VB_LPRO = 126,
+ SBA_VB_SET_FIR = 128,
+ SBA_VB_SET_IIR = 129,
+ SBA_SET_SSP_SLOT_MAP = 130,
+};
+
+enum sst_dsp_switch {
+ SST_SWITCH_OFF = 0,
+ SST_SWITCH_ON = 3,
+};
+
+enum sst_path_switch {
+ SST_PATH_OFF = 0,
+ SST_PATH_ON = 1,
+};
+
+enum sst_swm_state {
+ SST_SWM_OFF = 0,
+ SST_SWM_ON = 3,
+};
+
+#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id) do { \
+ dst.location_id.p.cell_nbr_idx = (cell_idx); \
+ dst.location_id.p.path_id = (pipe_id); \
+ } while (0)
+#define SST_FILL_LOCATION_ID(dst, loc_id) (\
+ dst.location_id.f = (loc_id))
+#define SST_FILL_MODULE_ID(dst, mod_id) (\
+ dst.module_id = (mod_id))
+
+#define SST_FILL_DESTINATION1(dst, id) do { \
+ SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF); \
+ SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16); \
+ } while (0)
+#define SST_FILL_DESTINATION2(dst, loc_id, mod_id) do { \
+ SST_FILL_LOCATION_ID(dst, loc_id); \
+ SST_FILL_MODULE_ID(dst, mod_id); \
+ } while (0)
+#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id) do { \
+ SST_FILL_LOCATION_IDS(dst, cell_idx, path_id); \
+ SST_FILL_MODULE_ID(dst, mod_id); \
+ } while (0)
+
+#define SST_FILL_DESTINATION(level, dst, ...) \
+ SST_FILL_DESTINATION##level(dst, __VA_ARGS__)
+#define SST_FILL_DEFAULT_DESTINATION(dst) \
+ SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID)
+
+struct sst_destination_id {
+ union sst_location_id {
+ struct {
+ u8 cell_nbr_idx; /* module index */
+ u8 path_id; /* pipe_id */
+ } __packed p; /* part */
+ u16 f; /* full */
+ } __packed location_id;
+ u16 module_id;
+} __packed;
+struct sst_dsp_header {
+ struct sst_destination_id dst;
+ u16 command_id;
+ u16 length;
+} __packed;
+
+/*
+ *
+ * Common Commands
+ *
+ */
+struct sst_cmd_generic {
+ struct sst_dsp_header header;
+} __packed;
+struct sst_cmd_set_params {
+ struct sst_destination_id dst;
+ u16 command_id;
+ char params[0];
+} __packed;
+#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \
+ xpname " " xmname " " #xinstance " " xtype
+
+#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \
+ xpname " " xmname " " #xinstance " " xtype " " xsubmodule
+enum sst_algo_kcontrol_type {
+ SST_ALGO_PARAMS,
+ SST_ALGO_BYPASS,
+};
+
+struct sst_algo_control {
+ enum sst_algo_kcontrol_type type;
+ int max;
+ u16 module_id;
+ u16 pipe_id;
+ u16 task_id;
+ u16 cmd_id;
+ bool bypass;
+ unsigned char *params;
+ struct snd_soc_dapm_widget *w;
+};
+
+/* size of the control = size of params + size of length field */
+#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd) \
+ (struct sst_algo_control){ \
+ .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod, \
+ .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd, \
+ }
+
+#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe, \
+ xtask, xcmd, xtype, xinfo, xget, xput) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = xinfo, .get = xget, .put = xput, \
+ .private_value = (unsigned long)& \
+ SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, \
+ xmod, xtask, xcmd), \
+}
+
+#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, \
+ xpipe, xinstance, xtask, xcmd) \
+ SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"), \
+ xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \
+ sst_algo_bytes_ctl_info, \
+ sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask) \
+ SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"), \
+ 0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS, \
+ snd_soc_info_bool_ext, \
+ sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe, \
+ xinstance, xtask, xcmd) \
+ SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask), \
+ SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd)
+
+#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod, \
+ xpipe, xinstance, xtask, xcmd) \
+ SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params", \
+ xsubmod), \
+ xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \
+ sst_algo_bytes_ctl_info, \
+ sst_algo_control_get, sst_algo_control_set)
+
+
+struct sst_enum {
+ bool tx;
+ unsigned short reg;
+ unsigned int max;
+ const char * const *texts;
+ struct snd_soc_dapm_widget *w;
+};
#endif
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c
index 67673a2c0f41..b4ad98c43e5c 100644
--- a/sound/soc/intel/sst-baytrail-ipc.c
+++ b/sound/soc/intel/sst-baytrail-ipc.c
@@ -817,7 +817,7 @@ static struct sst_dsp_device byt_dev = {
.ops = &sst_byt_ops,
};
-int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
{
struct sst_byt *byt = pdata->dsp;
@@ -826,14 +826,6 @@ int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
sst_byt_drop_all(byt);
dev_dbg(byt->dev, "dsp in reset\n");
- return 0;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq);
-
-int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
-{
- struct sst_byt *byt = pdata->dsp;
-
dev_dbg(byt->dev, "free all blocks and unload fw\n");
sst_fw_unload(byt->fw);
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h
index 06a4d202689b..8faff6dcf25d 100644
--- a/sound/soc/intel/sst-baytrail-ipc.h
+++ b/sound/soc/intel/sst-baytrail-ipc.h
@@ -66,7 +66,6 @@ int sst_byt_get_dsp_position(struct sst_byt *byt,
int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
-int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata);
int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
index 599401c0c655..eab1c7d85187 100644
--- a/sound/soc/intel/sst-baytrail-pcm.c
+++ b/sound/soc/intel/sst-baytrail-pcm.c
@@ -59,6 +59,9 @@ struct sst_byt_priv_data {
/* DAI data */
struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
+
+ /* flag indicating is stream context restore needed after suspend */
+ bool restore_stream;
};
/* this may get called several times by oss emulation */
@@ -184,7 +187,10 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
sst_byt_stream_start(byt, pcm_data->stream, 0);
break;
case SNDRV_PCM_TRIGGER_RESUME:
- schedule_work(&pcm_data->work);
+ if (pdata->restore_stream == true)
+ schedule_work(&pcm_data->work);
+ else
+ sst_byt_stream_resume(byt, pcm_data->stream);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
sst_byt_stream_resume(byt, pcm_data->stream);
@@ -193,6 +199,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
sst_byt_stream_stop(byt, pcm_data->stream);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
+ pdata->restore_stream = false;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
sst_byt_stream_pause(byt, pcm_data->stream);
break;
@@ -404,26 +411,10 @@ static const struct snd_soc_component_driver byt_dai_component = {
};
#ifdef CONFIG_PM
-static int sst_byt_pcm_dev_suspend_noirq(struct device *dev)
-{
- struct sst_pdata *sst_pdata = dev_get_platdata(dev);
- int ret;
-
- dev_dbg(dev, "suspending noirq\n");
-
- /* at this point all streams will be stopped and context saved */
- ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata);
- if (ret < 0) {
- dev_err(dev, "failed to suspend %d\n", ret);
- return ret;
- }
-
- return ret;
-}
-
static int sst_byt_pcm_dev_suspend_late(struct device *dev)
{
struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+ struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev);
int ret;
dev_dbg(dev, "suspending late\n");
@@ -434,34 +425,30 @@ static int sst_byt_pcm_dev_suspend_late(struct device *dev)
return ret;
}
+ priv_data->restore_stream = true;
+
return ret;
}
static int sst_byt_pcm_dev_resume_early(struct device *dev)
{
struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+ int ret;
dev_dbg(dev, "resume early\n");
/* load fw and boot DSP */
- return sst_byt_dsp_boot(dev, sst_pdata);
-}
-
-static int sst_byt_pcm_dev_resume(struct device *dev)
-{
- struct sst_pdata *sst_pdata = dev_get_platdata(dev);
-
- dev_dbg(dev, "resume\n");
+ ret = sst_byt_dsp_boot(dev, sst_pdata);
+ if (ret)
+ return ret;
/* wait for FW to finish booting */
return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
}
static const struct dev_pm_ops sst_byt_pm_ops = {
- .suspend_noirq = sst_byt_pcm_dev_suspend_noirq,
.suspend_late = sst_byt_pcm_dev_suspend_late,
.resume_early = sst_byt_pcm_dev_resume_early,
- .resume = sst_byt_pcm_dev_resume,
};
#define SST_BYT_PM_OPS (&sst_byt_pm_ops)
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 61bf6da4bb02..33fc5c3abf55 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -138,11 +138,10 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value)
static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct hsw_priv_data *pdata =
- snd_soc_platform_get_drvdata(platform);
struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
struct sst_hsw *hsw = pdata->hsw;
u32 volume;
@@ -176,11 +175,10 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- struct hsw_priv_data *pdata =
- snd_soc_platform_get_drvdata(platform);
struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
struct sst_hsw *hsw = pdata->hsw;
u32 volume;
@@ -208,8 +206,8 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
static int hsw_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
- struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
struct sst_hsw *hsw = pdata->hsw;
u32 volume;
@@ -233,8 +231,8 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol,
static int hsw_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
- struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
struct sst_hsw *hsw = pdata->hsw;
unsigned int volume = 0;
@@ -778,20 +776,11 @@ static const struct snd_soc_dapm_route graph[] = {
static int hsw_pcm_probe(struct snd_soc_platform *platform)
{
+ struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform);
struct sst_pdata *pdata = dev_get_platdata(platform->dev);
- struct hsw_priv_data *priv_data;
- struct device *dma_dev;
+ struct device *dma_dev = pdata->dma_dev;
int i, ret = 0;
- if (!pdata)
- return -ENODEV;
-
- dma_dev = pdata->dma_dev;
-
- priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
- priv_data->hsw = pdata->dsp;
- snd_soc_platform_set_drvdata(platform, priv_data);
-
/* allocate DSP buffer page tables */
for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
@@ -848,27 +837,38 @@ static struct snd_soc_platform_driver hsw_soc_platform = {
.ops = &hsw_pcm_ops,
.pcm_new = hsw_pcm_new,
.pcm_free = hsw_pcm_free,
- .controls = hsw_volume_controls,
- .num_controls = ARRAY_SIZE(hsw_volume_controls),
- .dapm_widgets = widgets,
- .num_dapm_widgets = ARRAY_SIZE(widgets),
- .dapm_routes = graph,
- .num_dapm_routes = ARRAY_SIZE(graph),
};
static const struct snd_soc_component_driver hsw_dai_component = {
- .name = "haswell-dai",
+ .name = "haswell-dai",
+ .controls = hsw_volume_controls,
+ .num_controls = ARRAY_SIZE(hsw_volume_controls),
+ .dapm_widgets = widgets,
+ .num_dapm_widgets = ARRAY_SIZE(widgets),
+ .dapm_routes = graph,
+ .num_dapm_routes = ARRAY_SIZE(graph),
};
static int hsw_pcm_dev_probe(struct platform_device *pdev)
{
struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
+ struct hsw_priv_data *priv_data;
int ret;
+ if (!sst_pdata)
+ return -EINVAL;
+
+ priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL);
+ if (!priv_data)
+ return -ENOMEM;
+
ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata);
if (ret < 0)
return -ENODEV;
+ priv_data->hsw = sst_pdata->dsp;
+ platform_set_drvdata(pdev, priv_data);
+
ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
if (ret < 0)
goto err_plat;
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c
index 29c059ca19e8..59467775c9b8 100644
--- a/sound/soc/intel/sst-mfld-platform-compress.c
+++ b/sound/soc/intel/sst-mfld-platform-compress.c
@@ -86,7 +86,7 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream)
/*need to check*/
str_id = stream->id;
if (str_id)
- ret_val = stream->compr_ops->close(str_id);
+ ret_val = stream->compr_ops->close(sst->dev, str_id);
module_put(sst->dev->driver->owner);
kfree(stream);
pr_debug("%s: %d\n", __func__, ret_val);
@@ -158,7 +158,7 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
cb.drain_cb_param = cstream;
cb.drain_notify = sst_drain_notify;
- retval = stream->compr_ops->open(&str_params, &cb);
+ retval = stream->compr_ops->open(sst->dev, &str_params, &cb);
if (retval < 0) {
pr_err("stream allocation failed %d\n", retval);
return retval;
@@ -170,10 +170,30 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
{
- struct sst_runtime_stream *stream =
- cstream->runtime->private_data;
-
- return stream->compr_ops->control(cmd, stream->id);
+ struct sst_runtime_stream *stream = cstream->runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ if (stream->compr_ops->stream_start)
+ return stream->compr_ops->stream_start(sst->dev, stream->id);
+ case SNDRV_PCM_TRIGGER_STOP:
+ if (stream->compr_ops->stream_drop)
+ return stream->compr_ops->stream_drop(sst->dev, stream->id);
+ case SND_COMPR_TRIGGER_DRAIN:
+ if (stream->compr_ops->stream_drain)
+ return stream->compr_ops->stream_drain(sst->dev, stream->id);
+ case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
+ if (stream->compr_ops->stream_partial_drain)
+ return stream->compr_ops->stream_partial_drain(sst->dev, stream->id);
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (stream->compr_ops->stream_pause)
+ return stream->compr_ops->stream_pause(sst->dev, stream->id);
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (stream->compr_ops->stream_pause_release)
+ return stream->compr_ops->stream_pause_release(sst->dev, stream->id);
+ default:
+ return -EINVAL;
+ }
}
static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
@@ -182,7 +202,7 @@ static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
struct sst_runtime_stream *stream;
stream = cstream->runtime->private_data;
- stream->compr_ops->tstamp(stream->id, tstamp);
+ stream->compr_ops->tstamp(sst->dev, stream->id, tstamp);
tstamp->byte_offset = tstamp->copied_total %
(u32)cstream->runtime->buffer_size;
pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
@@ -195,7 +215,7 @@ static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
struct sst_runtime_stream *stream;
stream = cstream->runtime->private_data;
- stream->compr_ops->ack(stream->id, (unsigned long)bytes);
+ stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes);
stream->bytes_written += bytes;
return 0;
@@ -225,7 +245,7 @@ static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
struct sst_runtime_stream *stream =
cstream->runtime->private_data;
- return stream->compr_ops->set_metadata(stream->id, metadata);
+ return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata);
}
struct snd_compr_ops sst_platform_compr_ops = {
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c
index 706212a6a68c..aa9b600dfc9b 100644
--- a/sound/soc/intel/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/sst-mfld-platform-pcm.c
@@ -43,12 +43,12 @@ int sst_register_dsp(struct sst_device *dev)
return -ENODEV;
mutex_lock(&sst_lock);
if (sst) {
- pr_err("we already have a device %s\n", sst->name);
+ dev_err(dev->dev, "we already have a device %s\n", sst->name);
module_put(dev->dev->driver->owner);
mutex_unlock(&sst_lock);
return -EEXIST;
}
- pr_debug("registering device %s\n", dev->name);
+ dev_dbg(dev->dev, "registering device %s\n", dev->name);
sst = dev;
mutex_unlock(&sst_lock);
return 0;
@@ -70,7 +70,7 @@ int sst_unregister_dsp(struct sst_device *dev)
}
module_put(sst->dev->driver->owner);
- pr_debug("unreg %s\n", sst->name);
+ dev_dbg(dev->dev, "unreg %s\n", sst->name);
sst = NULL;
mutex_unlock(&sst_lock);
return 0;
@@ -252,7 +252,7 @@ int sst_fill_stream_params(void *substream,
}
static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
- struct snd_soc_platform *platform)
+ struct snd_soc_dai *dai)
{
struct sst_runtime_stream *stream =
substream->runtime->private_data;
@@ -260,7 +260,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
struct snd_sst_params str_params = {0};
struct snd_sst_alloc_params_ext alloc_params = {0};
int ret_val = 0;
- struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
+ struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
/* set codec params and inform SST driver the same */
sst_fill_pcm_params(substream, &param);
@@ -277,7 +277,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
stream->stream_info.str_id = str_params.stream_id;
- ret_val = stream->ops->open(&str_params);
+ ret_val = stream->ops->open(sst->dev, &str_params);
if (ret_val <= 0)
return ret_val;
@@ -306,22 +306,31 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
{
struct sst_runtime_stream *stream =
substream->runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
int ret_val;
- pr_debug("setting buffer ptr param\n");
+ dev_dbg(rtd->dev, "setting buffer ptr param\n");
sst_set_stream_status(stream, SST_PLATFORM_INIT);
stream->stream_info.period_elapsed = sst_period_elapsed;
stream->stream_info.arg = substream;
stream->stream_info.buffer_ptr = 0;
stream->stream_info.sfreq = substream->runtime->rate;
- ret_val = stream->ops->device_control(
- SST_SND_STREAM_INIT, &stream->stream_info);
+ ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
if (ret_val)
- pr_err("control_set ret error %d\n", ret_val);
+ dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
return ret_val;
}
-/* end -- helper functions */
+
+static int power_up_sst(struct sst_runtime_stream *stream)
+{
+ return stream->ops->power(sst->dev, true);
+}
+
+static void power_down_sst(struct sst_runtime_stream *stream)
+{
+ stream->ops->power(sst->dev, false);
+}
static int sst_media_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
@@ -339,7 +348,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
mutex_lock(&sst_lock);
if (!sst ||
!try_module_get(sst->dev->driver->owner)) {
- pr_err("no device available to run\n");
+ dev_err(dai->dev, "no device available to run\n");
ret_val = -ENODEV;
goto out_ops;
}
@@ -352,6 +361,10 @@ static int sst_media_open(struct snd_pcm_substream *substream,
/* allocate memory for SST API set */
runtime->private_data = stream;
+ ret_val = power_up_sst(stream);
+ if (ret_val < 0)
+ return ret_val;
+
/* Make sure, that the period size is always even */
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIODS, 2);
@@ -371,26 +384,29 @@ static void sst_media_close(struct snd_pcm_substream *substream,
int ret_val = 0, str_id;
stream = substream->runtime->private_data;
+ power_down_sst(stream);
+
str_id = stream->stream_info.str_id;
if (str_id)
- ret_val = stream->ops->close(str_id);
+ ret_val = stream->ops->close(sst->dev, str_id);
module_put(sst->dev->driver->owner);
kfree(stream);
}
-static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform,
+static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream)
{
- struct sst_data *sst = snd_soc_platform_get_drvdata(platform);
+ struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
struct sst_runtime_stream *stream =
substream->runtime->private_data;
u32 str_id = stream->stream_info.str_id;
unsigned int pipe_id;
+
pipe_id = map[str_id].device_id;
- pr_debug("%s: got pipe_id = %#x for str_id = %d\n",
- __func__, pipe_id, str_id);
+ dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
+ pipe_id, str_id);
return pipe_id;
}
@@ -403,12 +419,11 @@ static int sst_media_prepare(struct snd_pcm_substream *substream,
stream = substream->runtime->private_data;
str_id = stream->stream_info.str_id;
if (stream->stream_info.str_id) {
- ret_val = stream->ops->device_control(
- SST_SND_DROP, &str_id);
+ ret_val = stream->ops->stream_drop(sst->dev, str_id);
return ret_val;
}
- ret_val = sst_platform_alloc_stream(substream, dai->platform);
+ ret_val = sst_platform_alloc_stream(substream, dai);
if (ret_val <= 0)
return ret_val;
snprintf(substream->pcm->id, sizeof(substream->pcm->id),
@@ -461,37 +476,40 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
{
int ret_val = 0, str_id;
struct sst_runtime_stream *stream;
- int str_cmd, status;
+ int status;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
- pr_debug("sst_platform_pcm_trigger called\n");
+ dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
+ if (substream->pcm->internal)
+ return 0;
stream = substream->runtime->private_data;
str_id = stream->stream_info.str_id;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- pr_debug("sst: Trigger Start\n");
- str_cmd = SST_SND_START;
+ dev_dbg(rtd->dev, "sst: Trigger Start\n");
status = SST_PLATFORM_RUNNING;
stream->stream_info.arg = substream;
+ ret_val = stream->ops->stream_start(sst->dev, str_id);
break;
case SNDRV_PCM_TRIGGER_STOP:
- pr_debug("sst: in stop\n");
- str_cmd = SST_SND_DROP;
+ dev_dbg(rtd->dev, "sst: in stop\n");
status = SST_PLATFORM_DROPPED;
+ ret_val = stream->ops->stream_drop(sst->dev, str_id);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- pr_debug("sst: in pause\n");
- str_cmd = SST_SND_PAUSE;
+ dev_dbg(rtd->dev, "sst: in pause\n");
status = SST_PLATFORM_PAUSED;
+ ret_val = stream->ops->stream_pause(sst->dev, str_id);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- pr_debug("sst: in pause release\n");
- str_cmd = SST_SND_RESUME;
+ dev_dbg(rtd->dev, "sst: in pause release\n");
status = SST_PLATFORM_RUNNING;
+ ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
break;
default:
return -EINVAL;
}
- ret_val = stream->ops->device_control(str_cmd, &str_id);
+
if (!ret_val)
sst_set_stream_status(stream, status);
@@ -505,16 +523,16 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
struct sst_runtime_stream *stream;
int ret_val, status;
struct pcm_stream_info *str_info;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
stream = substream->runtime->private_data;
status = sst_get_stream_status(stream);
if (status == SST_PLATFORM_INIT)
return 0;
str_info = &stream->stream_info;
- ret_val = stream->ops->device_control(
- SST_SND_BUFFER_POINTER, str_info);
+ ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
if (ret_val) {
- pr_err("sst: error code = %d\n", ret_val);
+ dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
return ret_val;
}
substream->runtime->delay = str_info->pcm_delay;
@@ -530,7 +548,7 @@ static struct snd_pcm_ops sst_platform_ops = {
static void sst_pcm_free(struct snd_pcm *pcm)
{
- pr_debug("sst_pcm_free called\n");
+ dev_dbg(pcm->dev, "sst_pcm_free called\n");
snd_pcm_lib_preallocate_free_for_all(pcm);
}
@@ -547,14 +565,20 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
snd_dma_continuous_data(GFP_DMA),
SST_MIN_BUFFER, SST_MAX_BUFFER);
if (retval) {
- pr_err("dma buffer allocationf fail\n");
+ dev_err(rtd->dev, "dma buffer allocationf fail\n");
return retval;
}
}
return retval;
}
-static struct snd_soc_platform_driver sst_soc_platform_drv = {
+static int sst_soc_probe(struct snd_soc_platform *platform)
+{
+ return sst_dsp_init_v2_dpcm(platform);
+}
+
+static struct snd_soc_platform_driver sst_soc_platform_drv = {
+ .probe = sst_soc_probe,
.ops = &sst_platform_ops,
.compr_ops = &sst_platform_compr_ops,
.pcm_new = sst_pcm_new,
@@ -574,13 +598,11 @@ static int sst_platform_probe(struct platform_device *pdev)
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (drv == NULL) {
- pr_err("kzalloc failed\n");
return -ENOMEM;
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (pdata == NULL) {
- pr_err("kzalloc failed for pdata\n");
return -ENOMEM;
}
@@ -592,14 +614,14 @@ static int sst_platform_probe(struct platform_device *pdev)
ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
if (ret) {
- pr_err("registering soc platform failed\n");
+ dev_err(&pdev->dev, "registering soc platform failed\n");
return ret;
}
ret = snd_soc_register_component(&pdev->dev, &sst_component,
sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
if (ret) {
- pr_err("registering cpu dais failed\n");
+ dev_err(&pdev->dev, "registering cpu dais failed\n");
snd_soc_unregister_platform(&pdev->dev);
}
return ret;
@@ -610,7 +632,7 @@ static int sst_platform_remove(struct platform_device *pdev)
snd_soc_unregister_component(&pdev->dev);
snd_soc_unregister_platform(&pdev->dev);
- pr_debug("sst_platform_remove success\n");
+ dev_dbg(&pdev->dev, "sst_platform_remove success\n");
return 0;
}
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h
index 6c6a42c08e24..19f83ec51613 100644
--- a/sound/soc/intel/sst-mfld-platform.h
+++ b/sound/soc/intel/sst-mfld-platform.h
@@ -54,20 +54,6 @@ enum sst_drv_status {
SST_PLATFORM_DROPPED,
};
-enum sst_controls {
- SST_SND_ALLOC = 0x00,
- SST_SND_PAUSE = 0x01,
- SST_SND_RESUME = 0x02,
- SST_SND_DROP = 0x03,
- SST_SND_FREE = 0x04,
- SST_SND_BUFFER_POINTER = 0x05,
- SST_SND_STREAM_INIT = 0x06,
- SST_SND_START = 0x07,
- SST_SET_BYTE_STREAM = 0x100A,
- SST_GET_BYTE_STREAM = 0x100B,
- SST_MAX_CONTROLS = SST_GET_BYTE_STREAM,
-};
-
enum sst_stream_ops {
STREAM_OPS_PLAYBACK = 0,
STREAM_OPS_CAPTURE,
@@ -113,24 +99,37 @@ struct sst_compress_cb {
struct compress_sst_ops {
const char *name;
- int (*open) (struct snd_sst_params *str_params,
- struct sst_compress_cb *cb);
- int (*control) (unsigned int cmd, unsigned int str_id);
- int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp);
- int (*ack) (unsigned int str_id, unsigned long bytes);
- int (*close) (unsigned int str_id);
- int (*get_caps) (struct snd_compr_caps *caps);
- int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
- int (*set_metadata) (unsigned int str_id,
+ int (*open)(struct device *dev,
+ struct snd_sst_params *str_params, struct sst_compress_cb *cb);
+ int (*stream_start)(struct device *dev, unsigned int str_id);
+ int (*stream_drop)(struct device *dev, unsigned int str_id);
+ int (*stream_drain)(struct device *dev, unsigned int str_id);
+ int (*stream_partial_drain)(struct device *dev, unsigned int str_id);
+ int (*stream_pause)(struct device *dev, unsigned int str_id);
+ int (*stream_pause_release)(struct device *dev, unsigned int str_id);
+
+ int (*tstamp)(struct device *dev, unsigned int str_id,
+ struct snd_compr_tstamp *tstamp);
+ int (*ack)(struct device *dev, unsigned int str_id,
+ unsigned long bytes);
+ int (*close)(struct device *dev, unsigned int str_id);
+ int (*get_caps)(struct snd_compr_caps *caps);
+ int (*get_codec_caps)(struct snd_compr_codec_caps *codec);
+ int (*set_metadata)(struct device *dev, unsigned int str_id,
struct snd_compr_metadata *mdata);
-
};
struct sst_ops {
- int (*open) (struct snd_sst_params *str_param);
- int (*device_control) (int cmd, void *arg);
- int (*set_generic_params)(enum sst_controls cmd, void *arg);
- int (*close) (unsigned int str_id);
+ int (*open)(struct device *dev, struct snd_sst_params *str_param);
+ int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info);
+ int (*stream_start)(struct device *dev, int str_id);
+ int (*stream_drop)(struct device *dev, int str_id);
+ int (*stream_pause)(struct device *dev, int str_id);
+ int (*stream_pause_release)(struct device *dev, int str_id);
+ int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info);
+ int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes);
+ int (*close)(struct device *dev, unsigned int str_id);
+ int (*power)(struct device *dev, bool state);
};
struct sst_runtime_stream {
@@ -152,6 +151,8 @@ struct sst_device {
};
struct sst_data;
+
+int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform);
void sst_set_stream_status(struct sst_runtime_stream *stream, int state);
int sst_fill_stream_params(void *substream, const struct sst_data *ctx,
struct snd_sst_params *str_params, bool is_compress);
@@ -166,6 +167,7 @@ struct sst_algo_int_control_v2 {
struct sst_data {
struct platform_device *pdev;
struct sst_platform_data *pdata;
+ struct snd_sst_bytes_v2 *byte_stream;
struct mutex lock;
};
int sst_register_dsp(struct sst_device *sst);
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
index f8a6adc2d81c..4336d1831485 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/omap/omap-twl4030.c
@@ -260,7 +260,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
.stream_name = "TWL4030 Voice",
.cpu_dai_name = "omap-mcbsp.3",
.codec_dai_name = "twl4030-voice",
- .platform_name = "omap-mcbsp.2",
+ .platform_name = "omap-mcbsp.3",
.codec_name = "twl4030-codec",
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBM_CFM,
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 943922c79f78..b10ae8074461 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -168,7 +168,7 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w,
static int rx51_hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
- struct snd_soc_codec *codec = w->dapm->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
if (SND_SOC_DAPM_EVENT_ON(event))
tpa6130a2_stereo_enable(codec, 1);
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 0109f6c2334e..a8e097433074 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -765,9 +765,7 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai)
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S32_LE)
+#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
.startup = pxa_ssp_startup,
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 8d8e4b59049f..fb9e05c9f471 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -165,13 +165,14 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
struct rk_i2s_dev *i2s = to_info(cpu_dai);
unsigned int mask = 0, val = 0;
- mask = I2S_CKR_MSS_SLAVE;
+ mask = I2S_CKR_MSS_MASK;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
- val = I2S_CKR_MSS_SLAVE;
+ /* Set source clock in Master mode */
+ val = I2S_CKR_MSS_MASTER;
break;
case SND_SOC_DAIFMT_CBM_CFM:
- val = I2S_CKR_MSS_MASTER;
+ val = I2S_CKR_MSS_SLAVE;
break;
default:
return -EINVAL;
@@ -361,6 +362,8 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg)
case I2S_XFER:
case I2S_CLR:
case I2S_RXDR:
+ case I2S_FIFOLR:
+ case I2S_INTSR:
return true;
default:
return false;
@@ -370,8 +373,8 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg)
static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case I2S_FIFOLR:
case I2S_INTSR:
+ case I2S_CLR:
return true;
default:
return false;
@@ -381,8 +384,6 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case I2S_FIFOLR:
- return true;
default:
return false;
}
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 03eec22f0f46..9d513473b300 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -462,7 +462,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
if (dir == SND_SOC_CLOCK_IN)
rfs = 0;
- if ((rfs && other->rfs && (other->rfs != rfs)) ||
+ if ((rfs && other && other->rfs && (other->rfs != rfs)) ||
(any_active(i2s) &&
(((dir == SND_SOC_CLOCK_IN)
&& !(mod & MOD_CDCLKCON)) ||
@@ -762,7 +762,8 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
} else {
u32 mod = readl(i2s->addr + I2SMOD);
i2s->cdclk_out = !(mod & MOD_CDCLKCON);
- other->cdclk_out = i2s->cdclk_out;
+ if (other)
+ other->cdclk_out = i2s->cdclk_out;
}
/* Reset any constraint on RFS and BFS */
i2s->rfs = 0;
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 9902efcb8ea1..a05482651aae 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -228,10 +228,12 @@ static struct snd_soc_dai_link speyside_dai[] = {
},
};
-static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm)
+static int speyside_wm9081_init(struct snd_soc_component *component)
{
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
/* At any time the WM9081 is active it will have this clock */
- return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0,
+ return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0,
MCLK_AUDIO_RATE, 0);
}
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 3fdf3be7b99a..f95e7ab135e8 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -247,7 +247,7 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv,
};
/* it shouldn't happen */
- if (use_dvc & !use_src)
+ if (use_dvc && !use_src)
dev_err(dev, "DVC is selected without SRC\n");
/* use SSIU or SSI ? */
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 27c06acce205..cecfab3cc948 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -101,10 +101,12 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
fe->dpcm[stream].runtime = fe_substream->runtime;
- if (dpcm_path_get(fe, stream, &list) <= 0) {
+ ret = dpcm_path_get(fe, stream, &list);
+ if (ret < 0)
+ goto fe_err;
+ else if (ret == 0)
dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
fe->dai_link->name, stream ? "capture" : "playback");
- }
/* calculate valid and active FE <-> BE dpcms */
dpcm_process_paths(fe, stream, &list, 1);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index d4bfd4a9076f..3d8cff629a18 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -270,79 +270,54 @@ static const struct file_operations codec_reg_fops = {
.llseek = default_llseek,
};
-static struct dentry *soc_debugfs_create_dir(struct dentry *parent,
- const char *fmt, ...)
+static void soc_init_component_debugfs(struct snd_soc_component *component)
{
- struct dentry *de;
- va_list ap;
- char *s;
+ if (component->debugfs_prefix) {
+ char *name;
- va_start(ap, fmt);
- s = kvasprintf(GFP_KERNEL, fmt, ap);
- va_end(ap);
+ name = kasprintf(GFP_KERNEL, "%s:%s",
+ component->debugfs_prefix, component->name);
+ if (name) {
+ component->debugfs_root = debugfs_create_dir(name,
+ component->card->debugfs_card_root);
+ kfree(name);
+ }
+ } else {
+ component->debugfs_root = debugfs_create_dir(component->name,
+ component->card->debugfs_card_root);
+ }
- if (!s)
- return NULL;
+ if (!component->debugfs_root) {
+ dev_warn(component->dev,
+ "ASoC: Failed to create component debugfs directory\n");
+ return;
+ }
- de = debugfs_create_dir(s, parent);
- kfree(s);
+ snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component),
+ component->debugfs_root);
- return de;
+ if (component->init_debugfs)
+ component->init_debugfs(component);
}
-static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
+static void soc_cleanup_component_debugfs(struct snd_soc_component *component)
{
- struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root;
+ debugfs_remove_recursive(component->debugfs_root);
+}
- codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root,
- "codec:%s",
- codec->component.name);
- if (!codec->debugfs_codec_root) {
- dev_warn(codec->dev,
- "ASoC: Failed to create codec debugfs directory\n");
- return;
- }
+static void soc_init_codec_debugfs(struct snd_soc_component *component)
+{
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
- debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root,
+ debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root,
&codec->cache_sync);
- debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root,
- &codec->cache_only);
codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
- codec->debugfs_codec_root,
+ codec->component.debugfs_root,
codec, &codec_reg_fops);
if (!codec->debugfs_reg)
dev_warn(codec->dev,
"ASoC: Failed to create codec register debugfs file\n");
-
- snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
-}
-
-static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
-{
- debugfs_remove_recursive(codec->debugfs_codec_root);
-}
-
-static void soc_init_platform_debugfs(struct snd_soc_platform *platform)
-{
- struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root;
-
- platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root,
- "platform:%s",
- platform->component.name);
- if (!platform->debugfs_platform_root) {
- dev_warn(platform->dev,
- "ASoC: Failed to create platform debugfs directory\n");
- return;
- }
-
- snd_soc_dapm_debugfs_init(&platform->component.dapm,
- platform->debugfs_platform_root);
-}
-
-static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform)
-{
- debugfs_remove_recursive(platform->debugfs_platform_root);
}
static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
@@ -474,19 +449,15 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
#else
-static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
-{
-}
-
-static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
-{
-}
+#define soc_init_codec_debugfs NULL
-static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform)
+static inline void soc_init_component_debugfs(
+ struct snd_soc_component *component)
{
}
-static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform)
+static inline void soc_cleanup_component_debugfs(
+ struct snd_soc_component *component)
{
}
@@ -579,10 +550,8 @@ int snd_soc_suspend(struct device *dev)
struct snd_soc_codec *codec;
int i, j;
- /* If the initialization of this soc device failed, there is no codec
- * associated with it. Just bail out in this case.
- */
- if (list_empty(&card->codec_dev_list))
+ /* If the card is not initialized yet there is nothing to do */
+ if (!card->instantiated)
return 0;
/* Due to the resume being scheduled into a workqueue we could
@@ -668,7 +637,7 @@ int snd_soc_suspend(struct device *dev)
list_for_each_entry(codec, &card->codec_dev_list, card_list) {
/* If there are paths active then the CODEC will be held with
* bias _ON and should not be suspended. */
- if (!codec->suspended && codec->driver->suspend) {
+ if (!codec->suspended) {
switch (codec->dapm.bias_level) {
case SND_SOC_BIAS_STANDBY:
/*
@@ -682,8 +651,10 @@ int snd_soc_suspend(struct device *dev)
"ASoC: idle_bias_off CODEC on over suspend\n");
break;
}
+
case SND_SOC_BIAS_OFF:
- codec->driver->suspend(codec);
+ if (codec->driver->suspend)
+ codec->driver->suspend(codec);
codec->suspended = 1;
codec->cache_sync = 1;
if (codec->component.regmap)
@@ -757,11 +728,12 @@ static void soc_resume_deferred(struct work_struct *work)
* left with bias OFF or STANDBY and suspended so we must now
* resume. Otherwise the suspend was suppressed.
*/
- if (codec->driver->resume && codec->suspended) {
+ if (codec->suspended) {
switch (codec->dapm.bias_level) {
case SND_SOC_BIAS_STANDBY:
case SND_SOC_BIAS_OFF:
- codec->driver->resume(codec);
+ if (codec->driver->resume)
+ codec->driver->resume(codec);
codec->suspended = 0;
break;
default:
@@ -835,10 +807,8 @@ int snd_soc_resume(struct device *dev)
struct snd_soc_card *card = dev_get_drvdata(dev);
int i, ac97_control = 0;
- /* If the initialization of this soc device failed, there is no codec
- * associated with it. Just bail out in this case.
- */
- if (list_empty(&card->codec_dev_list))
+ /* If the card is not initialized yet there is nothing to do */
+ if (!card->instantiated)
return 0;
/* activate pins from sleep state */
@@ -887,35 +857,40 @@ EXPORT_SYMBOL_GPL(snd_soc_resume);
static const struct snd_soc_dai_ops null_dai_ops = {
};
-static struct snd_soc_codec *soc_find_codec(
- const struct device_node *codec_of_node,
- const char *codec_name)
+static struct snd_soc_component *soc_find_component(
+ const struct device_node *of_node, const char *name)
{
- struct snd_soc_codec *codec;
+ struct snd_soc_component *component;
- list_for_each_entry(codec, &codec_list, list) {
- if (codec_of_node) {
- if (codec->dev->of_node != codec_of_node)
- continue;
- } else {
- if (strcmp(codec->component.name, codec_name))
- continue;
+ list_for_each_entry(component, &component_list, list) {
+ if (of_node) {
+ if (component->dev->of_node == of_node)
+ return component;
+ } else if (strcmp(component->name, name) == 0) {
+ return component;
}
-
- return codec;
}
return NULL;
}
-static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec,
- const char *codec_dai_name)
+static struct snd_soc_dai *snd_soc_find_dai(
+ const struct snd_soc_dai_link_component *dlc)
{
- struct snd_soc_dai *codec_dai;
+ struct snd_soc_component *component;
+ struct snd_soc_dai *dai;
+
+ /* Find CPU DAI from registered DAIs*/
+ list_for_each_entry(component, &component_list, list) {
+ if (dlc->of_node && component->dev->of_node != dlc->of_node)
+ continue;
+ if (dlc->name && strcmp(dev_name(component->dev), dlc->name))
+ continue;
+ list_for_each_entry(dai, &component->dai_list, list) {
+ if (dlc->dai_name && strcmp(dai->name, dlc->dai_name))
+ continue;
- list_for_each_entry(codec_dai, &codec->component.dai_list, list) {
- if (!strcmp(codec_dai->name, codec_dai_name)) {
- return codec_dai;
+ return dai;
}
}
@@ -926,33 +901,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
{
struct snd_soc_dai_link *dai_link = &card->dai_link[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
- struct snd_soc_component *component;
struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+ struct snd_soc_dai_link_component cpu_dai_component;
struct snd_soc_dai **codec_dais = rtd->codec_dais;
struct snd_soc_platform *platform;
- struct snd_soc_dai *cpu_dai;
const char *platform_name;
int i;
dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
- /* Find CPU DAI from registered DAIs*/
- list_for_each_entry(component, &component_list, list) {
- if (dai_link->cpu_of_node &&
- component->dev->of_node != dai_link->cpu_of_node)
- continue;
- if (dai_link->cpu_name &&
- strcmp(dev_name(component->dev), dai_link->cpu_name))
- continue;
- list_for_each_entry(cpu_dai, &component->dai_list, list) {
- if (dai_link->cpu_dai_name &&
- strcmp(cpu_dai->name, dai_link->cpu_dai_name))
- continue;
-
- rtd->cpu_dai = cpu_dai;
- }
- }
-
+ 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;
+ rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);
if (!rtd->cpu_dai) {
dev_err(card->dev, "ASoC: CPU DAI %s not registered\n",
dai_link->cpu_dai_name);
@@ -963,15 +924,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
/* Find CODEC from registered CODECs */
for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_codec *codec;
- codec = soc_find_codec(codecs[i].of_node, codecs[i].name);
- if (!codec) {
- dev_err(card->dev, "ASoC: CODEC %s not registered\n",
- codecs[i].name);
- return -EPROBE_DEFER;
- }
-
- codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name);
+ codec_dais[i] = snd_soc_find_dai(&codecs[i]);
if (!codec_dais[i]) {
dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
codecs[i].dai_name);
@@ -1012,68 +965,46 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
return 0;
}
-static int soc_remove_platform(struct snd_soc_platform *platform)
+static void soc_remove_component(struct snd_soc_component *component)
{
- int ret;
-
- if (platform->driver->remove) {
- ret = platform->driver->remove(platform);
- if (ret < 0)
- dev_err(platform->dev, "ASoC: failed to remove %d\n",
- ret);
- }
-
- /* Make sure all DAPM widgets are freed */
- snd_soc_dapm_free(&platform->component.dapm);
-
- soc_cleanup_platform_debugfs(platform);
- platform->probed = 0;
- module_put(platform->dev->driver->owner);
-
- return 0;
-}
+ if (!component->probed)
+ return;
-static void soc_remove_codec(struct snd_soc_codec *codec)
-{
- int err;
+ /* This is a HACK and will be removed soon */
+ if (component->codec)
+ list_del(&component->codec->card_list);
- if (codec->driver->remove) {
- err = codec->driver->remove(codec);
- if (err < 0)
- dev_err(codec->dev, "ASoC: failed to remove %d\n", err);
- }
+ if (component->remove)
+ component->remove(component);
- /* Make sure all DAPM widgets are freed */
- snd_soc_dapm_free(&codec->dapm);
+ snd_soc_dapm_free(snd_soc_component_get_dapm(component));
- soc_cleanup_codec_debugfs(codec);
- codec->probed = 0;
- list_del(&codec->card_list);
- module_put(codec->dev->driver->owner);
+ soc_cleanup_component_debugfs(component);
+ component->probed = 0;
+ module_put(component->dev->driver->owner);
}
-static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order)
+static void soc_remove_dai(struct snd_soc_dai *dai, int order)
{
int err;
- if (codec_dai && codec_dai->probed &&
- codec_dai->driver->remove_order == order) {
- if (codec_dai->driver->remove) {
- err = codec_dai->driver->remove(codec_dai);
+ if (dai && dai->probed &&
+ dai->driver->remove_order == order) {
+ if (dai->driver->remove) {
+ err = dai->driver->remove(dai);
if (err < 0)
- dev_err(codec_dai->dev,
+ dev_err(dai->dev,
"ASoC: failed to remove %s: %d\n",
- codec_dai->name, err);
+ dai->name, err);
}
- codec_dai->probed = 0;
+ dai->probed = 0;
}
}
static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int i, err;
+ int i;
/* unregister the rtd device */
if (rtd->dev_registered) {
@@ -1085,22 +1016,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
/* remove the CODEC DAI */
for (i = 0; i < rtd->num_codecs; i++)
- soc_remove_codec_dai(rtd->codec_dais[i], order);
+ soc_remove_dai(rtd->codec_dais[i], order);
- /* remove the cpu_dai */
- if (cpu_dai && cpu_dai->probed &&
- cpu_dai->driver->remove_order == order) {
- if (cpu_dai->driver->remove) {
- err = cpu_dai->driver->remove(cpu_dai);
- if (err < 0)
- dev_err(cpu_dai->dev,
- "ASoC: failed to remove %s: %d\n",
- cpu_dai->name, err);
- }
- cpu_dai->probed = 0;
- if (!cpu_dai->codec)
- module_put(cpu_dai->dev->driver->owner);
- }
+ soc_remove_dai(rtd->cpu_dai, order);
}
static void soc_remove_link_components(struct snd_soc_card *card, int num,
@@ -1109,29 +1027,24 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num,
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_platform *platform = rtd->platform;
- struct snd_soc_codec *codec;
+ struct snd_soc_component *component;
int i;
/* remove the platform */
- if (platform && platform->probed &&
- platform->driver->remove_order == order) {
- soc_remove_platform(platform);
- }
+ if (platform && platform->component.driver->remove_order == order)
+ soc_remove_component(&platform->component);
/* remove the CODEC-side CODEC */
for (i = 0; i < rtd->num_codecs; i++) {
- codec = rtd->codec_dais[i]->codec;
- if (codec && codec->probed &&
- codec->driver->remove_order == order)
- soc_remove_codec(codec);
+ component = rtd->codec_dais[i]->component;
+ if (component->driver->remove_order == order)
+ soc_remove_component(component);
}
/* remove any CPU-side CODEC */
if (cpu_dai) {
- codec = cpu_dai->codec;
- if (codec && codec->probed &&
- codec->driver->remove_order == order)
- soc_remove_codec(codec);
+ if (cpu_dai->component->driver->remove_order == order)
+ soc_remove_component(cpu_dai->component);
}
}
@@ -1173,137 +1086,78 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
}
}
-static int soc_probe_codec(struct snd_soc_card *card,
- struct snd_soc_codec *codec)
+static int soc_probe_component(struct snd_soc_card *card,
+ struct snd_soc_component *component)
{
- int ret = 0;
- const struct snd_soc_codec_driver *driver = codec->driver;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct snd_soc_dai *dai;
+ int ret;
+
+ if (component->probed)
+ return 0;
- codec->component.card = card;
- codec->dapm.card = card;
- soc_set_name_prefix(card, &codec->component);
+ component->card = card;
+ dapm->card = card;
+ soc_set_name_prefix(card, component);
- if (!try_module_get(codec->dev->driver->owner))
+ if (!try_module_get(component->dev->driver->owner))
return -ENODEV;
- soc_init_codec_debugfs(codec);
+ soc_init_component_debugfs(component);
- if (driver->dapm_widgets) {
- ret = snd_soc_dapm_new_controls(&codec->dapm,
- driver->dapm_widgets,
- driver->num_dapm_widgets);
+ if (component->dapm_widgets) {
+ ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets,
+ component->num_dapm_widgets);
if (ret != 0) {
- dev_err(codec->dev,
+ dev_err(component->dev,
"Failed to create new controls %d\n", ret);
goto err_probe;
}
}
- /* Create DAPM widgets for each DAI stream */
- list_for_each_entry(dai, &codec->component.dai_list, list) {
- ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai);
-
+ list_for_each_entry(dai, &component->dai_list, list) {
+ ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
if (ret != 0) {
- dev_err(codec->dev,
+ dev_err(component->dev,
"Failed to create DAI widgets %d\n", ret);
goto err_probe;
}
}
- codec->dapm.idle_bias_off = driver->idle_bias_off;
-
- if (driver->probe) {
- ret = driver->probe(codec);
+ if (component->probe) {
+ ret = component->probe(component);
if (ret < 0) {
- dev_err(codec->dev,
- "ASoC: failed to probe CODEC %d\n", ret);
+ dev_err(component->dev,
+ "ASoC: failed to probe component %d\n", ret);
goto err_probe;
}
- WARN(codec->dapm.idle_bias_off &&
- codec->dapm.bias_level != SND_SOC_BIAS_OFF,
- "codec %s can not start from non-off bias with idle_bias_off==1\n",
- codec->component.name);
- }
-
- if (driver->controls)
- snd_soc_add_codec_controls(codec, driver->controls,
- driver->num_controls);
- if (driver->dapm_routes)
- snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
- driver->num_dapm_routes);
-
- /* mark codec as probed and add to card codec list */
- codec->probed = 1;
- list_add(&codec->card_list, &card->codec_dev_list);
- list_add(&codec->dapm.list, &card->dapm_list);
- return 0;
-
-err_probe:
- soc_cleanup_codec_debugfs(codec);
- module_put(codec->dev->driver->owner);
-
- return ret;
-}
-
-static int soc_probe_platform(struct snd_soc_card *card,
- struct snd_soc_platform *platform)
-{
- int ret = 0;
- const struct snd_soc_platform_driver *driver = platform->driver;
- struct snd_soc_component *component;
- struct snd_soc_dai *dai;
-
- platform->component.card = card;
- platform->component.dapm.card = card;
-
- if (!try_module_get(platform->dev->driver->owner))
- return -ENODEV;
-
- soc_init_platform_debugfs(platform);
-
- if (driver->dapm_widgets)
- snd_soc_dapm_new_controls(&platform->component.dapm,
- driver->dapm_widgets, driver->num_dapm_widgets);
-
- /* Create DAPM widgets for each DAI stream */
- list_for_each_entry(component, &component_list, list) {
- if (component->dev != platform->dev)
- continue;
- list_for_each_entry(dai, &component->dai_list, list)
- snd_soc_dapm_new_dai_widgets(&platform->component.dapm,
- dai);
+ WARN(dapm->idle_bias_off &&
+ dapm->bias_level != SND_SOC_BIAS_OFF,
+ "codec %s can not start from non-off bias with idle_bias_off==1\n",
+ component->name);
}
- platform->component.dapm.idle_bias_off = 1;
-
- if (driver->probe) {
- ret = driver->probe(platform);
- if (ret < 0) {
- dev_err(platform->dev,
- "ASoC: failed to probe platform %d\n", ret);
- goto err_probe;
- }
- }
+ if (component->controls)
+ snd_soc_add_component_controls(component, component->controls,
+ component->num_controls);
+ if (component->dapm_routes)
+ snd_soc_dapm_add_routes(dapm, component->dapm_routes,
+ component->num_dapm_routes);
- if (driver->controls)
- snd_soc_add_platform_controls(platform, driver->controls,
- driver->num_controls);
- if (driver->dapm_routes)
- snd_soc_dapm_add_routes(&platform->component.dapm,
- driver->dapm_routes, driver->num_dapm_routes);
+ component->probed = 1;
+ list_add(&dapm->list, &card->dapm_list);
- /* mark platform as probed and add to card platform list */
- platform->probed = 1;
- list_add(&platform->component.dapm.list, &card->dapm_list);
+ /* This is a HACK and will be removed soon */
+ if (component->codec)
+ list_add(&component->codec->card_list, &card->codec_dev_list);
return 0;
err_probe:
- soc_cleanup_platform_debugfs(platform);
- module_put(platform->dev->driver->owner);
+ soc_cleanup_component_debugfs(component);
+ module_put(component->dev->driver->owner);
return ret;
}
@@ -1325,7 +1179,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
device_initialize(rtd->dev);
rtd->dev->parent = rtd->card->dev;
rtd->dev->release = rtd_release;
- rtd->dev->init_name = name;
+ dev_set_name(rtd->dev, "%s", name);
dev_set_drvdata(rtd->dev, rtd);
mutex_init(&rtd->pcm_mutex);
INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
@@ -1342,17 +1196,21 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
}
rtd->dev_registered = 1;
- /* add DAPM sysfs entries for this codec */
- ret = snd_soc_dapm_sys_add(rtd->dev);
- if (ret < 0)
- dev_err(rtd->dev,
- "ASoC: failed to add codec dapm sysfs entries: %d\n", ret);
+ if (rtd->codec) {
+ /* add DAPM sysfs entries for this codec */
+ ret = snd_soc_dapm_sys_add(rtd->dev);
+ if (ret < 0)
+ dev_err(rtd->dev,
+ "ASoC: failed to add codec dapm sysfs entries: %d\n",
+ ret);
- /* add codec sysfs entries */
- ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
- if (ret < 0)
- dev_err(rtd->dev,
- "ASoC: failed to add codec sysfs files: %d\n", ret);
+ /* add codec sysfs entries */
+ ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
+ if (ret < 0)
+ dev_err(rtd->dev,
+ "ASoC: failed to add codec sysfs files: %d\n",
+ ret);
+ }
return 0;
}
@@ -1361,33 +1219,31 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,
int order)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_component *component;
int i, ret;
/* probe the CPU-side component, if it is a CODEC */
- if (cpu_dai->codec &&
- !cpu_dai->codec->probed &&
- cpu_dai->codec->driver->probe_order == order) {
- ret = soc_probe_codec(card, cpu_dai->codec);
+ component = rtd->cpu_dai->component;
+ if (component->driver->probe_order == order) {
+ ret = soc_probe_component(card, component);
if (ret < 0)
return ret;
}
/* probe the CODEC-side components */
for (i = 0; i < rtd->num_codecs; i++) {
- if (!rtd->codec_dais[i]->codec->probed &&
- rtd->codec_dais[i]->codec->driver->probe_order == order) {
- ret = soc_probe_codec(card, rtd->codec_dais[i]->codec);
+ component = rtd->codec_dais[i]->component;
+ if (component->driver->probe_order == order) {
+ ret = soc_probe_component(card, component);
if (ret < 0)
return ret;
}
}
/* probe the platform */
- if (!platform->probed &&
- platform->driver->probe_order == order) {
- ret = soc_probe_platform(card, platform);
+ if (platform->component.driver->probe_order == order) {
+ ret = soc_probe_component(card, &platform->component);
if (ret < 0)
return ret;
}
@@ -1482,18 +1338,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
/* probe the cpu_dai */
if (!cpu_dai->probed &&
cpu_dai->driver->probe_order == order) {
- if (!cpu_dai->codec) {
- if (!try_module_get(cpu_dai->dev->driver->owner))
- return -ENODEV;
- }
-
if (cpu_dai->driver->probe) {
ret = cpu_dai->driver->probe(cpu_dai);
if (ret < 0) {
dev_err(cpu_dai->dev,
"ASoC: failed to probe CPU DAI %s: %d\n",
cpu_dai->name, ret);
- module_put(cpu_dai->dev->driver->owner);
return ret;
}
}
@@ -1654,17 +1504,24 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
- const char *codecname = aux_dev->codec_name;
+ const char *name = aux_dev->codec_name;
- rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname);
- if (!rtd->codec) {
+ rtd->component = soc_find_component(aux_dev->codec_of_node, name);
+ if (!rtd->component) {
if (aux_dev->codec_of_node)
- codecname = of_node_full_name(aux_dev->codec_of_node);
+ name = of_node_full_name(aux_dev->codec_of_node);
- dev_err(card->dev, "ASoC: %s not registered\n", codecname);
+ dev_err(card->dev, "ASoC: %s not registered\n", name);
return -EPROBE_DEFER;
}
+ /*
+ * Some places still reference rtd->codec, so we have to keep that
+ * initialized if the component is a CODEC. Once all those references
+ * have been removed, this code can be removed as well.
+ */
+ rtd->codec = rtd->component->codec;
+
return 0;
}
@@ -1674,18 +1531,13 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
int ret;
- if (rtd->codec->probed) {
- dev_err(rtd->codec->dev, "ASoC: codec already probed\n");
- return -EBUSY;
- }
-
- ret = soc_probe_codec(card, rtd->codec);
+ ret = soc_probe_component(card, rtd->component);
if (ret < 0)
return ret;
/* do machine specific initialization */
if (aux_dev->init) {
- ret = aux_dev->init(&rtd->codec->dapm);
+ ret = aux_dev->init(rtd->component);
if (ret < 0) {
dev_err(card->dev, "ASoC: failed to init %s: %d\n",
aux_dev->name, ret);
@@ -1699,7 +1551,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_component *component = rtd->component;
/* unregister the rtd device */
if (rtd->dev_registered) {
@@ -1708,8 +1560,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
rtd->dev_registered = 0;
}
- if (codec && codec->probed)
- soc_remove_codec(codec);
+ if (component && component->probed)
+ soc_remove_component(component);
}
static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
@@ -2107,19 +1959,14 @@ static struct platform_driver soc_driver = {
int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
struct snd_ac97_bus_ops *ops, int num)
{
- mutex_lock(&codec->mutex);
-
codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
- if (codec->ac97 == NULL) {
- mutex_unlock(&codec->mutex);
+ if (codec->ac97 == NULL)
return -ENOMEM;
- }
codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL);
if (codec->ac97->bus == NULL) {
kfree(codec->ac97);
codec->ac97 = NULL;
- mutex_unlock(&codec->mutex);
return -ENOMEM;
}
@@ -2132,7 +1979,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
*/
codec->ac97_created = 1;
- mutex_unlock(&codec->mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
@@ -2302,7 +2148,6 @@ EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset);
*/
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
{
- mutex_lock(&codec->mutex);
#ifdef CONFIG_SND_SOC_AC97_BUS
soc_unregister_ac97_codec(codec);
#endif
@@ -2310,7 +2155,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
kfree(codec->ac97);
codec->ac97 = NULL;
codec->ac97_created = 0;
- mutex_unlock(&codec->mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
@@ -3027,9 +2871,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
unsigned int val, val_mask;
int ret;
- val = ((ucontrol->value.integer.value[0] + min) & mask);
if (invert)
- val = max - val;
+ val = (max - ucontrol->value.integer.value[0]) & mask;
+ else
+ val = ((ucontrol->value.integer.value[0] + min) & mask);
val_mask = mask << shift;
val = val << shift;
@@ -3038,9 +2883,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
return ret;
if (snd_soc_volsw_is_stereo(mc)) {
- val = ((ucontrol->value.integer.value[1] + min) & mask);
if (invert)
- val = max - val;
+ val = (max - ucontrol->value.integer.value[1]) & mask;
+ else
+ val = ((ucontrol->value.integer.value[1] + min) & mask);
val_mask = mask << shift;
val = val << shift;
@@ -3085,8 +2931,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
if (invert)
ucontrol->value.integer.value[0] =
max - ucontrol->value.integer.value[0];
- ucontrol->value.integer.value[0] =
- ucontrol->value.integer.value[0] - min;
+ else
+ ucontrol->value.integer.value[0] =
+ ucontrol->value.integer.value[0] - min;
if (snd_soc_volsw_is_stereo(mc)) {
ret = snd_soc_component_read(component, rreg, &val);
@@ -3097,8 +2944,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
if (invert)
ucontrol->value.integer.value[1] =
max - ucontrol->value.integer.value[1];
- ucontrol->value.integer.value[1] =
- ucontrol->value.integer.value[1] - min;
+ else
+ ucontrol->value.integer.value[1] =
+ ucontrol->value.integer.value[1] - min;
}
return 0;
@@ -3203,7 +3051,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
unsigned int val, mask;
void *data;
- if (!component->regmap)
+ if (!component->regmap || !params->num_regs)
return -EINVAL;
len = params->num_regs * component->val_bytes;
@@ -3928,8 +3776,11 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card);
*/
int snd_soc_unregister_card(struct snd_soc_card *card)
{
- if (card->instantiated)
+ if (card->instantiated) {
+ card->instantiated = false;
+ snd_soc_dapm_shutdown(card);
soc_cleanup_card_resources(card);
+ }
dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
return 0;
@@ -4116,6 +3967,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
component->dev = dev;
component->driver = driver;
+ component->probe = component->driver->probe;
+ component->remove = component->driver->remove;
if (!component->dapm_ptr)
component->dapm_ptr = &component->dapm;
@@ -4124,19 +3977,42 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
dapm->dev = dev;
dapm->component = component;
dapm->bias_level = SND_SOC_BIAS_OFF;
+ dapm->idle_bias_off = true;
if (driver->seq_notifier)
dapm->seq_notifier = snd_soc_component_seq_notifier;
if (driver->stream_event)
dapm->stream_event = snd_soc_component_stream_event;
+ component->controls = driver->controls;
+ component->num_controls = driver->num_controls;
+ component->dapm_widgets = driver->dapm_widgets;
+ component->num_dapm_widgets = driver->num_dapm_widgets;
+ component->dapm_routes = driver->dapm_routes;
+ component->num_dapm_routes = driver->num_dapm_routes;
+
INIT_LIST_HEAD(&component->dai_list);
mutex_init(&component->io_mutex);
return 0;
}
+static void snd_soc_component_init_regmap(struct snd_soc_component *component)
+{
+ if (!component->regmap)
+ component->regmap = dev_get_regmap(component->dev, NULL);
+ if (component->regmap) {
+ int val_bytes = regmap_get_val_bytes(component->regmap);
+ /* Errors are legitimate for non-integer byte multiples */
+ if (val_bytes > 0)
+ component->val_bytes = val_bytes;
+ }
+}
+
static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
{
+ if (!component->write && !component->read)
+ snd_soc_component_init_regmap(component);
+
list_add(&component->list, &component_list);
}
@@ -4225,22 +4101,18 @@ found:
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
-static int snd_soc_platform_drv_write(struct snd_soc_component *component,
- unsigned int reg, unsigned int val)
+static int snd_soc_platform_drv_probe(struct snd_soc_component *component)
{
struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
- return platform->driver->write(platform, reg, val);
+ return platform->driver->probe(platform);
}
-static int snd_soc_platform_drv_read(struct snd_soc_component *component,
- unsigned int reg, unsigned int *val)
+static void snd_soc_platform_drv_remove(struct snd_soc_component *component)
{
struct snd_soc_platform *platform = snd_soc_component_to_platform(component);
- *val = platform->driver->read(platform, reg);
-
- return 0;
+ platform->driver->remove(platform);
}
/**
@@ -4261,10 +4133,15 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
platform->dev = dev;
platform->driver = platform_drv;
- if (platform_drv->write)
- platform->component.write = snd_soc_platform_drv_write;
- if (platform_drv->read)
- platform->component.read = snd_soc_platform_drv_read;
+
+ if (platform_drv->probe)
+ platform->component.probe = snd_soc_platform_drv_probe;
+ if (platform_drv->remove)
+ platform->component.remove = snd_soc_platform_drv_remove;
+
+#ifdef CONFIG_DEBUG_FS
+ platform->component.debugfs_prefix = "platform";
+#endif
mutex_lock(&client_mutex);
snd_soc_component_add_unlocked(&platform->component);
@@ -4386,6 +4263,20 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
stream->formats |= codec_format_map[i];
}
+static int snd_soc_codec_drv_probe(struct snd_soc_component *component)
+{
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+ return codec->driver->probe(codec);
+}
+
+static void snd_soc_codec_drv_remove(struct snd_soc_component *component)
+{
+ struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+
+ codec->driver->remove(codec);
+}
+
static int snd_soc_codec_drv_write(struct snd_soc_component *component,
unsigned int reg, unsigned int val)
{
@@ -4424,7 +4315,6 @@ int snd_soc_register_codec(struct device *dev,
{
struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
- struct regmap *regmap;
int ret, i;
dev_dbg(dev, "codec register %s\n", dev_name(dev));
@@ -4434,18 +4324,37 @@ int snd_soc_register_codec(struct device *dev,
return -ENOMEM;
codec->component.dapm_ptr = &codec->dapm;
+ codec->component.codec = codec;
ret = snd_soc_component_initialize(&codec->component,
&codec_drv->component_driver, dev);
if (ret)
goto err_free;
+ if (codec_drv->controls) {
+ codec->component.controls = codec_drv->controls;
+ codec->component.num_controls = codec_drv->num_controls;
+ }
+ if (codec_drv->dapm_widgets) {
+ codec->component.dapm_widgets = codec_drv->dapm_widgets;
+ codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets;
+ }
+ if (codec_drv->dapm_routes) {
+ codec->component.dapm_routes = codec_drv->dapm_routes;
+ codec->component.num_dapm_routes = codec_drv->num_dapm_routes;
+ }
+
+ if (codec_drv->probe)
+ codec->component.probe = snd_soc_codec_drv_probe;
+ if (codec_drv->remove)
+ codec->component.remove = snd_soc_codec_drv_remove;
if (codec_drv->write)
codec->component.write = snd_soc_codec_drv_write;
if (codec_drv->read)
codec->component.read = snd_soc_codec_drv_read;
codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time;
- codec->dapm.codec = codec;
+ codec->dapm.idle_bias_off = codec_drv->idle_bias_off;
+ codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off;
if (codec_drv->seq_notifier)
codec->dapm.seq_notifier = codec_drv->seq_notifier;
if (codec_drv->set_bias_level)
@@ -4455,23 +4364,13 @@ int snd_soc_register_codec(struct device *dev,
codec->component.val_bytes = codec_drv->reg_word_size;
mutex_init(&codec->mutex);
- if (!codec->component.write) {
- if (codec_drv->get_regmap)
- regmap = codec_drv->get_regmap(dev);
- else
- regmap = dev_get_regmap(dev, NULL);
-
- if (regmap) {
- ret = snd_soc_component_init_io(&codec->component,
- regmap);
- if (ret) {
- dev_err(codec->dev,
- "Failed to set cache I/O:%d\n",
- ret);
- goto err_cleanup;
- }
- }
- }
+#ifdef CONFIG_DEBUG_FS
+ codec->component.init_debugfs = soc_init_codec_debugfs;
+ codec->component.debugfs_prefix = "codec";
+#endif
+
+ if (codec_drv->get_regmap)
+ codec->component.regmap = codec_drv->get_regmap(dev);
for (i = 0; i < num_dai; i++) {
fixup_codec_formats(&dai_drv[i].playback);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 8348352dc2c6..2c456a376ade 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -326,12 +326,13 @@ static struct list_head *dapm_kcontrol_get_path_list(
list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
list_kcontrol)
-static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
+unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
return data->value;
}
+EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
unsigned int value)
@@ -1683,6 +1684,22 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
}
}
+static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
+{
+ if (dapm->idle_bias_off)
+ return true;
+
+ switch (snd_power_get_state(dapm->card->snd_card)) {
+ case SNDRV_CTL_POWER_D3hot:
+ case SNDRV_CTL_POWER_D3cold:
+ return dapm->suspend_bias_off;
+ default:
+ break;
+ }
+
+ return false;
+}
+
/*
* Scan each dapm widget for complete audio path.
* A complete path is a route that has valid endpoints i.e.:-
@@ -1706,7 +1723,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
trace_snd_soc_dapm_start(card);
list_for_each_entry(d, &card->dapm_list, list) {
- if (d->idle_bias_off)
+ if (dapm_idle_bias_off(d))
d->target_bias_level = SND_SOC_BIAS_OFF;
else
d->target_bias_level = SND_SOC_BIAS_STANDBY;
@@ -1772,7 +1789,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
if (d->target_bias_level > bias)
bias = d->target_bias_level;
list_for_each_entry(d, &card->dapm_list, list)
- if (!d->idle_bias_off)
+ if (!dapm_idle_bias_off(d))
d->target_bias_level = bias;
trace_snd_soc_dapm_walk_done(card);
@@ -2860,12 +2877,14 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg_val, val;
- int ret = 0;
- if (e->reg != SND_SOC_NOPM)
- ret = soc_dapm_read(dapm, e->reg, &reg_val);
- else
+ if (e->reg != SND_SOC_NOPM) {
+ int ret = soc_dapm_read(dapm, e->reg, &reg_val);
+ if (ret)
+ return ret;
+ } else {
reg_val = dapm_kcontrol_get_value(kcontrol);
+ }
val = (reg_val >> e->shift_l) & e->mask;
ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
@@ -2875,7 +2894,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
ucontrol->value.enumerated.item[1] = val;
}
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
@@ -3107,7 +3126,8 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
}
w->dapm = dapm;
- w->codec = dapm->codec;
+ if (dapm->component)
+ w->codec = dapm->component->codec;
INIT_LIST_HEAD(&w->sources);
INIT_LIST_HEAD(&w->sinks);
INIT_LIST_HEAD(&w->list);
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 6307f85e871b..b329b84bc5af 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -336,10 +336,12 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = {
};
static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
+ .component_driver = {
+ .probe_order = SND_SOC_COMP_ORDER_LATE,
+ },
.ops = &dmaengine_pcm_ops,
.pcm_new = dmaengine_pcm_new,
.pcm_free = dmaengine_pcm_free,
- .probe_order = SND_SOC_COMP_ORDER_LATE,
};
static const char * const dmaengine_pcm_dma_channel_names[] = {
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 7767fbd73eb7..9b3939049cef 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -271,31 +271,3 @@ int snd_soc_platform_write(struct snd_soc_platform *platform,
return snd_soc_component_write(&platform->component, reg, val);
}
EXPORT_SYMBOL_GPL(snd_soc_platform_write);
-
-/**
- * snd_soc_component_init_io() - Initialize regmap IO
- *
- * @component: component to initialize
- * @regmap: regmap instance to use for IO operations
- *
- * Return: 0 on success, a negative error code otherwise
- */
-int snd_soc_component_init_io(struct snd_soc_component *component,
- struct regmap *regmap)
-{
- int ret;
-
- if (!regmap)
- return -EINVAL;
-
- ret = regmap_get_val_bytes(regmap);
- /* Errors are legitimate for non-integer byte
- * multiples */
- if (ret > 0)
- component->val_bytes = ret;
-
- component->regmap = regmap;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_component_init_io);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 731fdb5b5f9b..642c86240752 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -2352,7 +2352,11 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
fe->dpcm[stream].runtime = fe_substream->runtime;
- if (dpcm_path_get(fe, stream, &list) <= 0) {
+ ret = dpcm_path_get(fe, stream, &list);
+ if (ret < 0) {
+ mutex_unlock(&fe->card->mutex);
+ return ret;
+ } else if (ret == 0) {
dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
fe->dai_link->name, stream ? "capture" : "playback");
}
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
index 0e5a8f35d0ad..a7dc3c56f44d 100644
--- a/sound/soc/spear/spear_pcm.c
+++ b/sound/soc/spear/spear_pcm.c
@@ -4,7 +4,7 @@
* sound/soc/spear/spear_pcm.c
*
* Copyright (C) 2012 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ * Rajeev Kumar<rajeevkumar.linux@gmail.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -50,6 +50,6 @@ int devm_spear_pcm_platform_register(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_spear_pcm_platform_register);
-MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>");
MODULE_DESCRIPTION("SPEAr PCM DMA module");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 9577121ce971..ca8037634100 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -21,7 +21,7 @@
*/
#ifndef __TEGRA_ASOC_UTILS_H__
-#define __TEGRA_ASOC_UTILS_H_
+#define __TEGRA_ASOC_UTILS_H__
struct clk;
struct device;