summaryrefslogtreecommitdiff
path: root/sound/soc/fsl
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/Kconfig12
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c108
-rw-r--r--sound/soc/fsl/fsl_esai.c32
-rw-r--r--sound/soc/fsl/fsl_sai.c332
-rw-r--r--sound/soc/fsl/fsl_sai.h48
-rw-r--r--sound/soc/fsl/fsl_spdif.c9
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c7
-rw-r--r--sound/soc/fsl/wm1133-ev1.c11
8 files changed, 379 insertions, 180 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 07f8f141727d..597962ec28fa 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,5 +1,6 @@
config SND_SOC_FSL_SAI
tristate
+ select REGMAP_MMIO
select SND_SOC_GENERIC_DMAENGINE_PCM
config SND_SOC_FSL_SSI
@@ -7,9 +8,11 @@ config SND_SOC_FSL_SSI
config SND_SOC_FSL_SPDIF
tristate
+ select REGMAP_MMIO
config SND_SOC_FSL_ESAI
tristate
+ select REGMAP_MMIO
config SND_SOC_FSL_UTILS
tristate
@@ -168,12 +171,14 @@ config SND_SOC_EUKREA_TLV320
depends on MACH_EUKREA_MBIMX27_BASEBOARD \
|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
|| MACH_EUKREA_MBIMXSD35_BASEBOARD \
- || MACH_EUKREA_MBIMXSD51_BASEBOARD
+ || MACH_EUKREA_MBIMXSD51_BASEBOARD \
+ || (OF && ARM)
depends on I2C
- select SND_SOC_TLV320AIC23
- select SND_SOC_IMX_PCM_FIQ
+ select SND_SOC_TLV320AIC23_I2C
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_SSI
+ select SND_SOC_FSL_SSI
+ select SND_SOC_IMX_PCM_DMA
help
Enable I2S based access to the TLV320AIC23B codec attached
to the SSI interface
@@ -204,7 +209,6 @@ config SND_SOC_IMX_SPDIF
tristate "SoC Audio support for i.MX boards with S/PDIF"
select SND_SOC_IMX_PCM_DMA
select SND_SOC_FSL_SPDIF
- select REGMAP_MMIO
help
SoC Audio support for i.MX boards with S/PDIF
Say Y if you want to add support for SoC audio on an i.MX board with
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index 5983740be123..eb093d5b85c4 100644
--- a/sound/soc/fsl/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -15,8 +15,11 @@
*
*/
+#include <linux/errno.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <sound/core.h>
@@ -26,6 +29,7 @@
#include "../codecs/tlv320aic23.h"
#include "imx-ssi.h"
+#include "fsl_ssi.h"
#include "imx-audmux.h"
#define CODEC_CLOCK 12000000
@@ -41,7 +45,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
- if (ret) {
+ /* fsl_ssi lacks the set_fmt ops. */
+ if (ret && ret != -ENOTSUPP) {
dev_err(cpu_dai->dev,
"Failed to set the cpu dai format.\n");
return ret;
@@ -63,11 +68,13 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
"Failed to set the codec sysclk.\n");
return ret;
}
+
snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
SND_SOC_CLOCK_IN);
- if (ret) {
+ /* fsl_ssi lacks the set_sysclk ops */
+ if (ret && ret != -EINVAL) {
dev_err(cpu_dai->dev,
"Can't set the IMX_SSP_SYS_CLK CPU system clock.\n");
return ret;
@@ -84,14 +91,10 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = {
.name = "tlv320aic23",
.stream_name = "TLV320AIC23",
.codec_dai_name = "tlv320aic23-hifi",
- .platform_name = "imx-ssi.0",
- .codec_name = "tlv320aic23-codec.0-001a",
- .cpu_dai_name = "imx-ssi.0",
.ops = &eukrea_tlv320_snd_ops,
};
static struct snd_soc_card eukrea_tlv320 = {
- .name = "cpuimx-audio",
.owner = THIS_MODULE,
.dai_link = &eukrea_tlv320_dai,
.num_links = 1,
@@ -101,8 +104,65 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
{
int ret;
int int_port = 0, ext_port;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *ssi_np, *codec_np;
- if (machine_is_eukrea_cpuimx27()) {
+ eukrea_tlv320.dev = &pdev->dev;
+ if (np) {
+ ret = snd_soc_of_parse_card_name(&eukrea_tlv320,
+ "eukrea,model");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "eukrea,model node missing or invalid.\n");
+ goto err;
+ }
+
+ ssi_np = of_parse_phandle(pdev->dev.of_node,
+ "ssi-controller", 0);
+ if (!ssi_np) {
+ dev_err(&pdev->dev,
+ "ssi-controller missing or invalid.\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ codec_np = of_parse_phandle(ssi_np, "codec-handle", 0);
+ if (codec_np)
+ eukrea_tlv320_dai.codec_of_node = codec_np;
+ else
+ dev_err(&pdev->dev, "codec-handle node missing or invalid.\n");
+
+ ret = of_property_read_u32(np, "fsl,mux-int-port", &int_port);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "fsl,mux-int-port node missing or invalid.\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "fsl,mux-ext-port node missing or invalid.\n");
+ return ret;
+ }
+
+ /*
+ * The port numbering in the hardware manual starts at 1, while
+ * the audmux API expects it starts at 0.
+ */
+ int_port--;
+ ext_port--;
+
+ eukrea_tlv320_dai.cpu_of_node = ssi_np;
+ eukrea_tlv320_dai.platform_of_node = ssi_np;
+ } else {
+ eukrea_tlv320_dai.cpu_dai_name = "imx-ssi.0";
+ eukrea_tlv320_dai.platform_name = "imx-ssi.0";
+ eukrea_tlv320_dai.codec_name = "tlv320aic23-codec.0-001a";
+ eukrea_tlv320.name = "cpuimx-audio";
+ }
+
+ if (machine_is_eukrea_cpuimx27() ||
+ of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux")) {
imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
IMX_AUDMUX_V1_PCR_SYN |
IMX_AUDMUX_V1_PCR_TFSDIR |
@@ -119,8 +179,12 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
);
} else if (machine_is_eukrea_cpuimx25sd() ||
machine_is_eukrea_cpuimx35sd() ||
- machine_is_eukrea_cpuimx51sd()) {
- ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3;
+ machine_is_eukrea_cpuimx51sd() ||
+ of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux")) {
+ if (!np)
+ ext_port = machine_is_eukrea_cpuimx25sd() ?
+ 4 : 3;
+
imx_audmux_v2_configure_port(int_port,
IMX_AUDMUX_V2_PTCR_SYN |
IMX_AUDMUX_V2_PTCR_TFSDIR |
@@ -134,14 +198,27 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)
);
} else {
- /* return happy. We might run on a totally different machine */
- return 0;
+ if (np) {
+ /* The eukrea,asoc-tlv320 driver was explicitely
+ * requested (through the device tree).
+ */
+ dev_err(&pdev->dev,
+ "Missing or invalid audmux DT node.\n");
+ return -ENODEV;
+ } else {
+ /* Return happy.
+ * We might run on a totally different machine.
+ */
+ return 0;
+ }
}
- eukrea_tlv320.dev = &pdev->dev;
ret = snd_soc_register_card(&eukrea_tlv320);
+err:
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ if (np)
+ of_node_put(ssi_np);
return ret;
}
@@ -153,10 +230,17 @@ static int eukrea_tlv320_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id imx_tlv320_dt_ids[] = {
+ { .compatible = "eukrea,asoc-tlv320"},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_tlv320_dt_ids);
+
static struct platform_driver eukrea_tlv320_driver = {
.driver = {
.name = "eukrea_tlv320",
.owner = THIS_MODULE,
+ .of_match_table = imx_tlv320_dt_ids,
},
.probe = eukrea_tlv320_probe,
.remove = eukrea_tlv320_remove,
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index c84026c99134..0ba37005ab04 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -431,17 +431,26 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static int fsl_esai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ int ret;
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
/*
* Some platforms might use the same bit to gate all three or two of
* clocks, so keep all clocks open/close at the same time for safety
*/
- clk_prepare_enable(esai_priv->coreclk);
- if (!IS_ERR(esai_priv->extalclk))
- clk_prepare_enable(esai_priv->extalclk);
- if (!IS_ERR(esai_priv->fsysclk))
- clk_prepare_enable(esai_priv->fsysclk);
+ ret = clk_prepare_enable(esai_priv->coreclk);
+ if (ret)
+ return ret;
+ if (!IS_ERR(esai_priv->extalclk)) {
+ ret = clk_prepare_enable(esai_priv->extalclk);
+ if (ret)
+ goto err_extalck;
+ }
+ if (!IS_ERR(esai_priv->fsysclk)) {
+ ret = clk_prepare_enable(esai_priv->fsysclk);
+ if (ret)
+ goto err_fsysclk;
+ }
if (!dai->active) {
/* Reset Port C */
@@ -463,6 +472,14 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream,
}
return 0;
+
+err_fsysclk:
+ if (!IS_ERR(esai_priv->extalclk))
+ clk_disable_unprepare(esai_priv->extalclk);
+err_extalck:
+ clk_disable_unprepare(esai_priv->coreclk);
+
+ return ret;
}
static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
@@ -661,7 +678,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
}
}
-static const struct regmap_config fsl_esai_regmap_config = {
+static struct regmap_config fsl_esai_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
@@ -687,6 +704,9 @@ static int fsl_esai_probe(struct platform_device *pdev)
esai_priv->pdev = pdev;
strcpy(esai_priv->name, np->name);
+ if (of_property_read_bool(np, "big-endian"))
+ fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
+
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index cdd3fa830704..c4a423111673 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -15,6 +15,7 @@
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <linux/of_address.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/dmaengine_pcm.h>
@@ -22,34 +23,6 @@
#include "fsl_sai.h"
-static inline u32 sai_readl(struct fsl_sai *sai,
- const void __iomem *addr)
-{
- u32 val;
-
- val = __raw_readl(addr);
-
- if (likely(sai->big_endian_regs))
- val = be32_to_cpu(val);
- else
- val = le32_to_cpu(val);
- rmb();
-
- return val;
-}
-
-static inline void sai_writel(struct fsl_sai *sai,
- u32 val, void __iomem *addr)
-{
- wmb();
- if (likely(sai->big_endian_regs))
- val = cpu_to_be32(val);
- else
- val = cpu_to_le32(val);
-
- __raw_writel(val, addr);
-}
-
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int fsl_dir)
{
@@ -61,7 +34,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
else
reg_cr2 = FSL_SAI_RCR2;
- val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+ regmap_read(sai->regmap, reg_cr2, &val_cr2);
+
val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
switch (clk_id) {
@@ -81,7 +55,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- sai_writel(sai, val_cr2, sai->base + reg_cr2);
+ regmap_write(sai->regmap, reg_cr2, val_cr2);
return 0;
}
@@ -89,32 +63,22 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
- struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
if (dir == SND_SOC_CLOCK_IN)
return 0;
- ret = clk_prepare_enable(sai->clk);
- if (ret)
- return ret;
-
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
FSL_FMT_TRANSMITTER);
if (ret) {
dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
- goto err_clk;
+ return ret;
}
ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
FSL_FMT_RECEIVER);
- if (ret) {
+ if (ret)
dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
- goto err_clk;
- }
-
-err_clk:
- clk_disable_unprepare(sai->clk);
return ret;
}
@@ -133,43 +97,84 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
reg_cr4 = FSL_SAI_RCR4;
}
- val_cr2 = sai_readl(sai, sai->base + reg_cr2);
- val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+ regmap_read(sai->regmap, reg_cr2, &val_cr2);
+ regmap_read(sai->regmap, reg_cr4, &val_cr4);
if (sai->big_endian_data)
val_cr4 &= ~FSL_SAI_CR4_MF;
else
val_cr4 |= FSL_SAI_CR4_MF;
+ /* DAI mode */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
+ /*
+ * Frame low, 1clk before data, one word length for frame sync,
+ * frame sync starts one serial clock cycle earlier,
+ * that is, together with the last bit of the previous
+ * data word.
+ */
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /*
+ * Frame high, one word length for frame sync,
+ * frame sync asserts with the first bit of the frame.
+ */
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ /*
+ * Frame high, 1clk before data, one bit for frame sync,
+ * frame sync starts one serial clock cycle earlier,
+ * that is, together with the last bit of the previous
+ * data word.
+ */
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ val_cr4 &= ~FSL_SAI_CR4_FSP;
val_cr4 |= FSL_SAI_CR4_FSE;
+ sai->is_dsp_mode = true;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ /*
+ * Frame high, one bit for frame sync,
+ * frame sync asserts with the first bit of the frame.
+ */
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
+ sai->is_dsp_mode = true;
break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ /* To be done */
default:
return -EINVAL;
}
+ /* DAI clock inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_IF:
- val_cr4 |= FSL_SAI_CR4_FSP;
- val_cr2 &= ~FSL_SAI_CR2_BCP;
+ /* Invert both clocks */
+ val_cr2 ^= FSL_SAI_CR2_BCP;
+ val_cr4 ^= FSL_SAI_CR4_FSP;
break;
case SND_SOC_DAIFMT_IB_NF:
- val_cr4 &= ~FSL_SAI_CR4_FSP;
- val_cr2 &= ~FSL_SAI_CR2_BCP;
+ /* Invert bit clock */
+ val_cr2 ^= FSL_SAI_CR2_BCP;
break;
case SND_SOC_DAIFMT_NB_IF:
- val_cr4 |= FSL_SAI_CR4_FSP;
- val_cr2 |= FSL_SAI_CR2_BCP;
+ /* Invert frame clock */
+ val_cr4 ^= FSL_SAI_CR4_FSP;
break;
case SND_SOC_DAIFMT_NB_NF:
- val_cr4 &= ~FSL_SAI_CR4_FSP;
- val_cr2 |= FSL_SAI_CR2_BCP;
+ /* Nothing to do for both normal cases */
break;
default:
return -EINVAL;
}
+ /* DAI clock master masks */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
@@ -179,39 +184,37 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
+ val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
+ val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+ break;
default:
return -EINVAL;
}
- sai_writel(sai, val_cr2, sai->base + reg_cr2);
- sai_writel(sai, val_cr4, sai->base + reg_cr4);
+ regmap_write(sai->regmap, reg_cr2, val_cr2);
+ regmap_write(sai->regmap, reg_cr4, val_cr4);
return 0;
}
static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
- struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
int ret;
- ret = clk_prepare_enable(sai->clk);
- if (ret)
- return ret;
-
ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
if (ret) {
dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
- goto err_clk;
+ return ret;
}
ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
- if (ret) {
+ if (ret)
dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
- goto err_clk;
- }
-
-err_clk:
- clk_disable_unprepare(sai->clk);
return ret;
}
@@ -235,16 +238,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
reg_mr = FSL_SAI_RMR;
}
- val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+ regmap_read(sai->regmap, reg_cr4, &val_cr4);
+ regmap_read(sai->regmap, reg_cr4, &val_cr5);
+
val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
- val_cr5 = sai_readl(sai, sai->base + reg_cr5);
val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
- val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+ if (!sai->is_dsp_mode)
+ val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+
val_cr5 |= FSL_SAI_CR5_WNW(word_width);
val_cr5 |= FSL_SAI_CR5_W0W(word_width);
@@ -257,9 +263,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
val_mr = ~0UL - ((1 << channels) - 1);
- sai_writel(sai, val_cr4, sai->base + reg_cr4);
- sai_writel(sai, val_cr5, sai->base + reg_cr5);
- sai_writel(sai, val_mr, sai->base + reg_mr);
+ regmap_write(sai->regmap, reg_cr4, val_cr4);
+ regmap_write(sai->regmap, reg_cr5, val_cr5);
+ regmap_write(sai->regmap, reg_mr, val_mr);
return 0;
}
@@ -268,44 +274,42 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
- u32 tcsr, rcsr, val_cr2, val_cr3, reg_cr3;
-
- val_cr2 = sai_readl(sai, sai->base + FSL_SAI_TCR2);
- val_cr2 &= ~FSL_SAI_CR2_SYNC;
- sai_writel(sai, val_cr2, sai->base + FSL_SAI_TCR2);
+ u32 tcsr, rcsr;
- val_cr2 = sai_readl(sai, sai->base + FSL_SAI_RCR2);
- val_cr2 |= FSL_SAI_CR2_SYNC;
- sai_writel(sai, val_cr2, sai->base + FSL_SAI_RCR2);
+ /*
+ * The transmitter bit clock and frame sync are to be
+ * used by both the transmitter and receiver.
+ */
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
+ ~FSL_SAI_CR2_SYNC);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
+ FSL_SAI_CR2_SYNC);
- tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR);
- rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR);
+ regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr);
+ regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
tcsr |= FSL_SAI_CSR_FRDE;
rcsr &= ~FSL_SAI_CSR_FRDE;
- reg_cr3 = FSL_SAI_TCR3;
} else {
rcsr |= FSL_SAI_CSR_FRDE;
tcsr &= ~FSL_SAI_CSR_FRDE;
- reg_cr3 = FSL_SAI_RCR3;
}
- val_cr3 = sai_readl(sai, sai->base + reg_cr3);
-
+ /*
+ * It is recommended that the transmitter is the last enabled
+ * and the first disabled.
+ */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
tcsr |= FSL_SAI_CSR_TERE;
rcsr |= FSL_SAI_CSR_TERE;
- val_cr3 |= FSL_SAI_CR3_TRCE;
- sai_writel(sai, val_cr3, sai->base + reg_cr3);
- sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
- sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
+ regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
+ regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
break;
-
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -314,11 +318,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
rcsr &= ~FSL_SAI_CSR_TERE;
}
- val_cr3 &= ~FSL_SAI_CR3_TRCE;
-
- sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
- sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
- sai_writel(sai, val_cr3, sai->base + reg_cr3);
+ regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr);
+ regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr);
break;
default:
return -EINVAL;
@@ -331,16 +332,32 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 reg;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ reg = FSL_SAI_TCR3;
+ else
+ reg = FSL_SAI_RCR3;
+
+ regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
+ FSL_SAI_CR3_TRCE);
- return clk_prepare_enable(sai->clk);
+ return 0;
}
static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 reg;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ reg = FSL_SAI_TCR3;
+ else
+ reg = FSL_SAI_RCR3;
- clk_disable_unprepare(sai->clk);
+ regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE,
+ ~FSL_SAI_CR3_TRCE);
}
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
@@ -355,18 +372,13 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
- int ret;
- ret = clk_prepare_enable(sai->clk);
- if (ret)
- return ret;
-
- sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR);
- sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR);
- sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1);
- sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1);
-
- clk_disable_unprepare(sai->clk);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
+ FSL_SAI_MAXBURST_TX * 2);
+ regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
+ FSL_SAI_MAXBURST_RX - 1);
snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
&sai->dma_params_rx);
@@ -397,26 +409,109 @@ static const struct snd_soc_component_driver fsl_component = {
.name = "fsl-sai",
};
+static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FSL_SAI_TCSR:
+ case FSL_SAI_TCR1:
+ case FSL_SAI_TCR2:
+ case FSL_SAI_TCR3:
+ case FSL_SAI_TCR4:
+ case FSL_SAI_TCR5:
+ case FSL_SAI_TFR:
+ case FSL_SAI_TMR:
+ case FSL_SAI_RCSR:
+ case FSL_SAI_RCR1:
+ case FSL_SAI_RCR2:
+ case FSL_SAI_RCR3:
+ case FSL_SAI_RCR4:
+ case FSL_SAI_RCR5:
+ case FSL_SAI_RDR:
+ case FSL_SAI_RFR:
+ case FSL_SAI_RMR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FSL_SAI_TFR:
+ case FSL_SAI_RFR:
+ case FSL_SAI_TDR:
+ case FSL_SAI_RDR:
+ return true;
+ default:
+ return false;
+ }
+
+}
+
+static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FSL_SAI_TCSR:
+ case FSL_SAI_TCR1:
+ case FSL_SAI_TCR2:
+ case FSL_SAI_TCR3:
+ case FSL_SAI_TCR4:
+ case FSL_SAI_TCR5:
+ case FSL_SAI_TDR:
+ case FSL_SAI_TMR:
+ case FSL_SAI_RCSR:
+ case FSL_SAI_RCR1:
+ case FSL_SAI_RCR2:
+ case FSL_SAI_RCR3:
+ case FSL_SAI_RCR4:
+ case FSL_SAI_RCR5:
+ case FSL_SAI_RMR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct regmap_config fsl_sai_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .max_register = FSL_SAI_RMR,
+ .readable_reg = fsl_sai_readable_reg,
+ .volatile_reg = fsl_sai_volatile_reg,
+ .writeable_reg = fsl_sai_writeable_reg,
+};
+
static int fsl_sai_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct fsl_sai *sai;
struct resource *res;
+ void __iomem *base;
int ret;
sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
if (!sai)
return -ENOMEM;
+ sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
+ if (sai->big_endian_regs)
+ fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
+
+ sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- sai->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(sai->base))
- return PTR_ERR(sai->base);
-
- sai->clk = devm_clk_get(&pdev->dev, "sai");
- if (IS_ERR(sai->clk)) {
- dev_err(&pdev->dev, "Cannot get SAI's clock\n");
- return PTR_ERR(sai->clk);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+ "sai", base, &fsl_sai_regmap_config);
+ if (IS_ERR(sai->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ return PTR_ERR(sai->regmap);
}
sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
@@ -424,9 +519,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
- sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
- sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
-
platform_set_drvdata(pdev, sai);
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 41bb62e69361..e432260be598 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -15,31 +15,36 @@
SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+/* SAI Register Map Register */
+#define FSL_SAI_TCSR 0x00 /* SAI Transmit Control */
+#define FSL_SAI_TCR1 0x04 /* SAI Transmit Configuration 1 */
+#define FSL_SAI_TCR2 0x08 /* SAI Transmit Configuration 2 */
+#define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */
+#define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */
+#define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */
+#define FSL_SAI_TDR 0x20 /* SAI Transmit Data */
+#define FSL_SAI_TFR 0x40 /* SAI Transmit FIFO */
+#define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */
+#define FSL_SAI_RCSR 0x80 /* SAI Receive Control */
+#define FSL_SAI_RCR1 0x84 /* SAI Receive Configuration 1 */
+#define FSL_SAI_RCR2 0x88 /* SAI Receive Configuration 2 */
+#define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */
+#define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */
+#define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */
+#define FSL_SAI_RDR 0xa0 /* SAI Receive Data */
+#define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */
+#define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */
+
/* SAI Transmit/Recieve Control Register */
-#define FSL_SAI_TCSR 0x00
-#define FSL_SAI_RCSR 0x80
#define FSL_SAI_CSR_TERE BIT(31)
#define FSL_SAI_CSR_FWF BIT(17)
#define FSL_SAI_CSR_FRIE BIT(8)
#define FSL_SAI_CSR_FRDE BIT(0)
-/* SAI Transmit Data/FIFO/MASK Register */
-#define FSL_SAI_TDR 0x20
-#define FSL_SAI_TFR 0x40
-#define FSL_SAI_TMR 0x60
-
-/* SAI Recieve Data/FIFO/MASK Register */
-#define FSL_SAI_RDR 0xa0
-#define FSL_SAI_RFR 0xc0
-#define FSL_SAI_RMR 0xe0
-
/* SAI Transmit and Recieve Configuration 1 Register */
-#define FSL_SAI_TCR1 0x04
-#define FSL_SAI_RCR1 0x84
+#define FSL_SAI_CR1_RFW_MASK 0x1f
/* SAI Transmit and Recieve Configuration 2 Register */
-#define FSL_SAI_TCR2 0x08
-#define FSL_SAI_RCR2 0x88
#define FSL_SAI_CR2_SYNC BIT(30)
#define FSL_SAI_CR2_MSEL_MASK (0xff << 26)
#define FSL_SAI_CR2_MSEL_BUS 0
@@ -50,15 +55,11 @@
#define FSL_SAI_CR2_BCD_MSTR BIT(24)
/* SAI Transmit and Recieve Configuration 3 Register */
-#define FSL_SAI_TCR3 0x0c
-#define FSL_SAI_RCR3 0x8c
#define FSL_SAI_CR3_TRCE BIT(16)
#define FSL_SAI_CR3_WDFL(x) (x)
#define FSL_SAI_CR3_WDFL_MASK 0x1f
/* SAI Transmit and Recieve Configuration 4 Register */
-#define FSL_SAI_TCR4 0x10
-#define FSL_SAI_RCR4 0x90
#define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16)
#define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16)
#define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8)
@@ -69,8 +70,6 @@
#define FSL_SAI_CR4_FSD_MSTR BIT(0)
/* SAI Transmit and Recieve Configuration 5 Register */
-#define FSL_SAI_TCR5 0x14
-#define FSL_SAI_RCR5 0x94
#define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24)
#define FSL_SAI_CR5_WNW_MASK (0x1f << 24)
#define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16)
@@ -100,12 +99,11 @@
#define FSL_SAI_MAXBURST_RX 6
struct fsl_sai {
- struct clk *clk;
-
- void __iomem *base;
+ struct regmap *regmap;
bool big_endian_regs;
bool big_endian_data;
+ bool is_dsp_mode;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 4d075f1abe78..6452ca83d889 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -911,8 +911,8 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai);
- dai->playback_dma_data = &spdif_private->dma_params_tx;
- dai->capture_dma_data = &spdif_private->dma_params_rx;
+ snd_soc_dai_init_dma_data(dai, &spdif_private->dma_params_tx,
+ &spdif_private->dma_params_rx);
snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls));
@@ -985,7 +985,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
}
}
-static const struct regmap_config fsl_spdif_regmap_config = {
+static struct regmap_config fsl_spdif_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
@@ -1105,6 +1105,9 @@ static int fsl_spdif_probe(struct platform_device *pdev)
memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
spdif_priv->cpu_dai_drv.name = spdif_priv->name;
+ if (of_property_read_bool(np, "big-endian"))
+ fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
+
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 6553202dd48c..7abf6a079574 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -270,18 +270,17 @@ static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
- goto out;
+ return ret;
}
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
- goto out;
+ return ret;
}
-out:
- return ret;
+ return 0;
}
static int ssi_irq = 0;
diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
index fce63252bdbb..804749a6c61e 100644
--- a/sound/soc/fsl/wm1133-ev1.c
+++ b/sound/soc/fsl/wm1133-ev1.c
@@ -214,12 +214,6 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- snd_soc_dapm_new_controls(dapm, wm1133_ev1_widgets,
- ARRAY_SIZE(wm1133_ev1_widgets));
-
- snd_soc_dapm_add_routes(dapm, wm1133_ev1_map,
- ARRAY_SIZE(wm1133_ev1_map));
-
/* Headphone jack detection */
snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
@@ -257,6 +251,11 @@ static struct snd_soc_card wm1133_ev1 = {
.owner = THIS_MODULE,
.dai_link = &wm1133_ev1_dai,
.num_links = 1,
+
+ .dapm_widgets = wm1133_ev1_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm1133_ev1_widgets),
+ .dapm_routes = wm1133_ev1_map,
+ .num_dapm_routes = ARRAY_SIZE(wm1133_ev1_map),
};
static struct platform_device *wm1133_ev1_snd_device;