summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/fsl_spdif.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/fsl/fsl_spdif.c')
-rw-r--r--sound/soc/fsl/fsl_spdif.c97
1 files changed, 89 insertions, 8 deletions
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index c631de325a6e..8ffb1a6048d6 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -49,6 +49,7 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
* @imx: for imx platform
* @shared_root_clock: flag of sharing a clock source with others;
* so the driver shouldn't set root clock rate
+ * @raw_capture_mode: if raw capture mode support
* @interrupts: interrupt number
* @tx_burst: tx maxburst size
* @rx_burst: rx maxburst size
@@ -57,6 +58,7 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
struct fsl_spdif_soc_data {
bool imx;
bool shared_root_clock;
+ bool raw_capture_mode;
u32 interrupts;
u32 tx_burst;
u32 rx_burst;
@@ -136,6 +138,7 @@ struct fsl_spdif_priv {
static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
.imx = false,
.shared_root_clock = false,
+ .raw_capture_mode = false,
.interrupts = 1,
.tx_burst = FSL_SPDIF_TXFIFO_WML,
.rx_burst = FSL_SPDIF_RXFIFO_WML,
@@ -145,6 +148,7 @@ static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
.imx = true,
.shared_root_clock = false,
+ .raw_capture_mode = false,
.interrupts = 1,
.tx_burst = FSL_SPDIF_TXFIFO_WML,
.rx_burst = FSL_SPDIF_RXFIFO_WML,
@@ -154,6 +158,7 @@ static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
.imx = true,
.shared_root_clock = true,
+ .raw_capture_mode = false,
.interrupts = 1,
.tx_burst = FSL_SPDIF_TXFIFO_WML,
.rx_burst = FSL_SPDIF_RXFIFO_WML,
@@ -164,12 +169,23 @@ static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
.imx = true,
.shared_root_clock = true,
+ .raw_capture_mode = false,
.interrupts = 2,
.tx_burst = 2, /* Applied for EDMA */
.rx_burst = 2, /* Applied for EDMA */
.tx_formats = SNDRV_PCM_FMTBIT_S24_LE, /* Applied for EDMA */
};
+static struct fsl_spdif_soc_data fsl_spdif_imx8mm = {
+ .imx = true,
+ .shared_root_clock = false,
+ .raw_capture_mode = true,
+ .interrupts = 1,
+ .tx_burst = FSL_SPDIF_TXFIFO_WML,
+ .rx_burst = FSL_SPDIF_RXFIFO_WML,
+ .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
+};
+
/* Check if clk is a root clock that does not share clock source with others */
static inline bool fsl_spdif_can_set_clk_rate(struct fsl_spdif_priv *spdif, int clk)
{
@@ -846,6 +862,39 @@ static int fsl_spdif_tx_vbit_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static int fsl_spdif_rx_rcm_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+ struct regmap *regmap = spdif_priv->regmap;
+ u32 val;
+
+ regmap_read(regmap, REG_SPDIF_SCR, &val);
+ val = (val & SCR_RAW_CAPTURE_MODE) ? 1 : 0;
+ ucontrol->value.integer.value[0] = val;
+
+ return 0;
+}
+
+static int fsl_spdif_rx_rcm_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+ struct regmap *regmap = spdif_priv->regmap;
+ u32 val = (ucontrol->value.integer.value[0] ? SCR_RAW_CAPTURE_MODE : 0);
+
+ if (val)
+ cpu_dai->driver->capture.formats |= SNDRV_PCM_FMTBIT_S32_LE;
+ else
+ cpu_dai->driver->capture.formats &= ~SNDRV_PCM_FMTBIT_S32_LE;
+
+ regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_RAW_CAPTURE_MODE, val);
+
+ return 0;
+}
+
/* DPLL lock information */
static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -1029,6 +1078,19 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
},
};
+static struct snd_kcontrol_new fsl_spdif_ctrls_rcm[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "IEC958 Raw Capture Mode",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_WRITE |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = snd_ctl_boolean_mono_info,
+ .get = fsl_spdif_rx_rcm_get,
+ .put = fsl_spdif_rx_rcm_put,
+ },
+};
+
static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai);
@@ -1038,6 +1100,10 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls));
+ if (spdif_private->soc->raw_capture_mode)
+ snd_soc_add_dai_controls(dai, fsl_spdif_ctrls_rcm,
+ ARRAY_SIZE(fsl_spdif_ctrls_rcm));
+
/*Clear the val bit for Tx*/
regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR,
SCR_VAL_MASK, SCR_VAL_CLEAR);
@@ -1289,8 +1355,7 @@ static int fsl_spdif_probe(struct platform_device *pdev)
spdif_priv->soc->tx_formats;
/* Get the addresses and IRQ */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- regs = devm_ioremap_resource(&pdev->dev, res);
+ regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(regs))
return PTR_ERR(regs);
@@ -1302,10 +1367,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
for (i = 0; i < spdif_priv->soc->interrupts; i++) {
irq = platform_get_irq(pdev, i);
- if (irq < 0) {
- dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+ if (irq < 0)
return irq;
- }
ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
dev_name(&pdev->dev), spdif_priv);
@@ -1375,22 +1438,38 @@ static int fsl_spdif_probe(struct platform_device *pdev)
&spdif_priv->cpu_dai_drv, 1);
if (ret) {
dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
- return ret;
+ goto err_pm_disable;
}
ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE);
- if (ret && ret != -EPROBE_DEFER)
- dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret, "imx_pcm_dma_init failed\n");
+ goto err_pm_disable;
+ }
+
+ return ret;
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
return ret;
}
+static int fsl_spdif_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
#ifdef CONFIG_PM
static int fsl_spdif_runtime_suspend(struct device *dev)
{
struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
int i;
+ /* Disable all the interrupts */
+ regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SIE, 0xffffff, 0);
+
regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC,
&spdif_priv->regcache_srpc);
regcache_cache_only(spdif_priv->regmap, true);
@@ -1476,6 +1555,7 @@ static const struct of_device_id fsl_spdif_dt_ids[] = {
{ .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, },
{ .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, },
{ .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, },
+ { .compatible = "fsl,imx8mm-spdif", .data = &fsl_spdif_imx8mm, },
{}
};
MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
@@ -1487,6 +1567,7 @@ static struct platform_driver fsl_spdif_driver = {
.pm = &fsl_spdif_pm,
},
.probe = fsl_spdif_probe,
+ .remove = fsl_spdif_remove,
};
module_platform_driver(fsl_spdif_driver);