summaryrefslogtreecommitdiff
path: root/sound/soc/fsl
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/Kconfig2
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c141
-rw-r--r--sound/soc/fsl/fsl_esai.c88
-rw-r--r--sound/soc/fsl/fsl_sai.c59
-rw-r--r--sound/soc/fsl/fsl_spdif.c73
-rw-r--r--sound/soc/fsl/fsl_ssi.c102
-rw-r--r--sound/soc/fsl/imx-spdif.c1
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c2
-rw-r--r--sound/soc/fsl/p1022_ds.c2
-rw-r--r--sound/soc/fsl/p1022_rdk.c2
10 files changed, 436 insertions, 36 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 19c302b0d..14dfdee05 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -283,6 +283,8 @@ config SND_SOC_IMX_MC13783
config SND_SOC_FSL_ASOC_CARD
tristate "Generic ASoC Sound Card with ASRC support"
depends on OF && I2C
+ # enforce SND_SOC_FSL_ASOC_CARD=m if SND_AC97_CODEC=m:
+ depends on SND_AC97_CODEC || SND_AC97_CODEC=n
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_PCM_DMA
select SND_SOC_FSL_ESAI
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 96f55ae75..1b05d1c5d 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -14,6 +14,9 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_platform.h>
+#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
+#include <sound/ac97_codec.h>
+#endif
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -115,6 +118,11 @@ static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
SND_SOC_DAPM_MIC("DMIC", NULL),
};
+static bool fsl_asoc_card_is_ac97(struct fsl_asoc_card_priv *priv)
+{
+ return priv->dai_fmt == SND_SOC_DAIFMT_AC97;
+}
+
static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -133,7 +141,9 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
* set_bias_level(), bypass the remaining settings in hw_params().
* Note: (dai_fmt & CBM_CFM) includes CBM_CFM and CBM_CFS.
*/
- if (priv->card.set_bias_level && priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM)
+ if ((priv->card.set_bias_level &&
+ priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM) ||
+ fsl_asoc_card_is_ac97(priv))
return 0;
/* Specific configurations of DAIs starts from here */
@@ -300,7 +310,7 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
ext_port--;
/*
- * Use asynchronous mode (6 wires) for all cases.
+ * Use asynchronous mode (6 wires) for all cases except AC97.
* If only 4 wires are needed, just set SSI into
* synchronous mode and enable 4 PADs in IOMUX.
*/
@@ -346,15 +356,30 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
IMX_AUDMUX_V2_PTCR_TCLKDIR;
break;
default:
- return -EINVAL;
+ if (!fsl_asoc_card_is_ac97(priv))
+ return -EINVAL;
+ }
+
+ if (fsl_asoc_card_is_ac97(priv)) {
+ int_ptcr = IMX_AUDMUX_V2_PTCR_SYN |
+ IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+ IMX_AUDMUX_V2_PTCR_TCLKDIR;
+ ext_ptcr = IMX_AUDMUX_V2_PTCR_SYN |
+ IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
+ IMX_AUDMUX_V2_PTCR_TFSDIR;
}
/* Asynchronous mode can not be set along with RCLKDIR */
- ret = imx_audmux_v2_configure_port(int_port, 0,
- IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
- if (ret) {
- dev_err(dev, "audmux internal port setup failed\n");
- return ret;
+ if (!fsl_asoc_card_is_ac97(priv)) {
+ unsigned int pdcr =
+ IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port);
+
+ ret = imx_audmux_v2_configure_port(int_port, 0,
+ pdcr);
+ if (ret) {
+ dev_err(dev, "audmux internal port setup failed\n");
+ return ret;
+ }
}
ret = imx_audmux_v2_configure_port(int_port, int_ptcr,
@@ -364,11 +389,16 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
return ret;
}
- ret = imx_audmux_v2_configure_port(ext_port, 0,
- IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
- if (ret) {
- dev_err(dev, "audmux external port setup failed\n");
- return ret;
+ if (!fsl_asoc_card_is_ac97(priv)) {
+ unsigned int pdcr =
+ IMX_AUDMUX_V2_PDCR_RXDSEL(int_port);
+
+ ret = imx_audmux_v2_configure_port(ext_port, 0,
+ pdcr);
+ if (ret) {
+ dev_err(dev, "audmux external port setup failed\n");
+ return ret;
+ }
}
ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr,
@@ -389,6 +419,23 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
struct device *dev = card->dev;
int ret;
+ if (fsl_asoc_card_is_ac97(priv)) {
+#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
+ struct snd_soc_codec *codec = card->rtd[0].codec;
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+ /*
+ * Use slots 3/4 for S/PDIF so SSI won't try to enable
+ * other slots and send some samples there
+ * due to SLOTREQ bits for S/PDIF received from codec
+ */
+ snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,
+ AC97_EA_SPSA_SLOT_MASK, AC97_EA_SPSA_3_4);
+#endif
+
+ return 0;
+ }
+
ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
if (ret) {
@@ -407,7 +454,6 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
struct platform_device *cpu_pdev;
struct fsl_asoc_card_priv *priv;
struct i2c_client *codec_dev;
- struct clk *codec_clk;
const char *codec_dai_name;
u32 width;
int ret;
@@ -420,9 +466,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
/* Give a chance to old DT binding */
if (!cpu_np)
cpu_np = of_parse_phandle(np, "ssi-controller", 0);
- codec_np = of_parse_phandle(np, "audio-codec", 0);
- if (!cpu_np || !codec_np) {
- dev_err(&pdev->dev, "phandle missing or invalid\n");
+ if (!cpu_np) {
+ dev_err(&pdev->dev, "CPU phandle missing or invalid\n");
ret = -EINVAL;
goto fail;
}
@@ -434,22 +479,24 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
goto fail;
}
- codec_dev = of_find_i2c_device_by_node(codec_np);
- if (!codec_dev) {
- dev_err(&pdev->dev, "failed to find codec platform device\n");
- ret = -EINVAL;
- goto fail;
- }
+ codec_np = of_parse_phandle(np, "audio-codec", 0);
+ if (codec_np)
+ codec_dev = of_find_i2c_device_by_node(codec_np);
+ else
+ codec_dev = NULL;
asrc_np = of_parse_phandle(np, "audio-asrc", 0);
if (asrc_np)
asrc_pdev = of_find_device_by_node(asrc_np);
/* Get the MCLK rate only, and leave it controlled by CODEC drivers */
- codec_clk = clk_get(&codec_dev->dev, NULL);
- if (!IS_ERR(codec_clk)) {
- priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
- clk_put(codec_clk);
+ if (codec_dev) {
+ struct clk *codec_clk = clk_get(&codec_dev->dev, NULL);
+
+ if (!IS_ERR(codec_clk)) {
+ priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
+ clk_put(codec_clk);
+ }
}
/* Default sample rate and format, will be updated in hw_params() */
@@ -486,12 +533,22 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->codec_priv.fll_id = WM8960_SYSCLK_AUTO;
priv->codec_priv.pll_id = WM8960_SYSCLK_AUTO;
priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+ } else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) {
+ codec_dai_name = "ac97-hifi";
+ priv->card.set_bias_level = NULL;
+ priv->dai_fmt = SND_SOC_DAIFMT_AC97;
} else {
dev_err(&pdev->dev, "unknown Device Tree compatible\n");
ret = -EINVAL;
goto asrc_fail;
}
+ if (!fsl_asoc_card_is_ac97(priv) && !codec_dev) {
+ dev_err(&pdev->dev, "failed to find codec device\n");
+ ret = -EINVAL;
+ goto asrc_fail;
+ }
+
/* Common settings for corresponding Freescale CPU DAI driver */
if (strstr(cpu_np->name, "ssi")) {
/* Only SSI needs to configure AUDMUX */
@@ -508,7 +565,9 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
}
- sprintf(priv->name, "%s-audio", codec_dev->name);
+ snprintf(priv->name, sizeof(priv->name), "%s-audio",
+ fsl_asoc_card_is_ac97(priv) ? "ac97" :
+ codec_dev->name);
/* Initialize sound card */
priv->pdev = pdev;
@@ -532,8 +591,26 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
/* Normal DAI Link */
priv->dai_link[0].cpu_of_node = cpu_np;
- priv->dai_link[0].codec_of_node = codec_np;
priv->dai_link[0].codec_dai_name = codec_dai_name;
+
+ if (!fsl_asoc_card_is_ac97(priv))
+ priv->dai_link[0].codec_of_node = codec_np;
+ else {
+ u32 idx;
+
+ ret = of_property_read_u32(cpu_np, "cell-index", &idx);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "cannot get CPU index property\n");
+ goto asrc_fail;
+ }
+
+ priv->dai_link[0].codec_name =
+ devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "ac97-codec.%u",
+ (unsigned int)idx);
+ }
+
priv->dai_link[0].platform_of_node = cpu_np;
priv->dai_link[0].dai_fmt = priv->dai_fmt;
priv->card.num_links = 1;
@@ -544,6 +621,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->dai_link[1].platform_of_node = asrc_np;
priv->dai_link[2].codec_dai_name = codec_dai_name;
priv->dai_link[2].codec_of_node = codec_np;
+ priv->dai_link[2].codec_name =
+ priv->dai_link[0].codec_name;
priv->dai_link[2].cpu_of_node = cpu_np;
priv->dai_link[2].dai_fmt = priv->dai_fmt;
priv->card.num_links = 3;
@@ -579,20 +658,22 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
asrc_fail:
of_node_put(asrc_np);
-fail:
of_node_put(codec_np);
+fail:
of_node_put(cpu_np);
return ret;
}
static const struct of_device_id fsl_asoc_card_dt_ids[] = {
+ { .compatible = "fsl,imx-audio-ac97", },
{ .compatible = "fsl,imx-audio-cs42888", },
{ .compatible = "fsl,imx-audio-sgtl5000", },
{ .compatible = "fsl,imx-audio-wm8962", },
{ .compatible = "fsl,imx-audio-wm8960", },
{}
};
+MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
static struct platform_driver fsl_asoc_card_driver = {
.probe = fsl_asoc_card_probe,
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 837979ea5..59f234e51 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -652,6 +652,24 @@ static const struct snd_soc_component_driver fsl_esai_component = {
.name = "fsl-esai",
};
+static const struct reg_default fsl_esai_reg_defaults[] = {
+ {0x8, 0x00000000},
+ {0x10, 0x00000000},
+ {0x18, 0x00000000},
+ {0x98, 0x00000000},
+ {0xd0, 0x00000000},
+ {0xd4, 0x00000000},
+ {0xd8, 0x00000000},
+ {0xdc, 0x00000000},
+ {0xe0, 0x00000000},
+ {0xe4, 0x0000ffff},
+ {0xe8, 0x0000ffff},
+ {0xec, 0x0000ffff},
+ {0xf0, 0x0000ffff},
+ {0xf8, 0x00000000},
+ {0xfc, 0x00000000},
+};
+
static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -684,6 +702,31 @@ static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
}
}
+static bool fsl_esai_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case REG_ESAI_ETDR:
+ case REG_ESAI_ERDR:
+ case REG_ESAI_ESR:
+ case REG_ESAI_TFSR:
+ case REG_ESAI_RFSR:
+ case REG_ESAI_TX0:
+ case REG_ESAI_TX1:
+ case REG_ESAI_TX2:
+ case REG_ESAI_TX3:
+ case REG_ESAI_TX4:
+ case REG_ESAI_TX5:
+ case REG_ESAI_RX0:
+ case REG_ESAI_RX1:
+ case REG_ESAI_RX2:
+ case REG_ESAI_RX3:
+ case REG_ESAI_SAISR:
+ return true;
+ default:
+ return false;
+ }
+}
+
static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -721,8 +764,12 @@ static const struct regmap_config fsl_esai_regmap_config = {
.val_bits = 32,
.max_register = REG_ESAI_PCRC,
+ .reg_defaults = fsl_esai_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_esai_reg_defaults),
.readable_reg = fsl_esai_readable_reg,
+ .volatile_reg = fsl_esai_volatile_reg,
.writeable_reg = fsl_esai_writeable_reg,
+ .cache_type = REGCACHE_RBTREE,
};
static int fsl_esai_probe(struct platform_device *pdev)
@@ -853,10 +900,51 @@ static const struct of_device_id fsl_esai_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
+#ifdef CONFIG_PM_SLEEP
+static int fsl_esai_suspend(struct device *dev)
+{
+ struct fsl_esai *esai = dev_get_drvdata(dev);
+
+ regcache_cache_only(esai->regmap, true);
+ regcache_mark_dirty(esai->regmap);
+
+ return 0;
+}
+
+static int fsl_esai_resume(struct device *dev)
+{
+ struct fsl_esai *esai = dev_get_drvdata(dev);
+ int ret;
+
+ regcache_cache_only(esai->regmap, false);
+
+ /* FIFO reset for safety */
+ regmap_update_bits(esai->regmap, REG_ESAI_TFCR,
+ ESAI_xFCR_xFR, ESAI_xFCR_xFR);
+ regmap_update_bits(esai->regmap, REG_ESAI_RFCR,
+ ESAI_xFCR_xFR, ESAI_xFCR_xFR);
+
+ ret = regcache_sync(esai->regmap);
+ if (ret)
+ return ret;
+
+ /* FIFO reset done */
+ regmap_update_bits(esai->regmap, REG_ESAI_TFCR, ESAI_xFCR_xFR, 0);
+ regmap_update_bits(esai->regmap, REG_ESAI_RFCR, ESAI_xFCR_xFR, 0);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_esai_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(fsl_esai_suspend, fsl_esai_resume)
+};
+
static struct platform_driver fsl_esai_driver = {
.probe = fsl_esai_probe,
.driver = {
.name = "fsl-esai-dai",
+ .pm = &fsl_esai_pm_ops,
.of_match_table = fsl_esai_dt_ids,
},
};
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index a18fd92c4..08b460ba0 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -27,13 +27,13 @@
#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
FSL_SAI_CSR_FEIE)
-static u32 fsl_sai_rates[] = {
+static const unsigned int fsl_sai_rates[] = {
8000, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 64000,
88200, 96000, 176400, 192000
};
-static struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
+static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
.count = ARRAY_SIZE(fsl_sai_rates),
.list = fsl_sai_rates,
};
@@ -454,7 +454,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
* Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
* Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
*/
- regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
+ sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0);
regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
@@ -504,6 +505,24 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
+
+ /*
+ * For sai master mode, after several open/close sai,
+ * there will be no frame clock, and can't recover
+ * anymore. Add software reset to fix this issue.
+ * This is a hardware bug, and will be fix in the
+ * next sai version.
+ */
+ if (!sai->is_slave_mode) {
+ /* Software Reset for both Tx and Rx */
+ regmap_write(sai->regmap,
+ FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+ regmap_write(sai->regmap,
+ FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+ /* Clear SR bit to finish the reset */
+ regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+ regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+ }
}
break;
default:
@@ -637,6 +656,8 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case FSL_SAI_TCSR:
+ case FSL_SAI_RCSR:
case FSL_SAI_TFR:
case FSL_SAI_RFR:
case FSL_SAI_TDR:
@@ -681,6 +702,7 @@ static const struct regmap_config fsl_sai_regmap_config = {
.readable_reg = fsl_sai_readable_reg,
.volatile_reg = fsl_sai_volatile_reg,
.writeable_reg = fsl_sai_writeable_reg,
+ .cache_type = REGCACHE_FLAT,
};
static int fsl_sai_probe(struct platform_device *pdev)
@@ -801,11 +823,42 @@ static const struct of_device_id fsl_sai_ids[] = {
{ .compatible = "fsl,imx6sx-sai", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, fsl_sai_ids);
+
+#ifdef CONFIG_PM_SLEEP
+static int fsl_sai_suspend(struct device *dev)
+{
+ struct fsl_sai *sai = dev_get_drvdata(dev);
+
+ regcache_cache_only(sai->regmap, true);
+ regcache_mark_dirty(sai->regmap);
+
+ return 0;
+}
+
+static int fsl_sai_resume(struct device *dev)
+{
+ struct fsl_sai *sai = dev_get_drvdata(dev);
+
+ regcache_cache_only(sai->regmap, false);
+ regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+ regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+ msleep(1);
+ regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+ regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+ return regcache_sync(sai->regmap);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_sai_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(fsl_sai_suspend, fsl_sai_resume)
+};
static struct platform_driver fsl_sai_driver = {
.probe = fsl_sai_probe,
.driver = {
.name = "fsl-sai",
+ .pm = &fsl_sai_pm_ops,
.of_match_table = fsl_sai_ids,
},
};
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index ab729f242..3d59bb671 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -108,6 +108,8 @@ struct fsl_spdif_priv {
struct clk *sysclk;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
+ /* regcache for SRPC */
+ u32 regcache_srpc;
};
/* DPLL locked and lock loss interrupt handler */
@@ -300,6 +302,8 @@ static int spdif_softreset(struct fsl_spdif_priv *spdif_priv)
struct regmap *regmap = spdif_priv->regmap;
u32 val, cycle = 1000;
+ regcache_cache_bypass(regmap, true);
+
regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET);
/*
@@ -310,6 +314,10 @@ static int spdif_softreset(struct fsl_spdif_priv *spdif_priv)
regmap_read(regmap, REG_SPDIF_SCR, &val);
} while ((val & SCR_SOFT_RESET) && cycle--);
+ regcache_cache_bypass(regmap, false);
+ regcache_mark_dirty(regmap);
+ regcache_sync(regmap);
+
if (cycle)
return 0;
else
@@ -997,6 +1005,14 @@ static const struct snd_soc_component_driver fsl_spdif_component = {
};
/* FSL SPDIF REGMAP */
+static const struct reg_default fsl_spdif_reg_defaults[] = {
+ {0x0, 0x00000400},
+ {0x4, 0x00000000},
+ {0xc, 0x00000000},
+ {0x34, 0x00000000},
+ {0x38, 0x00000000},
+ {0x50, 0x00020f00},
+};
static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
{
@@ -1022,6 +1038,26 @@ static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
}
}
+static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case REG_SPDIF_SRPC:
+ case REG_SPDIF_SIS:
+ case REG_SPDIF_SRL:
+ case REG_SPDIF_SRR:
+ case REG_SPDIF_SRCSH:
+ case REG_SPDIF_SRCSL:
+ case REG_SPDIF_SRU:
+ case REG_SPDIF_SRQ:
+ case REG_SPDIF_STL:
+ case REG_SPDIF_STR:
+ case REG_SPDIF_SRFM:
+ return true;
+ default:
+ return false;
+ }
+}
+
static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -1047,8 +1083,12 @@ static const struct regmap_config fsl_spdif_regmap_config = {
.val_bits = 32,
.max_register = REG_SPDIF_STC,
+ .reg_defaults = fsl_spdif_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_spdif_reg_defaults),
.readable_reg = fsl_spdif_readable_reg,
+ .volatile_reg = fsl_spdif_volatile_reg,
.writeable_reg = fsl_spdif_writeable_reg,
+ .cache_type = REGCACHE_RBTREE,
};
static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
@@ -1271,6 +1311,38 @@ static int fsl_spdif_probe(struct platform_device *pdev)
return ret;
}
+#ifdef CONFIG_PM_SLEEP
+static int fsl_spdif_suspend(struct device *dev)
+{
+ struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
+
+ regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC,
+ &spdif_priv->regcache_srpc);
+
+ regcache_cache_only(spdif_priv->regmap, true);
+ regcache_mark_dirty(spdif_priv->regmap);
+
+ return 0;
+}
+
+static int fsl_spdif_resume(struct device *dev)
+{
+ struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
+
+ regcache_cache_only(spdif_priv->regmap, false);
+
+ regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC,
+ SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
+ spdif_priv->regcache_srpc);
+
+ return regcache_sync(spdif_priv->regmap);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_spdif_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume)
+};
+
static const struct of_device_id fsl_spdif_dt_ids[] = {
{ .compatible = "fsl,imx35-spdif", },
{ .compatible = "fsl,vf610-spdif", },
@@ -1282,6 +1354,7 @@ static struct platform_driver fsl_spdif_driver = {
.driver = {
.name = "fsl-spdif-dai",
.of_match_table = fsl_spdif_dt_ids,
+ .pm = &fsl_spdif_pm,
},
.probe = fsl_spdif_probe,
};
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 37c5cd4d0..95d239230 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -111,12 +111,75 @@ struct fsl_ssi_rxtx_reg_val {
struct fsl_ssi_reg_val rx;
struct fsl_ssi_reg_val tx;
};
+
+static const struct reg_default fsl_ssi_reg_defaults[] = {
+ {0x10, 0x00000000},
+ {0x18, 0x00003003},
+ {0x1c, 0x00000200},
+ {0x20, 0x00000200},
+ {0x24, 0x00040000},
+ {0x28, 0x00040000},
+ {0x38, 0x00000000},
+ {0x48, 0x00000000},
+ {0x4c, 0x00000000},
+ {0x54, 0x00000000},
+ {0x58, 0x00000000},
+};
+
+static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CCSR_SSI_SACCEN:
+ case CCSR_SSI_SACCDIS:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CCSR_SSI_STX0:
+ case CCSR_SSI_STX1:
+ case CCSR_SSI_SRX0:
+ case CCSR_SSI_SRX1:
+ case CCSR_SSI_SISR:
+ case CCSR_SSI_SFCSR:
+ case CCSR_SSI_SACADD:
+ case CCSR_SSI_SACDAT:
+ case CCSR_SSI_SATAG:
+ case CCSR_SSI_SACCST:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CCSR_SSI_SRX0:
+ case CCSR_SSI_SRX1:
+ case CCSR_SSI_SACCST:
+ return false;
+ default:
+ return true;
+ }
+}
+
static const struct regmap_config fsl_ssi_regconfig = {
.max_register = CCSR_SSI_SACCDIS,
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
+ .reg_defaults = fsl_ssi_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults),
+ .readable_reg = fsl_ssi_readable_reg,
+ .volatile_reg = fsl_ssi_volatile_reg,
+ .writeable_reg = fsl_ssi_writeable_reg,
+ .cache_type = REGCACHE_RBTREE,
};
struct fsl_ssi_soc_data {
@@ -176,6 +239,9 @@ struct fsl_ssi_private {
unsigned int baudclk_streams;
unsigned int bitclk_freq;
+ /*regcache for SFCSR*/
+ u32 regcache_sfcsr;
+
/* DMA params */
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -1514,10 +1580,46 @@ static int fsl_ssi_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int fsl_ssi_suspend(struct device *dev)
+{
+ struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
+ struct regmap *regs = ssi_private->regs;
+
+ regmap_read(regs, CCSR_SSI_SFCSR,
+ &ssi_private->regcache_sfcsr);
+
+ regcache_cache_only(regs, true);
+ regcache_mark_dirty(regs);
+
+ return 0;
+}
+
+static int fsl_ssi_resume(struct device *dev)
+{
+ struct fsl_ssi_private *ssi_private = dev_get_drvdata(dev);
+ struct regmap *regs = ssi_private->regs;
+
+ regcache_cache_only(regs, false);
+
+ regmap_update_bits(regs, CCSR_SSI_SFCSR,
+ CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK |
+ CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK,
+ ssi_private->regcache_sfcsr);
+
+ return regcache_sync(regs);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_ssi_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(fsl_ssi_suspend, fsl_ssi_resume)
+};
+
static struct platform_driver fsl_ssi_driver = {
.driver = {
.name = "fsl-ssi-dai",
.of_match_table = fsl_ssi_ids,
+ .pm = &fsl_ssi_pm,
},
.probe = fsl_ssi_probe,
.remove = fsl_ssi_remove,
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
index 33da26a12..a407e833c 100644
--- a/sound/soc/fsl/imx-spdif.c
+++ b/sound/soc/fsl/imx-spdif.c
@@ -89,6 +89,7 @@ MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
static struct platform_driver imx_spdif_driver = {
.driver = {
.name = "imx-spdif",
+ .pm = &snd_soc_pm_ops,
.of_match_table = imx_spdif_dt_ids,
},
.probe = imx_spdif_audio_probe,
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 9621b9140..6f236f170 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -12,11 +12,11 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/fsl/guts.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
-#include <asm/fsl_guts.h>
#include "fsl_dma.h"
#include "fsl_ssi.h"
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 71c1a7dc3..747aab060 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -11,12 +11,12 @@
*/
#include <linux/module.h>
+#include <linux/fsl/guts.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
-#include <asm/fsl_guts.h>
#include "fsl_dma.h"
#include "fsl_ssi.h"
diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c
index ee2904842..1dd49e5f9 100644
--- a/sound/soc/fsl/p1022_rdk.c
+++ b/sound/soc/fsl/p1022_rdk.c
@@ -18,12 +18,12 @@
*/
#include <linux/module.h>
+#include <linux/fsl/guts.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
-#include <asm/fsl_guts.h>
#include "fsl_dma.h"
#include "fsl_ssi.h"