summaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2020-12-11 17:48:04 +0000
committerMark Brown <broonie@kernel.org>2020-12-11 17:48:04 +0000
commit460aa020f56c974a3e7e5b5378b2355fec6a2c11 (patch)
tree959dc05609eec2a040245f43964ae5738ee741cb /sound/soc/fsl
parent031616c434db05ce766f76c62865f55698e0924f (diff)
parent84de089e770b57280d87dff51be894b6fda18810 (diff)
downloadlinux-460aa020f56c974a3e7e5b5378b2355fec6a2c11.tar.bz2
Merge remote-tracking branch 'asoc/for-5.11' into asoc-next
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/Kconfig77
-rw-r--r--sound/soc/fsl/Makefile16
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c13
-rw-r--r--sound/soc/fsl/fsl_aud2htx.c308
-rw-r--r--sound/soc/fsl/fsl_aud2htx.h67
-rw-r--r--sound/soc/fsl/fsl_audmix.c13
-rw-r--r--sound/soc/fsl/fsl_sai.c20
-rw-r--r--sound/soc/fsl/fsl_sai.h1
-rw-r--r--sound/soc/fsl/fsl_spdif.c73
-rw-r--r--sound/soc/fsl/fsl_spdif.h9
-rw-r--r--sound/soc/fsl/fsl_xcvr.c1360
-rw-r--r--sound/soc/fsl/fsl_xcvr.h266
-rw-r--r--sound/soc/fsl/imx-audmux.c28
-rw-r--r--sound/soc/fsl/imx-hdmi.c236
-rw-r--r--sound/soc/fsl/imx-mc13783.c156
-rw-r--r--sound/soc/fsl/imx-ssi.c651
-rw-r--r--sound/soc/fsl/mx27vis-aic32x4.c214
-rw-r--r--sound/soc/fsl/phycore-ac97.c121
-rw-r--r--sound/soc/fsl/wm1133-ev1.c289
19 files changed, 2378 insertions, 1540 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3f76ff71ea47..84db0b7b9d59 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -95,6 +95,22 @@ config SND_SOC_FSL_EASRC
destination sample rate. It is a new design module compare with the
old ASRC.
+config SND_SOC_FSL_XCVR
+ tristate "NXP Audio Transceiver (XCVR) module support"
+ select REGMAP_MMIO
+ select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y if you want to add Audio Transceiver (XCVR) support for NXP
+ iMX CPUs. XCVR is a digital module that supports HDMI2.1 eARC,
+ HDMI1.4 ARC and SPDIF.
+
+config SND_SOC_FSL_AUD2HTX
+ tristate "AUDIO TO HDMI TX module support"
+ depends on ARCH_MXC || COMPILE_TEST
+ help
+ Say Y if you want to add AUDIO TO HDMI TX support for NXP.
+
config SND_SOC_FSL_UTILS
tristate
@@ -213,57 +229,18 @@ endif # SND_POWERPC_SOC
config SND_SOC_IMX_PCM_FIQ
tristate
- default y if SND_SOC_IMX_SSI=y && (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC)
+ default y if (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC)
select FIQ
if SND_IMX_SOC
-config SND_SOC_IMX_SSI
- tristate
- select SND_SOC_FSL_UTILS
-
comment "SoC Audio support for Freescale i.MX boards:"
-config SND_MXC_SOC_WM1133_EV1
- tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted"
- depends on MACH_MX31ADS_WM1133_EV1
- select SND_SOC_WM8350
- select SND_SOC_IMX_PCM_FIQ
- select SND_SOC_IMX_AUDMUX
- select SND_SOC_IMX_SSI
- help
- Enable support for audio on the i.MX31ADS with the WM1133-EV1
- PMIC board with WM8835x fitted.
-
-config SND_SOC_MX27VIS_AIC32X4
- tristate "SoC audio support for Visstrim M10 boards"
- depends on MACH_IMX27_VISSTRIM_M10 && I2C
- select SND_SOC_TLV320AIC32X4
- select SND_SOC_IMX_PCM_DMA
- select SND_SOC_IMX_AUDMUX
- select SND_SOC_IMX_SSI
- help
- Say Y if you want to add support for SoC audio on Visstrim SM10
- board with TLV320AIC32X4 codec.
-
-config SND_SOC_PHYCORE_AC97
- tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
- depends on MACH_PCM043 || MACH_PCA100
- select SND_SOC_AC97_BUS
- select SND_SOC_WM9712
- select SND_SOC_IMX_PCM_FIQ
- select SND_SOC_IMX_AUDMUX
- select SND_SOC_IMX_SSI
- help
- Say Y if you want to add support for SoC audio on Phytec phyCORE
- and phyCARD boards in AC97 mode
-
config SND_SOC_EUKREA_TLV320
tristate "Eukrea TLV320"
depends on ARCH_MXC && !ARM64 && I2C
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
@@ -302,14 +279,6 @@ config SND_SOC_IMX_SPDIF
Say Y if you want to add support for SoC audio on an i.MX board with
a S/DPDIF.
-config SND_SOC_IMX_MC13783
- tristate "SoC Audio support for I.MX boards with mc13783"
- depends on MFD_MC13XXX && ARM
- select SND_SOC_IMX_SSI
- select SND_SOC_IMX_AUDMUX
- select SND_SOC_MC13783
- select SND_SOC_IMX_PCM_DMA
-
config SND_SOC_FSL_ASOC_CARD
tristate "Generic ASoC Sound Card with ASRC support"
depends on OF && I2C
@@ -336,6 +305,18 @@ config SND_SOC_IMX_AUDMIX
Say Y if you want to add support for SoC audio on an i.MX board with
an Audio Mixer.
+config SND_SOC_IMX_HDMI
+ tristate "SoC Audio support for i.MX boards with HDMI port"
+ select SND_SOC_FSL_SAI
+ select SND_SOC_FSL_AUD2HTX
+ select SND_SOC_HDMI_CODEC
+ help
+ ALSA SoC Audio support with HDMI feature for Freescale SoCs that have
+ SAI/AUD2HTX and connect with internal HDMI IP or external module
+ SII902X.
+ Say Y if you want to add support for SoC audio on an i.MX board with
+ IMX HDMI.
+
endif # SND_IMX_SOC
endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b835eebf8825..8c5fa8a859c0 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -25,6 +25,8 @@ snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
snd-soc-fsl-mqs-objs := fsl_mqs.o
snd-soc-fsl-easrc-objs := fsl_easrc.o
+snd-soc-fsl-xcvr-objs := fsl_xcvr.o
+snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o
obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -38,6 +40,8 @@ obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o
obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o
obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o
+obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o
# MPC5200 Platform Support
obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
@@ -49,9 +53,7 @@ obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
# i.MX Platform Support
-snd-soc-imx-ssi-objs := imx-ssi.o
snd-soc-imx-audmux-objs := imx-audmux.o
-obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
@@ -59,21 +61,15 @@ obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
# i.MX Machine Support
snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
-snd-soc-phycore-ac97-objs := phycore-ac97.o
-snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
-snd-soc-wm1133-ev1-objs := wm1133-ev1.o
snd-soc-imx-es8328-objs := imx-es8328.o
snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
snd-soc-imx-spdif-objs := imx-spdif.o
-snd-soc-imx-mc13783-objs := imx-mc13783.o
snd-soc-imx-audmix-objs := imx-audmix.o
+snd-soc-imx-hdmi-objs := imx-hdmi.o
obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
-obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
-obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
-obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
-obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o
+obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index a2dd3b6b7fec..f62f81ceab0d 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -131,6 +131,13 @@ static const struct snd_soc_dapm_route audio_map_tx[] = {
{"CPU-Playback", NULL, "ASRC-Playback"},
};
+static const struct snd_soc_dapm_route audio_map_rx[] = {
+ /* 1st half -- Normal DAPM routes */
+ {"CPU-Capture", NULL, "Capture"},
+ /* 2nd half -- ASRC DAPM routes */
+ {"ASRC-Capture", NULL, "CPU-Capture"},
+};
+
/* Add all possible widgets into here without being redundant */
static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Line Out Jack", NULL),
@@ -653,6 +660,11 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->cpu_priv.slot_width = 32;
priv->card.dapm_routes = audio_map_tx;
priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
+ } else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) {
+ codec_dai_name = "si476x-codec";
+ priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+ priv->card.dapm_routes = audio_map_rx;
+ priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
} else {
dev_err(&pdev->dev, "unknown Device Tree compatible\n");
ret = -EINVAL;
@@ -869,6 +881,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = {
{ .compatible = "fsl,imx-audio-wm8960", },
{ .compatible = "fsl,imx-audio-mqs", },
{ .compatible = "fsl,imx-audio-wm8524", },
+ { .compatible = "fsl,imx-audio-si476x", },
{}
};
MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c
new file mode 100644
index 000000000000..d70d5e75a30c
--- /dev/null
+++ b/sound/soc/fsl/fsl_aud2htx.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2020 NXP
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/pm_qos.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/dma-mapping.h>
+
+#include "fsl_aud2htx.h"
+#include "imx-pcm.h"
+
+static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_aud2htx *aud2htx = snd_soc_dai_get_drvdata(dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
+ AUD2HTX_CTRL_EN, AUD2HTX_CTRL_EN);
+ regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+ AUD2HTX_CTRE_DE, AUD2HTX_CTRE_DE);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+ AUD2HTX_CTRE_DE, 0);
+ regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL,
+ AUD2HTX_CTRL_EN, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
+ .trigger = fsl_aud2htx_trigger,
+};
+
+static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev);
+
+ /* DMA request when number of entries < WTMK_LOW */
+ regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+ AUD2HTX_CTRE_DT_MASK, 0);
+
+ /* Disable interrupts*/
+ regmap_update_bits(aud2htx->regmap, AUD2HTX_IRQ_MASK,
+ AUD2HTX_WM_HIGH_IRQ_MASK |
+ AUD2HTX_WM_LOW_IRQ_MASK |
+ AUD2HTX_OVF_MASK,
+ AUD2HTX_WM_HIGH_IRQ_MASK |
+ AUD2HTX_WM_LOW_IRQ_MASK |
+ AUD2HTX_OVF_MASK);
+
+ /* Configure watermark */
+ regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+ AUD2HTX_CTRE_WL_MASK,
+ AUD2HTX_WTMK_LOW << AUD2HTX_CTRE_WL_SHIFT);
+ regmap_update_bits(aud2htx->regmap, AUD2HTX_CTRL_EXT,
+ AUD2HTX_CTRE_WH_MASK,
+ AUD2HTX_WTMK_HIGH << AUD2HTX_CTRE_WH_SHIFT);
+
+ snd_soc_dai_init_dma_data(cpu_dai, &aud2htx->dma_params_tx,
+ &aud2htx->dma_params_rx);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver fsl_aud2htx_dai = {
+ .probe = fsl_aud2htx_dai_probe,
+ .playback = {
+ .stream_name = "CPU-Playback",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .formats = FSL_AUD2HTX_FORMATS,
+ },
+ .ops = &fsl_aud2htx_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_aud2htx_component = {
+ .name = "fsl-aud2htx",
+};
+
+static const struct reg_default fsl_aud2htx_reg_defaults[] = {
+ {AUD2HTX_CTRL, 0x00000000},
+ {AUD2HTX_CTRL_EXT, 0x00000000},
+ {AUD2HTX_WR, 0x00000000},
+ {AUD2HTX_STATUS, 0x00000000},
+ {AUD2HTX_IRQ_NOMASK, 0x00000000},
+ {AUD2HTX_IRQ_MASKED, 0x00000000},
+ {AUD2HTX_IRQ_MASK, 0x00000000},
+};
+
+static bool fsl_aud2htx_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AUD2HTX_CTRL:
+ case AUD2HTX_CTRL_EXT:
+ case AUD2HTX_STATUS:
+ case AUD2HTX_IRQ_NOMASK:
+ case AUD2HTX_IRQ_MASKED:
+ case AUD2HTX_IRQ_MASK:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fsl_aud2htx_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AUD2HTX_CTRL:
+ case AUD2HTX_CTRL_EXT:
+ case AUD2HTX_WR:
+ case AUD2HTX_IRQ_NOMASK:
+ case AUD2HTX_IRQ_MASKED:
+ case AUD2HTX_IRQ_MASK:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fsl_aud2htx_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AUD2HTX_STATUS:
+ case AUD2HTX_IRQ_NOMASK:
+ case AUD2HTX_IRQ_MASKED:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config fsl_aud2htx_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .max_register = AUD2HTX_IRQ_MASK,
+ .reg_defaults = fsl_aud2htx_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_aud2htx_reg_defaults),
+ .readable_reg = fsl_aud2htx_readable_reg,
+ .volatile_reg = fsl_aud2htx_volatile_reg,
+ .writeable_reg = fsl_aud2htx_writeable_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct of_device_id fsl_aud2htx_dt_ids[] = {
+ { .compatible = "fsl,imx8mp-aud2htx",},
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_aud2htx_dt_ids);
+
+static irqreturn_t fsl_aud2htx_isr(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+static int fsl_aud2htx_probe(struct platform_device *pdev)
+{
+ struct fsl_aud2htx *aud2htx;
+ struct resource *res;
+ void __iomem *regs;
+ int ret, irq;
+
+ aud2htx = devm_kzalloc(&pdev->dev, sizeof(*aud2htx), GFP_KERNEL);
+ if (!aud2htx)
+ return -ENOMEM;
+
+ aud2htx->pdev = pdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(regs)) {
+ dev_err(&pdev->dev, "failed ioremap\n");
+ return PTR_ERR(regs);
+ }
+
+ aud2htx->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ &fsl_aud2htx_regmap_config);
+ if (IS_ERR(aud2htx->regmap)) {
+ dev_err(&pdev->dev, "failed to init regmap");
+ return PTR_ERR(aud2htx->regmap);
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, fsl_aud2htx_isr, 0,
+ dev_name(&pdev->dev), aud2htx);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret);
+ return ret;
+ }
+
+ aud2htx->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(aud2htx->bus_clk)) {
+ dev_err(&pdev->dev, "failed to get mem clock\n");
+ return PTR_ERR(aud2htx->bus_clk);
+ }
+
+ aud2htx->dma_params_tx.chan_name = "tx";
+ aud2htx->dma_params_tx.maxburst = AUD2HTX_MAXBURST;
+ aud2htx->dma_params_tx.addr = res->start + AUD2HTX_WR;
+
+ platform_set_drvdata(pdev, aud2htx);
+ pm_runtime_enable(&pdev->dev);
+
+ regcache_cache_only(aud2htx->regmap, true);
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &fsl_aud2htx_component,
+ &fsl_aud2htx_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register ASoC DAI\n");
+ return ret;
+ }
+
+ ret = imx_pcm_dma_init(pdev, IMX_DEFAULT_DMABUF_SIZE);
+ if (ret)
+ dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
+
+ return ret;
+}
+
+static int fsl_aud2htx_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int __maybe_unused fsl_aud2htx_runtime_suspend(struct device *dev)
+{
+ struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
+
+ regcache_cache_only(aud2htx->regmap, true);
+ clk_disable_unprepare(aud2htx->bus_clk);
+
+ return 0;
+}
+
+static int __maybe_unused fsl_aud2htx_runtime_resume(struct device *dev)
+{
+ struct fsl_aud2htx *aud2htx = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(aud2htx->bus_clk);
+ if (ret)
+ return ret;
+
+ regcache_cache_only(aud2htx->regmap, false);
+ regcache_mark_dirty(aud2htx->regmap);
+ regcache_sync(aud2htx->regmap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops fsl_aud2htx_pm_ops = {
+ SET_RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend,
+ fsl_aud2htx_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_aud2htx_driver = {
+ .probe = fsl_aud2htx_probe,
+ .remove = fsl_aud2htx_remove,
+ .driver = {
+ .name = "fsl-aud2htx",
+ .pm = &fsl_aud2htx_pm_ops,
+ .of_match_table = fsl_aud2htx_dt_ids,
+ },
+};
+module_platform_driver(fsl_aud2htx_driver);
+
+MODULE_AUTHOR("Shengjiu Wang <Shengjiu.Wang@nxp.com>");
+MODULE_DESCRIPTION("NXP AUD2HTX driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_aud2htx.h b/sound/soc/fsl/fsl_aud2htx.h
new file mode 100644
index 000000000000..ad70d6a7694c
--- /dev/null
+++ b/sound/soc/fsl/fsl_aud2htx.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2020 NXP
+ */
+
+#ifndef _FSL_AUD2HTX_H
+#define _FSL_AUD2HTX_H
+
+#define FSL_AUD2HTX_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+/* AUD2HTX Register Map */
+#define AUD2HTX_CTRL 0x0 /* AUD2HTX Control Register */
+#define AUD2HTX_CTRL_EXT 0x4 /* AUD2HTX Control Extended Register */
+#define AUD2HTX_WR 0x8 /* AUD2HTX Write Register */
+#define AUD2HTX_STATUS 0xC /* AUD2HTX Status Register */
+#define AUD2HTX_IRQ_NOMASK 0x10 /* AUD2HTX Nonmasked Interrupt Flags Register */
+#define AUD2HTX_IRQ_MASKED 0x14 /* AUD2HTX Masked Interrupt Flags Register */
+#define AUD2HTX_IRQ_MASK 0x18 /* AUD2HTX IRQ Masks Register */
+
+/* AUD2HTX Control Register */
+#define AUD2HTX_CTRL_EN BIT(0)
+
+/* AUD2HTX Control Extended Register */
+#define AUD2HTX_CTRE_DE BIT(0)
+#define AUD2HTX_CTRE_DT_SHIFT 0x1
+#define AUD2HTX_CTRE_DT_WIDTH 0x2
+#define AUD2HTX_CTRE_DT_MASK ((BIT(AUD2HTX_CTRE_DT_WIDTH) - 1) \
+ << AUD2HTX_CTRE_DT_SHIFT)
+#define AUD2HTX_CTRE_WL_SHIFT 16
+#define AUD2HTX_CTRE_WL_WIDTH 5
+#define AUD2HTX_CTRE_WL_MASK ((BIT(AUD2HTX_CTRE_WL_WIDTH) - 1) \
+ << AUD2HTX_CTRE_WL_SHIFT)
+#define AUD2HTX_CTRE_WH_SHIFT 24
+#define AUD2HTX_CTRE_WH_WIDTH 5
+#define AUD2HTX_CTRE_WH_MASK ((BIT(AUD2HTX_CTRE_WH_WIDTH) - 1) \
+ << AUD2HTX_CTRE_WH_SHIFT)
+
+/* AUD2HTX IRQ Masks Register */
+#define AUD2HTX_WM_HIGH_IRQ_MASK BIT(2)
+#define AUD2HTX_WM_LOW_IRQ_MASK BIT(1)
+#define AUD2HTX_OVF_MASK BIT(0)
+
+#define AUD2HTX_FIFO_DEPTH 0x20
+#define AUD2HTX_WTMK_LOW 0x10
+#define AUD2HTX_WTMK_HIGH 0x10
+#define AUD2HTX_MAXBURST 0x10
+
+/**
+ * fsl_aud2htx: AUD2HTX private data
+ *
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @bus_clk: clock source to access register
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ */
+struct fsl_aud2htx {
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ struct clk *bus_clk;
+
+ struct snd_dmaengine_dai_dma_data dma_params_rx;
+ struct snd_dmaengine_dai_dma_data dma_params_tx;
+};
+
+#endif /* _FSL_AUD2HTX_H */
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index 7ad5925772e8..8dc44dec7956 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -455,7 +455,6 @@ static const struct regmap_config fsl_audmix_regmap_config = {
static const struct of_device_id fsl_audmix_ids[] = {
{
.compatible = "fsl,imx8qm-audmix",
- .data = "imx-audmix",
},
{ /* sentinel */ }
};
@@ -465,17 +464,9 @@ static int fsl_audmix_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fsl_audmix *priv;
- const char *mdrv;
- const struct of_device_id *of_id;
void __iomem *regs;
int ret;
- of_id = of_match_device(fsl_audmix_ids, dev);
- if (!of_id || !of_id->data)
- return -EINVAL;
-
- mdrv = of_id->data;
-
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -510,10 +501,10 @@ static int fsl_audmix_probe(struct platform_device *pdev)
goto err_disable_pm;
}
- priv->pdev = platform_device_register_data(dev, mdrv, 0, NULL, 0);
+ priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0);
if (IS_ERR(priv->pdev)) {
ret = PTR_ERR(priv->pdev);
- dev_err(dev, "failed to register platform %s: %d\n", mdrv, ret);
+ dev_err(dev, "failed to register platform: %d\n", ret);
goto err_disable_pm;
}
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 3e5c1eaccd5e..f3d3d20d35d7 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -359,7 +359,14 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
if (sai->is_slave_mode)
return 0;
- for (id = 0; id < FSL_SAI_MCLK_MAX; id++) {
+ /*
+ * There is no point in polling MCLK0 if it is identical to MCLK1.
+ * And given that MQS use case has to use MCLK1 though two clocks
+ * are the same, we simply skip MCLK0 and start to find from MCLK1.
+ */
+ id = sai->soc_data->mclk0_is_mclk1 ? 1 : 0;
+
+ for (; id < FSL_SAI_MCLK_MAX; id++) {
clk_rate = clk_get_rate(sai->mclk_clk[id]);
if (!clk_rate)
continue;
@@ -1040,7 +1047,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
sai->bus_clk = NULL;
}
- sai->mclk_clk[0] = sai->bus_clk;
for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
sprintf(tmp, "mclk%d", i);
sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
@@ -1051,6 +1057,11 @@ static int fsl_sai_probe(struct platform_device *pdev)
}
}
+ if (sai->soc_data->mclk0_is_mclk1)
+ sai->mclk_clk[0] = sai->mclk_clk[1];
+ else
+ sai->mclk_clk[0] = sai->bus_clk;
+
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -1165,6 +1176,7 @@ static const struct fsl_sai_soc_data fsl_sai_vf610_data = {
.use_edma = false,
.fifo_depth = 32,
.reg_offset = 0,
+ .mclk0_is_mclk1 = false,
};
static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
@@ -1172,6 +1184,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = {
.use_edma = false,
.fifo_depth = 32,
.reg_offset = 0,
+ .mclk0_is_mclk1 = true,
};
static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
@@ -1179,6 +1192,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = {
.use_edma = false,
.fifo_depth = 16,
.reg_offset = 8,
+ .mclk0_is_mclk1 = false,
};
static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
@@ -1186,6 +1200,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = {
.use_edma = false,
.fifo_depth = 128,
.reg_offset = 8,
+ .mclk0_is_mclk1 = false,
};
static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
@@ -1193,6 +1208,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = {
.use_edma = true,
.fifo_depth = 64,
.reg_offset = 0,
+ .mclk0_is_mclk1 = false,
};
static const struct of_device_id fsl_sai_ids[] = {
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 4bbcd0dbe8f1..ff2619f1b214 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -219,6 +219,7 @@
struct fsl_sai_soc_data {
bool use_imx_pcm;
bool use_edma;
+ bool mclk0_is_mclk1;
unsigned int fifo_depth;
unsigned int reg_offset;
};
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index b0f643fefe1e..5fa178f3f497 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -49,10 +49,18 @@ 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
+ * @interrupts: interrupt number
+ * @tx_burst: tx maxburst size
+ * @rx_burst: rx maxburst size
+ * @tx_formats: tx supported data format
*/
struct fsl_spdif_soc_data {
bool imx;
bool shared_root_clock;
+ u32 interrupts;
+ u32 tx_burst;
+ u32 rx_burst;
+ u64 tx_formats;
};
/*
@@ -128,16 +136,38 @@ struct fsl_spdif_priv {
static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
.imx = false,
.shared_root_clock = false,
+ .interrupts = 1,
+ .tx_burst = FSL_SPDIF_TXFIFO_WML,
+ .rx_burst = FSL_SPDIF_RXFIFO_WML,
+ .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
};
static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
.imx = true,
.shared_root_clock = false,
+ .interrupts = 1,
+ .tx_burst = FSL_SPDIF_TXFIFO_WML,
+ .rx_burst = FSL_SPDIF_RXFIFO_WML,
+ .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
};
static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
.imx = true,
.shared_root_clock = true,
+ .interrupts = 1,
+ .tx_burst = FSL_SPDIF_TXFIFO_WML,
+ .rx_burst = FSL_SPDIF_RXFIFO_WML,
+ .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
+
+};
+
+static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
+ .imx = true,
+ .shared_root_clock = true,
+ .interrupts = 2,
+ .tx_burst = 2, /* Applied for EDMA */
+ .rx_burst = 2, /* Applied for EDMA */
+ .tx_formats = SNDRV_PCM_FMTBIT_S24_LE, /* Applied for EDMA */
};
/* Check if clk is a root clock that does not share clock source with others */
@@ -429,10 +459,18 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
rate = SPDIF_TXRATE_48000;
csfs = IEC958_AES3_CON_FS_48000;
break;
+ case 88200:
+ rate = SPDIF_TXRATE_88200;
+ csfs = IEC958_AES3_CON_FS_88200;
+ break;
case 96000:
rate = SPDIF_TXRATE_96000;
csfs = IEC958_AES3_CON_FS_96000;
break;
+ case 176400:
+ rate = SPDIF_TXRATE_176400;
+ csfs = IEC958_AES3_CON_FS_176400;
+ break;
case 192000:
rate = SPDIF_TXRATE_192000;
csfs = IEC958_AES3_CON_FS_192000;
@@ -827,7 +865,7 @@ static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 16000;
- uinfo->value.integer.max = 96000;
+ uinfo->value.integer.max = 192000;
return 0;
}
@@ -1145,7 +1183,8 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
struct clk *clk, u64 savesub,
enum spdif_txrate index, bool round)
{
- static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
+ static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+ 192000, };
bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
u64 rate_ideal, rate_actual, sub;
u32 arate;
@@ -1205,7 +1244,8 @@ out:
static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
enum spdif_txrate index)
{
- static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 };
+ static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+ 192000, };
struct platform_device *pdev = spdif_priv->pdev;
struct device *dev = &pdev->dev;
u64 savesub = 100000, ret;
@@ -1273,6 +1313,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
/* Initialize this copy of the CPU DAI driver structure */
memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev);
+ spdif_priv->cpu_dai_drv.playback.formats =
+ spdif_priv->soc->tx_formats;
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1287,15 +1329,19 @@ static int fsl_spdif_probe(struct platform_device *pdev)
return PTR_ERR(spdif_priv->regmap);
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ 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);
+ return irq;
+ }
- ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
- dev_name(&pdev->dev), spdif_priv);
- if (ret) {
- dev_err(&pdev->dev, "could not claim irq %u\n", irq);
- return ret;
+ ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
+ dev_name(&pdev->dev), spdif_priv);
+ if (ret) {
+ dev_err(&pdev->dev, "could not claim irq %u\n", irq);
+ return ret;
+ }
}
/* Get system clock for rx clock rate calculation */
@@ -1344,8 +1390,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
spdif_priv->dpll_locked = false;
- spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML;
- spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML;
+ spdif_priv->dma_params_tx.maxburst = spdif_priv->soc->tx_burst;
+ spdif_priv->dma_params_rx.maxburst = spdif_priv->soc->rx_burst;
spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL;
spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL;
@@ -1458,6 +1504,7 @@ static const struct of_device_id fsl_spdif_dt_ids[] = {
{ .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, },
{ .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, },
{ .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, },
+ { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, },
{}
};
MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
index e6c61e07bc1a..d5f1dfd58740 100644
--- a/sound/soc/fsl/fsl_spdif.h
+++ b/sound/soc/fsl/fsl_spdif.h
@@ -163,7 +163,9 @@ enum spdif_txrate {
SPDIF_TXRATE_32000 = 0,
SPDIF_TXRATE_44100,
SPDIF_TXRATE_48000,
+ SPDIF_TXRATE_88200,
SPDIF_TXRATE_96000,
+ SPDIF_TXRATE_176400,
SPDIF_TXRATE_192000,
};
#define SPDIF_TXRATE_MAX (SPDIF_TXRATE_192000 + 1)
@@ -177,15 +179,20 @@ enum spdif_txrate {
#define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_88200 | \
SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_176400 | \
SNDRV_PCM_RATE_192000)
#define FSL_SPDIF_RATES_CAPTURE (SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_32000 | \
SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_88200 | \
SNDRV_PCM_RATE_64000 | \
- SNDRV_PCM_RATE_96000)
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_176400 | \
+ SNDRV_PCM_RATE_192000)
#define FSL_SPDIF_FORMATS_PLAYBACK (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
new file mode 100644
index 000000000000..3d58c88ea603
--- /dev/null
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -0,0 +1,1360 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2019 NXP
+
+#include <linux/bitrev.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_iec958.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_xcvr.h"
+#include "imx-pcm.h"
+
+#define FSL_XCVR_CAPDS_SIZE 256
+
+struct fsl_xcvr_soc_data {
+ const char *fw_name;
+};
+
+struct fsl_xcvr {
+ const struct fsl_xcvr_soc_data *soc_data;
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ struct clk *ipg_clk;
+ struct clk *pll_ipg_clk;
+ struct clk *phy_clk;
+ struct clk *spba_clk;
+ struct reset_control *reset;
+ u8 streams;
+ u32 mode;
+ u32 arc_mode;
+ void __iomem *ram_addr;
+ struct snd_dmaengine_dai_dma_data dma_prms_rx;
+ struct snd_dmaengine_dai_dma_data dma_prms_tx;
+ struct snd_aes_iec958 rx_iec958;
+ struct snd_aes_iec958 tx_iec958;
+ u8 cap_ds[FSL_XCVR_CAPDS_SIZE];
+};
+
+static const struct fsl_xcvr_pll_conf {
+ u8 mfi; /* min=0x18, max=0x38 */
+ u32 mfn; /* signed int, 2's compl., min=0x3FFF0000, max=0x00010000 */
+ u32 mfd; /* unsigned int */
+ u32 fout; /* Fout = Fref*(MFI + MFN/MFD), Fref is 24MHz */
+} fsl_xcvr_pll_cfg[] = {
+ { .mfi = 54, .mfn = 1, .mfd = 6, .fout = 1300000000, }, /* 1.3 GHz */
+ { .mfi = 32, .mfn = 96, .mfd = 125, .fout = 786432000, }, /* 8000 Hz */
+ { .mfi = 30, .mfn = 66, .mfd = 625, .fout = 722534400, }, /* 11025 Hz */
+ { .mfi = 29, .mfn = 1, .mfd = 6, .fout = 700000000, }, /* 700 MHz */
+};
+
+/*
+ * HDMI2.1 spec defines 6- and 12-channels layout for one bit audio
+ * stream. Todo: to check how this case can be considered below
+ */
+static const u32 fsl_xcvr_earc_channels[] = { 1, 2, 8, 16, 32, };
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_channels_constr = {
+ .count = ARRAY_SIZE(fsl_xcvr_earc_channels),
+ .list = fsl_xcvr_earc_channels,
+};
+
+static const u32 fsl_xcvr_earc_rates[] = {
+ 32000, 44100, 48000, 64000, 88200, 96000,
+ 128000, 176400, 192000, 256000, 352800, 384000,
+ 512000, 705600, 768000, 1024000, 1411200, 1536000,
+};
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_rates_constr = {
+ .count = ARRAY_SIZE(fsl_xcvr_earc_rates),
+ .list = fsl_xcvr_earc_rates,
+};
+
+static const u32 fsl_xcvr_spdif_channels[] = { 2, };
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_channels_constr = {
+ .count = ARRAY_SIZE(fsl_xcvr_spdif_channels),
+ .list = fsl_xcvr_spdif_channels,
+};
+
+static const u32 fsl_xcvr_spdif_rates[] = {
+ 32000, 44100, 48000, 88200, 96000, 176400, 192000,
+};
+static const struct snd_pcm_hw_constraint_list fsl_xcvr_spdif_rates_constr = {
+ .count = ARRAY_SIZE(fsl_xcvr_spdif_rates),
+ .list = fsl_xcvr_spdif_rates,
+};
+
+static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+
+ xcvr->arc_mode = snd_soc_enum_item_to_val(e, item[0]);
+
+ return 0;
+}
+
+static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+ ucontrol->value.enumerated.item[0] = xcvr->arc_mode;
+
+ return 0;
+}
+
+static const u32 fsl_xcvr_phy_arc_cfg[] = {
+ FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN, FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN,
+};
+
+static const char * const fsl_xcvr_arc_mode[] = { "Single Ended", "Common", };
+static const struct soc_enum fsl_xcvr_arc_mode_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_arc_mode), fsl_xcvr_arc_mode);
+static struct snd_kcontrol_new fsl_xcvr_arc_mode_kctl =
+ SOC_ENUM_EXT("ARC Mode", fsl_xcvr_arc_mode_enum,
+ fsl_xcvr_arc_mode_get, fsl_xcvr_arc_mode_put);
+
+/* Capabilities data structure, bytes */
+static int fsl_xcvr_type_capds_bytes_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = FSL_XCVR_CAPDS_SIZE;
+
+ return 0;
+}
+
+static int fsl_xcvr_capds_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+ memcpy(ucontrol->value.bytes.data, xcvr->cap_ds, FSL_XCVR_CAPDS_SIZE);
+
+ return 0;
+}
+
+static int fsl_xcvr_capds_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+ memcpy(xcvr->cap_ds, ucontrol->value.bytes.data, FSL_XCVR_CAPDS_SIZE);
+
+ return 0;
+}
+
+static struct snd_kcontrol_new fsl_xcvr_earc_capds_kctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "Capabilities Data Structure",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fsl_xcvr_type_capds_bytes_info,
+ .get = fsl_xcvr_capds_get,
+ .put = fsl_xcvr_capds_put,
+};
+
+static int fsl_xcvr_activate_ctl(struct snd_soc_dai *dai, const char *name,
+ bool active)
+{
+ struct snd_soc_card *card = dai->component->card;
+ struct snd_kcontrol *kctl;
+ bool enabled;
+
+ kctl = snd_soc_card_get_kcontrol(card, name);
+ if (kctl == NULL)
+ return -ENOENT;
+
+ enabled = ((kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_WRITE) != 0);
+ if (active == enabled)
+ return 0; /* nothing to do */
+
+ if (active)
+ kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+ else
+ kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
+
+ snd_ctl_notify(card->snd_card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
+
+ return 1;
+}
+
+static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ struct snd_soc_card *card = dai->component->card;
+ struct snd_soc_pcm_runtime *rtd;
+
+ xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
+
+ fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
+ (xcvr->mode == FSL_XCVR_MODE_ARC));
+ fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
+ (xcvr->mode == FSL_XCVR_MODE_EARC));
+ /* Allow playback for SPDIF only */
+ rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
+ rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =
+ (xcvr->mode == FSL_XCVR_MODE_SPDIF ? 1 : 0);
+ return 0;
+}
+
+static int fsl_xcvr_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+ ucontrol->value.enumerated.item[0] = xcvr->mode;
+
+ return 0;
+}
+
+static const char * const fsl_xcvr_mode[] = { "SPDIF", "ARC RX", "eARC", };
+static const struct soc_enum fsl_xcvr_mode_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_mode), fsl_xcvr_mode);
+static struct snd_kcontrol_new fsl_xcvr_mode_kctl =
+ SOC_ENUM_EXT("XCVR Mode", fsl_xcvr_mode_enum,
+ fsl_xcvr_mode_get, fsl_xcvr_mode_put);
+
+/** phy: true => phy, false => pll */
+static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy)
+{
+ struct device *dev = &xcvr->pdev->dev;
+ u32 val, idx, tidx;
+ int ret;
+
+ idx = BIT(phy ? 26 : 24);
+ tidx = BIT(phy ? 27 : 25);
+
+ regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF);
+ regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg);
+ regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_WDATA, data);
+ regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx);
+
+ ret = regmap_read_poll_timeout(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val,
+ (val & idx) == ((val & tidx) >> 1),
+ 10, 10000);
+ if (ret)
+ dev_err(dev, "AI timeout: failed to set %s reg 0x%02x=0x%08x\n",
+ phy ? "PHY" : "PLL", reg, data);
+ return ret;
+}
+
+static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
+{
+ struct device *dev = &xcvr->pdev->dev;
+ u32 i, div = 0, log2;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(fsl_xcvr_pll_cfg); i++) {
+ if (fsl_xcvr_pll_cfg[i].fout % freq == 0) {
+ div = fsl_xcvr_pll_cfg[i].fout / freq;
+ break;
+ }
+ }
+
+ if (!div || i >= ARRAY_SIZE(fsl_xcvr_pll_cfg))
+ return -EINVAL;
+
+ log2 = ilog2(div);
+
+ /* Release AI interface from reset */
+ ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
+ FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
+ if (ret < 0) {
+ dev_err(dev, "Error while setting IER0: %d\n", ret);
+ return ret;
+ }
+
+ /* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET,
+ FSL_XCVR_PLL_BANDGAP_EN_VBG, 0);
+
+ /* PLL: CTRL0: DIV_INTEGER */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0);
+ /* PLL: NUMERATOR: MFN */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0);
+ /* PLL: DENOMINATOR: MFD */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0);
+ /* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+ FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0);
+ udelay(25);
+ /* PLL: CTRL0: Clear Hold Ring Off */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR,
+ FSL_XCVR_PLL_CTRL0_HROFF, 0);
+ udelay(100);
+ if (tx) { /* TX is enabled for SPDIF only */
+ /* PLL: POSTDIV: PDIV0 */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+ FSL_XCVR_PLL_PDIVx(log2, 0), 0);
+ /* PLL: CTRL_SET: CLKMUX0_EN */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+ FSL_XCVR_PLL_CTRL0_CM0_EN, 0);
+ } else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */
+ /* PLL: POSTDIV: PDIV1 */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+ FSL_XCVR_PLL_PDIVx(log2, 1), 0);
+ /* PLL: CTRL_SET: CLKMUX1_EN */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+ FSL_XCVR_PLL_CTRL0_CM1_EN, 0);
+ } else { /* SPDIF / ARC RX */
+ /* PLL: POSTDIV: PDIV2 */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
+ FSL_XCVR_PLL_PDIVx(log2, 2), 0);
+ /* PLL: CTRL_SET: CLKMUX2_EN */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
+ FSL_XCVR_PLL_CTRL0_CM2_EN, 0);
+ }
+
+ if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
+ /* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+ FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+ FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+ /* PHY: CTRL2_SET: EARC_TX_MODE */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
+ FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+ } else if (!tx) { /* SPDIF / ARC RX mode */
+ if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
+ /* PHY: CTRL_SET: SPDIF_EN */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+ FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+ else /* PHY: CTRL_SET: ARC RX setup */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+ FSL_XCVR_PHY_CTRL_PHY_EN |
+ FSL_XCVR_PHY_CTRL_RX_CM_EN |
+ fsl_xcvr_phy_arc_cfg[xcvr->arc_mode], 1);
+ }
+
+ dev_dbg(dev, "PLL Fexp: %u, Fout: %u, mfi: %u, mfn: %u, mfd: %d, div: %u, pdiv0: %u\n",
+ freq, fsl_xcvr_pll_cfg[i].fout, fsl_xcvr_pll_cfg[i].mfi,
+ fsl_xcvr_pll_cfg[i].mfn, fsl_xcvr_pll_cfg[i].mfd, div, log2);
+ return 0;
+}
+
+static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
+{
+ struct device *dev = &xcvr->pdev->dev;
+ int ret;
+
+ clk_disable_unprepare(xcvr->phy_clk);
+ ret = clk_set_rate(xcvr->phy_clk, freq);
+ if (ret < 0) {
+ dev_err(dev, "Error while setting AUD PLL rate: %d\n", ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(xcvr->phy_clk);
+ if (ret) {
+ dev_err(dev, "failed to start PHY clock: %d\n", ret);
+ return ret;
+ }
+
+ /* Release AI interface from reset */
+ ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
+ FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
+ if (ret < 0) {
+ dev_err(dev, "Error while setting IER0: %d\n", ret);
+ return ret;
+ }
+
+ if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
+ /* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+ FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+ FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+ /* PHY: CTRL2_SET: EARC_TX_MODE */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
+ FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+ } else { /* SPDIF mode */
+ /* PHY: CTRL_SET: TX_CLK_AUD_SS | SPDIF_EN */
+ fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
+ FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS |
+ FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+ }
+
+ dev_dbg(dev, "PLL Fexp: %u\n", freq);
+
+ return 0;
+}
+
+#define FSL_XCVR_SPDIF_RX_FREQ 175000000
+static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u32 m_ctl = 0, v_ctl = 0;
+ u32 r = substream->runtime->rate, ch = substream->runtime->channels;
+ u32 fout = 32 * r * ch * 10 * 2;
+ int ret = 0;
+
+ switch (xcvr->mode) {
+ case FSL_XCVR_MODE_SPDIF:
+ case FSL_XCVR_MODE_ARC:
+ if (tx) {
+ ret = fsl_xcvr_en_aud_pll(xcvr, fout);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to set TX freq %u: %d\n",
+ fout, ret);
+ return ret;
+ }
+
+ ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET,
+ FSL_XCVR_TX_DPTH_CTRL_FRM_FMT);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret);
+ return ret;
+ }
+
+ /**
+ * set SPDIF MODE - this flag is used to gate
+ * SPDIF output, useless for SPDIF RX
+ */
+ m_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+ v_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+ } else {
+ /**
+ * Clear RX FIFO, flip RX FIFO bits,
+ * disable eARC related HW mode detects
+ */
+ ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
+ FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+ FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO |
+ FSL_XCVR_RX_DPTH_CTRL_COMP |
+ FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
+ return ret;
+ }
+
+ ret = fsl_xcvr_en_phy_pll(xcvr, FSL_XCVR_SPDIF_RX_FREQ, tx);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to set RX freq %u: %d\n",
+ FSL_XCVR_SPDIF_RX_FREQ, ret);
+ return ret;
+ }
+ }
+ break;
+ case FSL_XCVR_MODE_EARC:
+ if (!tx) {
+ /** Clear RX FIFO, flip RX FIFO bits */
+ ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
+ FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+ FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
+ return ret;
+ }
+
+ /** Enable eARC related HW mode detects */
+ ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_CLR,
+ FSL_XCVR_RX_DPTH_CTRL_COMP |
+ FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to clr TX_DPTH: %d\n", ret);
+ return ret;
+ }
+ }
+
+ /* clear CMDC RESET */
+ m_ctl |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+ /* set TX_RX_MODE */
+ m_ctl |= FSL_XCVR_EXT_CTRL_TX_RX_MODE;
+ v_ctl |= (tx ? FSL_XCVR_EXT_CTRL_TX_RX_MODE : 0);
+ break;
+ }
+
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+ FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
+ if (ret < 0) {
+ dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
+ return ret;
+ }
+
+ /* clear DPATH RESET */
+ m_ctl |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, v_ctl);
+ if (ret < 0) {
+ dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fsl_xcvr_constr(const struct snd_pcm_substream *substream,
+ const struct snd_pcm_hw_constraint_list *channels,
+ const struct snd_pcm_hw_constraint_list *rates)
+{
+ struct snd_pcm_runtime *rt = substream->runtime;
+ int ret;
+
+ ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ channels);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,
+ rates);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ int ret = 0;
+
+ if (xcvr->streams & BIT(substream->stream)) {
+ dev_err(dai->dev, "%sX busy\n", tx ? "T" : "R");
+ return -EBUSY;
+ }
+
+ switch (xcvr->mode) {
+ case FSL_XCVR_MODE_SPDIF:
+ case FSL_XCVR_MODE_ARC:
+ ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
+ &fsl_xcvr_spdif_rates_constr);
+ break;
+ case FSL_XCVR_MODE_EARC:
+ ret = fsl_xcvr_constr(substream, &fsl_xcvr_earc_channels_constr,
+ &fsl_xcvr_earc_rates_constr);
+ break;
+ }
+ if (ret < 0)
+ return ret;
+
+ xcvr->streams |= BIT(substream->stream);
+
+ /* Disable XCVR controls if there is stream started */
+ fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
+ fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
+ fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
+
+ return 0;
+}
+
+static void fsl_xcvr_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u32 mask = 0, val = 0;
+ int ret;
+
+ xcvr->streams &= ~BIT(substream->stream);
+
+ /* Enable XCVR controls if there is no stream started */
+ if (!xcvr->streams) {
+ fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
+ fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
+ (xcvr->mode == FSL_XCVR_MODE_ARC));
+ fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
+ (xcvr->mode == FSL_XCVR_MODE_EARC));
+
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
+ FSL_XCVR_IRQ_EARC_ALL, 0);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to set IER0: %d\n", ret);
+ return;
+ }
+
+ /* clear SPDIF MODE */
+ if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
+ mask |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
+ }
+
+ if (xcvr->mode == FSL_XCVR_MODE_EARC) {
+ /* set CMDC RESET */
+ mask |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+ val |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
+ }
+
+ /* set DPATH RESET */
+ mask |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+ val |= FSL_XCVR_EXT_CTRL_DPTH_RESET(tx);
+
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
+ if (ret < 0) {
+ dev_err(dai->dev, "Err setting DPATH RESET: %d\n", ret);
+ return;
+ }
+}
+
+static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ int ret;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (tx) {
+ switch (xcvr->mode) {
+ case FSL_XCVR_MODE_EARC:
+ /* set isr_cmdc_tx_en, w1c */
+ ret = regmap_write(xcvr->regmap,
+ FSL_XCVR_ISR_SET,
+ FSL_XCVR_ISR_CMDC_TX_EN);
+ if (ret < 0) {
+ dev_err(dai->dev, "err updating isr %d\n", ret);
+ return ret;
+ }
+ fallthrough;
+ case FSL_XCVR_MODE_SPDIF:
+ ret = regmap_write(xcvr->regmap,
+ FSL_XCVR_TX_DPTH_CTRL_SET,
+ FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret);
+ return ret;
+ }
+ break;
+ }
+ }
+
+ /* enable DMA RD/WR */
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
+ return ret;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ /* disable DMA RD/WR */
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_DMA_DIS(tx),
+ FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
+ return ret;
+ }
+
+ if (tx) {
+ switch (xcvr->mode) {
+ case FSL_XCVR_MODE_SPDIF:
+ ret = regmap_write(xcvr->regmap,
+ FSL_XCVR_TX_DPTH_CTRL_CLR,
+ FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret);
+ return ret;
+ }
+ fallthrough;
+ case FSL_XCVR_MODE_EARC:
+ /* clear ISR_CMDC_TX_EN, W1C */
+ ret = regmap_write(xcvr->regmap,
+ FSL_XCVR_ISR_CLR,
+ FSL_XCVR_ISR_CMDC_TX_EN);
+ if (ret < 0) {
+ dev_err(dai->dev,
+ "Err updating ISR %d\n", ret);
+ return ret;
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
+{
+ struct device *dev = &xcvr->pdev->dev;
+ const struct firmware *fw;
+ int ret = 0, rem, off, out, page = 0, size = FSL_XCVR_REG_OFFSET;
+ u32 mask, val;
+
+ ret = request_firmware(&fw, xcvr->soc_data->fw_name, dev);
+ if (ret) {
+ dev_err(dev, "failed to request firmware.\n");
+ return ret;
+ }
+
+ rem = fw->size;
+
+ /* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */
+ if (rem > 16384) {
+ dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem);
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ for (page = 0; page < 10; page++) {
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_PAGE_MASK,
+ FSL_XCVR_EXT_CTRL_PAGE(page));
+ if (ret < 0) {
+ dev_err(dev, "FW: failed to set page %d, err=%d\n",
+ page, ret);
+ goto err_firmware;
+ }
+
+ off = page * size;
+ out = min(rem, size);
+ /* IPG clock is assumed to be running, otherwise it will hang */
+ if (out > 0) {
+ /* write firmware into code memory */
+ memcpy_toio(xcvr->ram_addr, fw->data + off, out);
+ rem -= out;
+ if (rem == 0) {
+ /* last part of firmware written */
+ /* clean remaining part of code memory page */
+ memset_io(xcvr->ram_addr + out, 0, size - out);
+ }
+ } else {
+ /* clean current page, including data memory */
+ memset_io(xcvr->ram_addr, 0, size);
+ }
+ };
+
+err_firmware:
+ release_firmware(fw);
+ if (ret < 0)
+ return ret;
+
+ /* configure watermarks */
+ mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK;
+ val = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX);
+ val |= FSL_XCVR_EXT_CTRL_TX_FWM(FSL_XCVR_FIFO_WMK_TX);
+ /* disable DMA RD/WR */
+ mask |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
+ val |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
+ /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
+ mask |= FSL_XCVR_EXT_CTRL_PAGE_MASK;
+ val |= FSL_XCVR_EXT_CTRL_PAGE(8);
+
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set watermarks: %d\n", ret);
+ return ret;
+ }
+
+ /* Store Capabilities Data Structure into Data RAM */
+ memcpy_toio(xcvr->ram_addr + FSL_XCVR_CAP_DATA_STR, xcvr->cap_ds,
+ FSL_XCVR_CAPDS_SIZE);
+ return 0;
+}
+
+static int fsl_xcvr_type_iec958_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+
+ return 0;
+}
+
+static int fsl_xcvr_type_iec958_bytes_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof_field(struct snd_aes_iec958, status);
+
+ return 0;
+}
+
+static int fsl_xcvr_rx_cs_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+ memcpy(ucontrol->value.iec958.status, xcvr->rx_iec958.status, 24);
+
+ return 0;
+}
+
+static int fsl_xcvr_tx_cs_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+ memcpy(ucontrol->value.iec958.status, xcvr->tx_iec958.status, 24);
+
+ return 0;
+}
+
+static int fsl_xcvr_tx_cs_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+ memcpy(xcvr->tx_iec958.status, ucontrol->value.iec958.status, 24);
+
+ return 0;
+}
+
+static struct snd_kcontrol_new fsl_xcvr_rx_ctls[] = {
+ /* Channel status controller */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .info = fsl_xcvr_type_iec958_info,
+ .get = fsl_xcvr_rx_cs_get,
+ },
+ /* Capture channel status, bytes */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "Capture Channel Status",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .info = fsl_xcvr_type_iec958_bytes_info,
+ .get = fsl_xcvr_rx_cs_get,
+ },
+};
+
+static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
+ /* Channel status controller */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fsl_xcvr_type_iec958_info,
+ .get = fsl_xcvr_tx_cs_get,
+ .put = fsl_xcvr_tx_cs_put,
+ },
+ /* Playback channel status, bytes */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "Playback Channel Status",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = fsl_xcvr_type_iec958_bytes_info,
+ .get = fsl_xcvr_tx_cs_get,
+ .put = fsl_xcvr_tx_cs_put,
+ },
+};
+
+static struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
+ .prepare = fsl_xcvr_prepare,
+ .startup = fsl_xcvr_startup,
+ .shutdown = fsl_xcvr_shutdown,
+ .trigger = fsl_xcvr_trigger,
+};
+
+static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
+{
+ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &xcvr->dma_prms_tx, &xcvr->dma_prms_rx);
+ snd_soc_dai_set_drvdata(dai, xcvr);
+
+ snd_soc_add_dai_controls(dai, &fsl_xcvr_mode_kctl, 1);
+ snd_soc_add_dai_controls(dai, &fsl_xcvr_arc_mode_kctl, 1);
+ snd_soc_add_dai_controls(dai, &fsl_xcvr_earc_capds_kctl, 1);
+ snd_soc_add_dai_controls(dai, fsl_xcvr_tx_ctls,
+ ARRAY_SIZE(fsl_xcvr_tx_ctls));
+ snd_soc_add_dai_controls(dai, fsl_xcvr_rx_ctls,
+ ARRAY_SIZE(fsl_xcvr_rx_ctls));
+ return 0;
+}
+
+static struct snd_soc_dai_driver fsl_xcvr_dai = {
+ .probe = fsl_xcvr_dai_probe,
+ .ops = &fsl_xcvr_dai_ops,
+ .playback = {
+ .stream_name = "CPU-Playback",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 32000,
+ .rate_max = 1536000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+ },
+ .capture = {
+ .stream_name = "CPU-Capture",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 32000,
+ .rate_max = 1536000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+ },
+};
+
+static const struct snd_soc_component_driver fsl_xcvr_comp = {
+ .name = "fsl-xcvr-dai",
+};
+
+static const struct reg_default fsl_xcvr_reg_defaults[] = {
+ { FSL_XCVR_VERSION, 0x00000000 },
+ { FSL_XCVR_EXT_CTRL, 0xF8204040 },
+ { FSL_XCVR_EXT_STATUS, 0x00000000 },
+ { FSL_XCVR_EXT_IER0, 0x00000000 },
+ { FSL_XCVR_EXT_IER1, 0x00000000 },
+ { FSL_XCVR_EXT_ISR, 0x00000000 },
+ { FSL_XCVR_EXT_ISR_SET, 0x00000000 },
+ { FSL_XCVR_EXT_ISR_CLR, 0x00000000 },
+ { FSL_XCVR_EXT_ISR_TOG, 0x00000000 },
+ { FSL_XCVR_IER, 0x00000000 },
+ { FSL_XCVR_ISR, 0x00000000 },
+ { FSL_XCVR_ISR_SET, 0x00000000 },
+ { FSL_XCVR_ISR_CLR, 0x00000000 },
+ { FSL_XCVR_ISR_TOG, 0x00000000 },
+ { FSL_XCVR_RX_DPTH_CTRL, 0x00002C89 },
+ { FSL_XCVR_RX_DPTH_CTRL_SET, 0x00002C89 },
+ { FSL_XCVR_RX_DPTH_CTRL_CLR, 0x00002C89 },
+ { FSL_XCVR_RX_DPTH_CTRL_TOG, 0x00002C89 },
+ { FSL_XCVR_TX_DPTH_CTRL, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_CTRL_SET, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_CTRL_CLR, 0x00000000 },
+ { FSL_XCVR_TX_DPTH_CTRL_TOG, 0x00000000 },
+ { FSL_XCVR_TX_CS_DATA_0, 0x00000000 },
+ { FSL_XCVR_TX_CS_DATA_1, 0x00000000 },
+ { FSL_XCVR_TX_CS_DATA_2, 0x00000000 },
+ { FSL_XCVR_TX_CS_DATA_3, 0x00000000 },
+ { FSL_XCVR_TX_CS_DATA_4, 0x00000000 },
+ { FSL_XCVR_TX_CS_DATA_5, 0x00000000 },
+ { FSL_XCVR_DEBUG_REG_0, 0x00000000 },
+ { FSL_XCVR_DEBUG_REG_1, 0x00000000 },
+};
+
+static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FSL_XCVR_VERSION:
+ case FSL_XCVR_EXT_CTRL:
+ case FSL_XCVR_EXT_STATUS:
+ case FSL_XCVR_EXT_IER0:
+ case FSL_XCVR_EXT_IER1:
+ case FSL_XCVR_EXT_ISR:
+ case FSL_XCVR_EXT_ISR_SET:
+ case FSL_XCVR_EXT_ISR_CLR:
+ case FSL_XCVR_EXT_ISR_TOG:
+ case FSL_XCVR_IER:
+ case FSL_XCVR_ISR:
+ case FSL_XCVR_ISR_SET:
+ case FSL_XCVR_ISR_CLR:
+ case FSL_XCVR_ISR_TOG:
+ case FSL_XCVR_PHY_AI_CTRL:
+ case FSL_XCVR_PHY_AI_CTRL_SET:
+ case FSL_XCVR_PHY_AI_CTRL_CLR:
+ case FSL_XCVR_PHY_AI_CTRL_TOG:
+ case FSL_XCVR_PHY_AI_RDATA:
+ case FSL_XCVR_CLK_CTRL:
+ case FSL_XCVR_RX_DPTH_CTRL:
+ case FSL_XCVR_RX_DPTH_CTRL_SET:
+ case FSL_XCVR_RX_DPTH_CTRL_CLR:
+ case FSL_XCVR_RX_DPTH_CTRL_TOG:
+ case FSL_XCVR_TX_DPTH_CTRL:
+ case FSL_XCVR_TX_DPTH_CTRL_SET:
+ case FSL_XCVR_TX_DPTH_CTRL_CLR:
+ case FSL_XCVR_TX_DPTH_CTRL_TOG:
+ case FSL_XCVR_TX_CS_DATA_0:
+ case FSL_XCVR_TX_CS_DATA_1:
+ case FSL_XCVR_TX_CS_DATA_2:
+ case FSL_XCVR_TX_CS_DATA_3:
+ case FSL_XCVR_TX_CS_DATA_4:
+ case FSL_XCVR_TX_CS_DATA_5:
+ case FSL_XCVR_DEBUG_REG_0:
+ case FSL_XCVR_DEBUG_REG_1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case FSL_XCVR_EXT_CTRL:
+ case FSL_XCVR_EXT_IER0:
+ case FSL_XCVR_EXT_IER1:
+ case FSL_XCVR_EXT_ISR:
+ case FSL_XCVR_EXT_ISR_SET:
+ case FSL_XCVR_EXT_ISR_CLR:
+ case FSL_XCVR_EXT_ISR_TOG:
+ case FSL_XCVR_IER:
+ case FSL_XCVR_ISR_SET:
+ case FSL_XCVR_ISR_CLR:
+ case FSL_XCVR_ISR_TOG:
+ case FSL_XCVR_PHY_AI_CTRL:
+ case FSL_XCVR_PHY_AI_CTRL_SET:
+ case FSL_XCVR_PHY_AI_CTRL_CLR:
+ case FSL_XCVR_PHY_AI_CTRL_TOG:
+ case FSL_XCVR_PHY_AI_WDATA:
+ case FSL_XCVR_CLK_CTRL:
+ case FSL_XCVR_RX_DPTH_CTRL:
+ case FSL_XCVR_RX_DPTH_CTRL_SET:
+ case FSL_XCVR_RX_DPTH_CTRL_CLR:
+ case FSL_XCVR_RX_DPTH_CTRL_TOG:
+ case FSL_XCVR_TX_DPTH_CTRL_SET:
+ case FSL_XCVR_TX_DPTH_CTRL_CLR:
+ case FSL_XCVR_TX_DPTH_CTRL_TOG:
+ case FSL_XCVR_TX_CS_DATA_0:
+ case FSL_XCVR_TX_CS_DATA_1:
+ case FSL_XCVR_TX_CS_DATA_2:
+ case FSL_XCVR_TX_CS_DATA_3:
+ case FSL_XCVR_TX_CS_DATA_4:
+ case FSL_XCVR_TX_CS_DATA_5:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fsl_xcvr_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return fsl_xcvr_readable_reg(dev, reg);
+}
+
+static const struct regmap_config fsl_xcvr_regmap_cfg = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = FSL_XCVR_MAX_REG,
+ .reg_defaults = fsl_xcvr_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_xcvr_reg_defaults),
+ .readable_reg = fsl_xcvr_readable_reg,
+ .volatile_reg = fsl_xcvr_volatile_reg,
+ .writeable_reg = fsl_xcvr_writeable_reg,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t irq0_isr(int irq, void *devid)
+{
+ struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid;
+ struct device *dev = &xcvr->pdev->dev;
+ struct regmap *regmap = xcvr->regmap;
+ void __iomem *reg_ctrl, *reg_buff;
+ u32 isr, isr_clr = 0, val, i;
+
+ regmap_read(regmap, FSL_XCVR_EXT_ISR, &isr);
+
+ if (isr & FSL_XCVR_IRQ_NEW_CS) {
+ dev_dbg(dev, "Received new CS block\n");
+ isr_clr |= FSL_XCVR_IRQ_NEW_CS;
+ /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
+ regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_PAGE_MASK,
+ FSL_XCVR_EXT_CTRL_PAGE(8));
+
+ /* Find updated CS buffer */
+ reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_0;
+ reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_0;
+ memcpy_fromio(&val, reg_ctrl, sizeof(val));
+ if (!val) {
+ reg_ctrl = xcvr->ram_addr + FSL_XCVR_RX_CS_CTRL_1;
+ reg_buff = xcvr->ram_addr + FSL_XCVR_RX_CS_BUFF_1;
+ memcpy_fromio(&val, reg_ctrl, sizeof(val));
+ }
+
+ if (val) {
+ /* copy CS buffer */
+ memcpy_fromio(&xcvr->rx_iec958.status, reg_buff,
+ sizeof(xcvr->rx_iec958.status));
+ for (i = 0; i < 6; i++) {
+ val = *(u32 *)(xcvr->rx_iec958.status + i*4);
+ *(u32 *)(xcvr->rx_iec958.status + i*4) =
+ bitrev32(val);
+ }
+ /* clear CS control register */
+ memset_io(reg_ctrl, 0, sizeof(val));
+ }
+ }
+ if (isr & FSL_XCVR_IRQ_NEW_UD) {
+ dev_dbg(dev, "Received new UD block\n");
+ isr_clr |= FSL_XCVR_IRQ_NEW_UD;
+ }
+ if (isr & FSL_XCVR_IRQ_MUTE) {
+ dev_dbg(dev, "HW mute bit detected\n");
+ isr_clr |= FSL_XCVR_IRQ_MUTE;
+ }
+ if (isr & FSL_XCVR_IRQ_FIFO_UOFL_ERR) {
+ dev_dbg(dev, "RX/TX FIFO full/empty\n");
+ isr_clr |= FSL_XCVR_IRQ_FIFO_UOFL_ERR;
+ }
+ if (isr & FSL_XCVR_IRQ_ARC_MODE) {
+ dev_dbg(dev, "CMDC SM falls out of eARC mode\n");
+ isr_clr |= FSL_XCVR_IRQ_ARC_MODE;
+ }
+ if (isr & FSL_XCVR_IRQ_DMA_RD_REQ) {
+ dev_dbg(dev, "DMA read request\n");
+ isr_clr |= FSL_XCVR_IRQ_DMA_RD_REQ;
+ }
+ if (isr & FSL_XCVR_IRQ_DMA_WR_REQ) {
+ dev_dbg(dev, "DMA write request\n");
+ isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ;
+ }
+
+ if (isr_clr) {
+ regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static const struct fsl_xcvr_soc_data fsl_xcvr_imx8mp_data = {
+ .fw_name = "imx/xcvr/xcvr-imx8mp.bin",
+};
+
+static const struct of_device_id fsl_xcvr_dt_ids[] = {
+ { .compatible = "fsl,imx8mp-xcvr", .data = &fsl_xcvr_imx8mp_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_xcvr_dt_ids);
+
+static int fsl_xcvr_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id;
+ struct fsl_xcvr *xcvr;
+ struct resource *ram_res, *regs_res, *rx_res, *tx_res;
+ void __iomem *regs;
+ int ret, irq;
+
+ of_id = of_match_device(fsl_xcvr_dt_ids, dev);
+ if (!of_id)
+ return -EINVAL;
+
+ xcvr = devm_kzalloc(dev, sizeof(*xcvr), GFP_KERNEL);
+ if (!xcvr)
+ return -ENOMEM;
+
+ xcvr->pdev = pdev;
+ xcvr->soc_data = of_device_get_match_data(&pdev->dev);
+
+ xcvr->ipg_clk = devm_clk_get(dev, "ipg");
+ if (IS_ERR(xcvr->ipg_clk)) {
+ dev_err(dev, "failed to get ipg clock\n");
+ return PTR_ERR(xcvr->ipg_clk);
+ }
+
+ xcvr->phy_clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(xcvr->phy_clk)) {
+ dev_err(dev, "failed to get phy clock\n");
+ return PTR_ERR(xcvr->phy_clk);
+ }
+
+ xcvr->spba_clk = devm_clk_get(dev, "spba");
+ if (IS_ERR(xcvr->spba_clk)) {
+ dev_err(dev, "failed to get spba clock\n");
+ return PTR_ERR(xcvr->spba_clk);
+ }
+
+ xcvr->pll_ipg_clk = devm_clk_get(dev, "pll_ipg");
+ if (IS_ERR(xcvr->pll_ipg_clk)) {
+ dev_err(dev, "failed to get pll_ipg clock\n");
+ return PTR_ERR(xcvr->pll_ipg_clk);
+ }
+
+ ram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ram");
+ xcvr->ram_addr = devm_ioremap_resource(dev, ram_res);
+ if (IS_ERR(xcvr->ram_addr))
+ return PTR_ERR(xcvr->ram_addr);
+
+ regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+ regs = devm_ioremap_resource(dev, regs_res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ xcvr->regmap = devm_regmap_init_mmio_clk(dev, NULL, regs,
+ &fsl_xcvr_regmap_cfg);
+ if (IS_ERR(xcvr->regmap)) {
+ dev_err(dev, "failed to init XCVR regmap: %ld\n",
+ PTR_ERR(xcvr->regmap));
+ return PTR_ERR(xcvr->regmap);
+ }
+
+ xcvr->reset = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(xcvr->reset)) {
+ dev_err(dev, "failed to get XCVR reset control\n");
+ return PTR_ERR(xcvr->reset);
+ }
+
+ /* get IRQs */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "no irq[0]: %d\n", irq);
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, irq0_isr, 0, pdev->name, xcvr);
+ if (ret) {
+ dev_err(dev, "failed to claim IRQ0: %i\n", ret);
+ return ret;
+ }
+
+ rx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rxfifo");
+ tx_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "txfifo");
+ xcvr->dma_prms_rx.chan_name = "rx";
+ xcvr->dma_prms_tx.chan_name = "tx";
+ xcvr->dma_prms_rx.addr = rx_res->start;
+ xcvr->dma_prms_tx.addr = tx_res->start;
+ xcvr->dma_prms_rx.maxburst = FSL_XCVR_MAXBURST_RX;
+ xcvr->dma_prms_tx.maxburst = FSL_XCVR_MAXBURST_TX;
+
+ platform_set_drvdata(pdev, xcvr);
+ pm_runtime_enable(dev);
+ regcache_cache_only(xcvr->regmap, true);
+
+ ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp,
+ &fsl_xcvr_dai, 1);
+ if (ret) {
+ dev_err(dev, "failed to register component %s\n",
+ fsl_xcvr_comp.name);
+ return ret;
+ }
+
+ ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
+ if (ret)
+ dev_err(dev, "failed to pcm register\n");
+
+ return ret;
+}
+
+static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev)
+{
+ struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
+ int ret;
+
+ /* Assert M0+ reset */
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_CORE_RESET,
+ FSL_XCVR_EXT_CTRL_CORE_RESET);
+ if (ret < 0)
+ dev_err(dev, "Failed to assert M0+ core: %d\n", ret);
+
+ ret = reset_control_assert(xcvr->reset);
+ if (ret < 0)
+ dev_err(dev, "Failed to assert M0+ reset: %d\n", ret);
+
+ regcache_cache_only(xcvr->regmap, true);
+
+ clk_disable_unprepare(xcvr->spba_clk);
+ clk_disable_unprepare(xcvr->phy_clk);
+ clk_disable_unprepare(xcvr->pll_ipg_clk);
+ clk_disable_unprepare(xcvr->ipg_clk);
+
+ return 0;
+}
+
+static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev)
+{
+ struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(xcvr->ipg_clk);
+ if (ret) {
+ dev_err(dev, "failed to start IPG clock.\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(xcvr->pll_ipg_clk);
+ if (ret) {
+ dev_err(dev, "failed to start PLL IPG clock.\n");
+ goto stop_ipg_clk;
+ }
+
+ ret = clk_prepare_enable(xcvr->phy_clk);
+ if (ret) {
+ dev_err(dev, "failed to start PHY clock: %d\n", ret);
+ goto stop_pll_ipg_clk;
+ }
+
+ ret = clk_prepare_enable(xcvr->spba_clk);
+ if (ret) {
+ dev_err(dev, "failed to start SPBA clock.\n");
+ goto stop_phy_clk;
+ }
+
+ regcache_cache_only(xcvr->regmap, false);
+ regcache_mark_dirty(xcvr->regmap);
+ ret = regcache_sync(xcvr->regmap);
+
+ if (ret) {
+ dev_err(dev, "failed to sync regcache.\n");
+ goto stop_spba_clk;
+ }
+
+ ret = reset_control_deassert(xcvr->reset);
+ if (ret) {
+ dev_err(dev, "failed to deassert M0+ reset.\n");
+ goto stop_spba_clk;
+ }
+
+ ret = fsl_xcvr_load_firmware(xcvr);
+ if (ret) {
+ dev_err(dev, "failed to load firmware.\n");
+ goto stop_spba_clk;
+ }
+
+ /* Release M0+ reset */
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_CORE_RESET, 0);
+ if (ret < 0) {
+ dev_err(dev, "M0+ core release failed: %d\n", ret);
+ goto stop_spba_clk;
+ }
+
+ /* Let M0+ core complete firmware initialization */
+ msleep(50);
+
+ return 0;
+
+stop_spba_clk:
+ clk_disable_unprepare(xcvr->spba_clk);
+stop_phy_clk:
+ clk_disable_unprepare(xcvr->phy_clk);
+stop_pll_ipg_clk:
+ clk_disable_unprepare(xcvr->pll_ipg_clk);
+stop_ipg_clk:
+ clk_disable_unprepare(xcvr->ipg_clk);
+
+ return ret;
+}
+
+static const struct dev_pm_ops fsl_xcvr_pm_ops = {
+ SET_RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend,
+ fsl_xcvr_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_xcvr_driver = {
+ .probe = fsl_xcvr_probe,
+ .driver = {
+ .name = "fsl,imx8mp-audio-xcvr",
+ .pm = &fsl_xcvr_pm_ops,
+ .of_match_table = fsl_xcvr_dt_ids,
+ },
+};
+module_platform_driver(fsl_xcvr_driver);
+
+MODULE_AUTHOR("Viorel Suman <viorel.suman@nxp.com>");
+MODULE_DESCRIPTION("NXP Audio Transceiver (XCVR) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h
new file mode 100644
index 000000000000..7f2853c60085
--- /dev/null
+++ b/sound/soc/fsl/fsl_xcvr.h
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NXP XCVR ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright 2019 NXP
+ */
+
+#ifndef __FSL_XCVR_H
+#define __FSL_XCVR_H
+
+#define FSL_XCVR_MODE_SPDIF 0
+#define FSL_XCVR_MODE_ARC 1
+#define FSL_XCVR_MODE_EARC 2
+
+/* XCVR Registers */
+#define FSL_XCVR_REG_OFFSET 0x800 /* regs offset */
+#define FSL_XCVR_FIFO_SIZE 0x80 /* 128 */
+#define FSL_XCVR_FIFO_WMK_RX (FSL_XCVR_FIFO_SIZE >> 1) /* 64 */
+#define FSL_XCVR_FIFO_WMK_TX (FSL_XCVR_FIFO_SIZE >> 1) /* 64 */
+#define FSL_XCVR_MAXBURST_RX (FSL_XCVR_FIFO_WMK_RX >> 2) /* 16 */
+#define FSL_XCVR_MAXBURST_TX (FSL_XCVR_FIFO_WMK_TX >> 2) /* 16 */
+
+#define FSL_XCVR_RX_FIFO_ADDR 0x0C00
+#define FSL_XCVR_TX_FIFO_ADDR 0x0E00
+
+#define FSL_XCVR_VERSION 0x00 /* Version */
+#define FSL_XCVR_EXT_CTRL 0x10 /* Control */
+#define FSL_XCVR_EXT_STATUS 0x20 /* Status */
+#define FSL_XCVR_EXT_IER0 0x30 /* Interrupt en 0 */
+#define FSL_XCVR_EXT_IER1 0x40 /* Interrupt en 1 */
+#define FSL_XCVR_EXT_ISR 0x50 /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_SET 0x54 /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_CLR 0x58 /* Interrupt status */
+#define FSL_XCVR_EXT_ISR_TOG 0x5C /* Interrupt status */
+#define FSL_XCVR_IER 0x70 /* Interrupt en for M0+ */
+#define FSL_XCVR_ISR 0x80 /* Interrupt status */
+#define FSL_XCVR_ISR_SET 0x84 /* Interrupt status set */
+#define FSL_XCVR_ISR_CLR 0x88 /* Interrupt status clear */
+#define FSL_XCVR_ISR_TOG 0x8C /* Interrupt status toggle */
+#define FSL_XCVR_PHY_AI_CTRL 0x90
+#define FSL_XCVR_PHY_AI_CTRL_SET 0x94
+#define FSL_XCVR_PHY_AI_CTRL_CLR 0x98
+#define FSL_XCVR_PHY_AI_CTRL_TOG 0x9C
+#define FSL_XCVR_PHY_AI_WDATA 0xA0
+#define FSL_XCVR_PHY_AI_RDATA 0xA4
+#define FSL_XCVR_CLK_CTRL 0xB0
+#define FSL_XCVR_RX_DPTH_CTRL 0x180 /* RX datapath ctrl reg */
+#define FSL_XCVR_RX_DPTH_CTRL_SET 0x184
+#define FSL_XCVR_RX_DPTH_CTRL_CLR 0x188
+#define FSL_XCVR_RX_DPTH_CTRL_TOG 0x18c
+
+#define FSL_XCVR_TX_DPTH_CTRL 0x220 /* TX datapath ctrl reg */
+#define FSL_XCVR_TX_DPTH_CTRL_SET 0x224
+#define FSL_XCVR_TX_DPTH_CTRL_CLR 0x228
+#define FSL_XCVR_TX_DPTH_CTRL_TOG 0x22C
+#define FSL_XCVR_TX_CS_DATA_0 0x230 /* TX channel status bits regs */
+#define FSL_XCVR_TX_CS_DATA_1 0x234
+#define FSL_XCVR_TX_CS_DATA_2 0x238
+#define FSL_XCVR_TX_CS_DATA_3 0x23C
+#define FSL_XCVR_TX_CS_DATA_4 0x240
+#define FSL_XCVR_TX_CS_DATA_5 0x244
+#define FSL_XCVR_DEBUG_REG_0 0x2E0
+#define FSL_XCVR_DEBUG_REG_1 0x2F0
+
+#define FSL_XCVR_MAX_REG FSL_XCVR_DEBUG_REG_1
+
+#define FSL_XCVR_EXT_CTRL_CORE_RESET BIT(31)
+
+#define FSL_XCVR_EXT_CTRL_RX_CMDC_RESET BIT(30)
+#define FSL_XCVR_EXT_CTRL_TX_CMDC_RESET BIT(29)
+#define FSL_XCVR_EXT_CTRL_CMDC_RESET(t) (t ? BIT(29) : BIT(30))
+
+#define FSL_XCVR_EXT_CTRL_RX_DPTH_RESET BIT(28)
+#define FSL_XCVR_EXT_CTRL_TX_DPTH_RESET BIT(27)
+#define FSL_XCVR_EXT_CTRL_DPTH_RESET(t) (t ? BIT(27) : BIT(28))
+
+#define FSL_XCVR_EXT_CTRL_TX_RX_MODE BIT(26)
+#define FSL_XCVR_EXT_CTRL_DMA_RD_DIS BIT(25)
+#define FSL_XCVR_EXT_CTRL_DMA_WR_DIS BIT(24)
+#define FSL_XCVR_EXT_CTRL_DMA_DIS(t) (t ? BIT(24) : BIT(25))
+#define FSL_XCVR_EXT_CTRL_SPDIF_MODE BIT(23)
+#define FSL_XCVR_EXT_CTRL_SLEEP_MODE BIT(21)
+
+#define FSL_XCVR_EXT_CTRL_TX_FWM_SHFT 0
+#define FSL_XCVR_EXT_CTRL_TX_FWM_MASK GENMASK(6, 0)
+#define FSL_XCVR_EXT_CTRL_TX_FWM(i) (((i) << FSL_XCVR_EXT_CTRL_TX_FWM_SHFT) \
+ & FSL_XCVR_EXT_CTRL_TX_FWM_MASK)
+#define FSL_XCVR_EXT_CTRL_RX_FWM_SHFT 8
+#define FSL_XCVR_EXT_CTRL_RX_FWM_MASK GENMASK(14, 8)
+#define FSL_XCVR_EXT_CTRL_RX_FWM(i) (((i) << FSL_XCVR_EXT_CTRL_RX_FWM_SHFT) \
+ & FSL_XCVR_EXT_CTRL_RX_FWM_MASK)
+#define FSL_XCVR_EXT_CTRL_PAGE_SHFT 16
+#define FSL_XCVR_EXT_CTRL_PAGE_MASK GENMASK(19, 16)
+#define FSL_XCVR_EXT_CTRL_PAGE(i) (((i) << FSL_XCVR_EXT_CTRL_PAGE_SHFT) \
+ & FSL_XCVR_EXT_CTRL_PAGE_MASK)
+
+#define FSL_XCVR_EXT_STUS_NT_FIFO_ENTR GENMASK(7, 0)
+#define FSL_XCVR_EXT_STUS_NR_FIFO_ENTR GENMASK(15, 8)
+#define FSL_XCVR_EXT_STUS_CM0_SLEEPING BIT(16)
+#define FSL_XCVR_EXT_STUS_CM0_DEEP_SLP BIT(17)
+#define FSL_XCVR_EXT_STUS_CM0_SLP_HACK BIT(18)
+#define FSL_XCVR_EXT_STUS_RX_CMDC_RSTO BIT(23)
+#define FSL_XCVR_EXT_STUS_TX_CMDC_RSTO BIT(24)
+#define FSL_XCVR_EXT_STUS_RX_CMDC_COTO BIT(25)
+#define FSL_XCVR_EXT_STUS_TX_CMDC_COTO BIT(26)
+#define FSL_XCVR_EXT_STUS_HB_STATUS BIT(27)
+#define FSL_XCVR_EXT_STUS_NEW_UD4_REC BIT(28)
+#define FSL_XCVR_EXT_STUS_NEW_UD5_REC BIT(29)
+#define FSL_XCVR_EXT_STUS_NEW_UD6_REC BIT(30)
+#define FSL_XCVR_EXT_STUS_HPD_INPUT BIT(31)
+
+#define FSL_XCVR_IRQ_NEW_CS BIT(0)
+#define FSL_XCVR_IRQ_NEW_UD BIT(1)
+#define FSL_XCVR_IRQ_MUTE BIT(2)
+#define FSL_XCVR_IRQ_CMDC_RESP_TO BIT(3)
+#define FSL_XCVR_IRQ_ECC_ERR BIT(4)
+#define FSL_XCVR_IRQ_PREAMBLE_MISMATCH BIT(5)
+#define FSL_XCVR_IRQ_FIFO_UOFL_ERR BIT(6)
+#define FSL_XCVR_IRQ_HOST_WAKEUP BIT(7)
+#define FSL_XCVR_IRQ_HOST_OHPD BIT(8)
+#define FSL_XCVR_IRQ_DMAC_NO_DATA_REC BIT(9)
+#define FSL_XCVR_IRQ_DMAC_FMT_CHG_DET BIT(10)
+#define FSL_XCVR_IRQ_HB_STATE_CHG BIT(11)
+#define FSL_XCVR_IRQ_CMDC_STATUS_UPD BIT(12)
+#define FSL_XCVR_IRQ_TEMP_UPD BIT(13)
+#define FSL_XCVR_IRQ_DMA_RD_REQ BIT(14)
+#define FSL_XCVR_IRQ_DMA_WR_REQ BIT(15)
+#define FSL_XCVR_IRQ_DMAC_BME_BIT_ERR BIT(16)
+#define FSL_XCVR_IRQ_PREAMBLE_MATCH BIT(17)
+#define FSL_XCVR_IRQ_M_W_PRE_MISMATCH BIT(18)
+#define FSL_XCVR_IRQ_B_PRE_MISMATCH BIT(19)
+#define FSL_XCVR_IRQ_UNEXP_PRE_REC BIT(20)
+#define FSL_XCVR_IRQ_ARC_MODE BIT(21)
+#define FSL_XCVR_IRQ_CH_UD_OFLOW BIT(22)
+#define FSL_XCVR_IRQ_EARC_ALL (FSL_XCVR_IRQ_NEW_CS | \
+ FSL_XCVR_IRQ_NEW_UD | \
+ FSL_XCVR_IRQ_MUTE | \
+ FSL_XCVR_IRQ_FIFO_UOFL_ERR | \
+ FSL_XCVR_IRQ_HOST_WAKEUP | \
+ FSL_XCVR_IRQ_ARC_MODE)
+
+#define FSL_XCVR_ISR_CMDC_TX_EN BIT(3)
+#define FSL_XCVR_ISR_HPD_TGL BIT(15)
+#define FSL_XCVR_ISR_DMAC_SPARE_INT BIT(19)
+#define FSL_XCVR_ISR_SET_SPDIF_RX_INT BIT(20)
+#define FSL_XCVR_ISR_SET_SPDIF_TX_INT BIT(21)
+#define FSL_XCVR_ISR_SET_SPDIF_MODE(t) (t ? BIT(21) : BIT(20))
+#define FSL_XCVR_ISR_SET_ARC_CM_INT BIT(22)
+#define FSL_XCVR_ISR_SET_ARC_SE_INT BIT(23)
+
+#define FSL_XCVR_PHY_AI_ADDR_MASK GENMASK(7, 0)
+#define FSL_XCVR_PHY_AI_RESETN BIT(15)
+#define FSL_XCVR_PHY_AI_TOG_PLL BIT(24)
+#define FSL_XCVR_PHY_AI_TOG_DONE_PLL BIT(25)
+#define FSL_XCVR_PHY_AI_TOG_PHY BIT(26)
+#define FSL_XCVR_PHY_AI_TOG_DONE_PHY BIT(27)
+#define FSL_XCVR_PHY_AI_RW_MASK BIT(31)
+
+#define FSL_XCVR_RX_DPTH_CTRL_PAPB_FIFO_STATUS BIT(0)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_PRE_ERR_CHK BIT(1)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_NOD_REC_CHK BIT(2)
+#define FSL_XCVR_RX_DPTH_CTRL_ECC_VUC_BIT_CHK BIT(3)
+#define FSL_XCVR_RX_DPTH_CTRL_EN_CMP_PAR_CALC BIT(4)
+#define FSL_XCVR_RX_DPTH_CTRL_RST_PKT_CNT_FIFO BIT(5)
+#define FSL_XCVR_RX_DPTH_CTRL_STORE_FMT BIT(6)
+#define FSL_XCVR_RX_DPTH_CTRL_EN_PAR_CALC BIT(7)
+#define FSL_XCVR_RX_DPTH_CTRL_UDR BIT(8)
+#define FSL_XCVR_RX_DPTH_CTRL_CSR BIT(9)
+#define FSL_XCVR_RX_DPTH_CTRL_UDA BIT(10)
+#define FSL_XCVR_RX_DPTH_CTRL_CSA BIT(11)
+#define FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO BIT(12)
+#define FSL_XCVR_RX_DPTH_CTRL_DIS_B_PRE_ERR_CHK BIT(13)
+#define FSL_XCVR_RX_DPTH_CTRL_PABS BIT(19)
+#define FSL_XCVR_RX_DPTH_CTRL_DTS_CDS BIT(20)
+#define FSL_XCVR_RX_DPTH_CTRL_BLKC BIT(21)
+#define FSL_XCVR_RX_DPTH_CTRL_MUTE_CTRL BIT(22)
+#define FSL_XCVR_RX_DPTH_CTRL_MUTE_MODE BIT(23)
+#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_CTRL BIT(24)
+#define FSL_XCVR_RX_DPTH_CTRL_FMT_CHG_MODE BIT(25)
+#define FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL BIT(26)
+#define FSL_XCVR_RX_DPTH_CTRL_LAYB_MODE BIT(27)
+#define FSL_XCVR_RX_DPTH_CTRL_PRC BIT(28)
+#define FSL_XCVR_RX_DPTH_CTRL_COMP BIT(29)
+#define FSL_XCVR_RX_DPTH_CTRL_FSM GENMASK(31, 30)
+
+#define FSL_XCVR_TX_DPTH_CTRL_CS_ACK BIT(0)
+#define FSL_XCVR_TX_DPTH_CTRL_UD_ACK BIT(1)
+#define FSL_XCVR_TX_DPTH_CTRL_CS_MOD BIT(2)
+#define FSL_XCVR_TX_DPTH_CTRL_UD_MOD BIT(3)
+#define FSL_XCVR_TX_DPTH_CTRL_VLD_MOD BIT(4)
+#define FSL_XCVR_TX_DPTH_CTRL_FRM_VLD BIT(5)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_PARITY BIT(6)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_PREAMBLE BIT(7)
+#define FSL_XCVR_TX_DPTH_CTRL_EN_ECC_INTER BIT(8)
+#define FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM BIT(10)
+#define FSL_XCVR_TX_DPTH_CTRL_FRM_FMT BIT(11)
+#define FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX BIT(14)
+#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_STR BIT(15)
+#define FSL_XCVR_TX_DPTH_CTRL_ADD_CYC_TX_OE_END BIT(16)
+#define FSL_XCVR_TX_DPTH_CTRL_CLK_RATIO BIT(29)
+#define FSL_XCVR_TX_DPTH_CTRL_TM_NO_PRE_BME GENMASK(31, 30)
+
+#define FSL_XCVR_PHY_AI_CTRL_AI_RESETN BIT(15)
+
+#define FSL_XCVR_PLL_CTRL0 0x00
+#define FSL_XCVR_PLL_CTRL0_SET 0x04
+#define FSL_XCVR_PLL_CTRL0_CLR 0x08
+#define FSL_XCVR_PLL_NUM 0x20
+#define FSL_XCVR_PLL_DEN 0x30
+#define FSL_XCVR_PLL_PDIV 0x40
+#define FSL_XCVR_PLL_BANDGAP_SET 0x54
+#define FSL_XCVR_PHY_CTRL 0x00
+#define FSL_XCVR_PHY_CTRL_SET 0x04
+#define FSL_XCVR_PHY_CTRL_CLR 0x08
+#define FSL_XCVR_PHY_CTRL2 0x70
+#define FSL_XCVR_PHY_CTRL2_SET 0x74
+#define FSL_XCVR_PHY_CTRL2_CLR 0x78
+
+#define FSL_XCVR_PLL_BANDGAP_EN_VBG BIT(0)
+#define FSL_XCVR_PLL_CTRL0_HROFF BIT(13)
+#define FSL_XCVR_PLL_CTRL0_PWP BIT(14)
+#define FSL_XCVR_PLL_CTRL0_CM0_EN BIT(24)
+#define FSL_XCVR_PLL_CTRL0_CM1_EN BIT(25)
+#define FSL_XCVR_PLL_CTRL0_CM2_EN BIT(26)
+#define FSL_XCVR_PLL_PDIVx(v, i) ((v & 0x7) << (4 * i))
+
+#define FSL_XCVR_PHY_CTRL_PHY_EN BIT(0)
+#define FSL_XCVR_PHY_CTRL_RX_CM_EN BIT(1)
+#define FSL_XCVR_PHY_CTRL_TSDIFF_OE BIT(5)
+#define FSL_XCVR_PHY_CTRL_SPDIF_EN BIT(8)
+#define FSL_XCVR_PHY_CTRL_ARC_MODE_SE_EN BIT(9)
+#define FSL_XCVR_PHY_CTRL_ARC_MODE_CM_EN BIT(10)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_MASK GENMASK(26, 25)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_HDMI_SS BIT(25)
+#define FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS BIT(26)
+#define FSL_XCVR_PHY_CTRL2_EARC_TXMS BIT(14)
+
+#define FSL_XCVR_CS_DATA_0_FS_MASK GENMASK(31, 24)
+#define FSL_XCVR_CS_DATA_0_FS_32000 0x3000000
+#define FSL_XCVR_CS_DATA_0_FS_44100 0x0000000
+#define FSL_XCVR_CS_DATA_0_FS_48000 0x2000000
+#define FSL_XCVR_CS_DATA_0_FS_64000 0xB000000
+#define FSL_XCVR_CS_DATA_0_FS_88200 0x8000000
+#define FSL_XCVR_CS_DATA_0_FS_96000 0xA000000
+#define FSL_XCVR_CS_DATA_0_FS_176400 0xC000000
+#define FSL_XCVR_CS_DATA_0_FS_192000 0xE000000
+
+#define FSL_XCVR_CS_DATA_0_CH_MASK 0x3A
+#define FSL_XCVR_CS_DATA_0_CH_U2LPCM 0x00
+#define FSL_XCVR_CS_DATA_0_CH_UMLPCM 0x20
+#define FSL_XCVR_CS_DATA_0_CH_U1BAUD 0x30
+
+#define FSL_XCVR_CS_DATA_1_CH_MASK 0xF000
+#define FSL_XCVR_CS_DATA_1_CH_2 0x0000
+#define FSL_XCVR_CS_DATA_1_CH_8 0x7000
+#define FSL_XCVR_CS_DATA_1_CH_16 0xB000
+#define FSL_XCVR_CS_DATA_1_CH_32 0x3000
+
+/* Data memory structures */
+#define FSL_XCVR_RX_CS_CTRL_0 0x20 /* First RX CS control register */
+#define FSL_XCVR_RX_CS_CTRL_1 0x24 /* Second RX CS control register */
+#define FSL_XCVR_RX_CS_BUFF_0 0x80 /* First RX CS buffer */
+#define FSL_XCVR_RX_CS_BUFF_1 0xA0 /* Second RX CS buffer */
+#define FSL_XCVR_CAP_DATA_STR 0x300 /* Capabilities data structure */
+
+#endif /* __FSL_XCVR_H */
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index 25c18b9e348f..dfa05d40b276 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -170,22 +170,9 @@ static enum imx_audmux_type {
IMX31_AUDMUX,
} audmux_type;
-static const struct platform_device_id imx_audmux_ids[] = {
- {
- .name = "imx21-audmux",
- .driver_data = IMX21_AUDMUX,
- }, {
- .name = "imx31-audmux",
- .driver_data = IMX31_AUDMUX,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, imx_audmux_ids);
-
static const struct of_device_id imx_audmux_dt_ids[] = {
- { .compatible = "fsl,imx21-audmux", .data = &imx_audmux_ids[0], },
- { .compatible = "fsl,imx31-audmux", .data = &imx_audmux_ids[1], },
+ { .compatible = "fsl,imx21-audmux", .data = (void *)IMX21_AUDMUX, },
+ { .compatible = "fsl,imx31-audmux", .data = (void *)IMX31_AUDMUX, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_audmux_dt_ids);
@@ -300,9 +287,6 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
static int imx_audmux_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id =
- of_match_device(imx_audmux_dt_ids, &pdev->dev);
-
audmux_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(audmux_base))
return PTR_ERR(audmux_base);
@@ -314,9 +298,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
audmux_clk = NULL;
}
- if (of_id)
- pdev->id_entry = of_id->data;
- audmux_type = pdev->id_entry->driver_data;
+ audmux_type = (enum imx_audmux_type)of_device_get_match_data(&pdev->dev);
switch (audmux_type) {
case IMX31_AUDMUX:
@@ -335,8 +317,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
if (!regcache)
return -ENOMEM;
- if (of_id)
- imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
+ imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
return 0;
}
@@ -386,7 +367,6 @@ static const struct dev_pm_ops imx_audmux_pm = {
static struct platform_driver imx_audmux_driver = {
.probe = imx_audmux_probe,
.remove = imx_audmux_remove,
- .id_table = imx_audmux_ids,
.driver = {
.name = DRIVER_NAME,
.pm = &imx_audmux_pm,
diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c
new file mode 100644
index 000000000000..2c2a76a71940
--- /dev/null
+++ b/sound/soc/fsl/imx-hdmi.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2017-2020 NXP
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/hdmi-codec.h>
+#include "fsl_sai.h"
+
+/**
+ * struct cpu_priv - CPU private data
+ * @sysclk_freq: SYSCLK rates for set_sysclk()
+ * @sysclk_dir: SYSCLK directions for set_sysclk()
+ * @sysclk_id: SYSCLK ids for set_sysclk()
+ * @slot_width: Slot width of each frame
+ *
+ * Note: [1] for tx and [0] for rx
+ */
+struct cpu_priv {
+ unsigned long sysclk_freq[2];
+ u32 sysclk_dir[2];
+ u32 sysclk_id[2];
+ u32 slot_width;
+};
+
+struct imx_hdmi_data {
+ struct snd_soc_dai_link dai;
+ struct snd_soc_card card;
+ struct snd_soc_jack hdmi_jack;
+ struct snd_soc_jack_pin hdmi_jack_pin;
+ struct cpu_priv cpu_priv;
+ u32 dai_fmt;
+};
+
+static int imx_hdmi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct imx_hdmi_data *data = snd_soc_card_get_drvdata(rtd->card);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_card *card = rtd->card;
+ struct device *dev = card->dev;
+ u32 slot_width = data->cpu_priv.slot_width;
+ int ret;
+
+ /* MCLK always is (256 or 192) * rate. */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, data->cpu_priv.sysclk_id[tx],
+ 8 * slot_width * params_rate(params),
+ tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set cpu sysclk: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0, 2, slot_width);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops imx_hdmi_ops = {
+ .hw_params = imx_hdmi_hw_params,
+};
+
+static const struct snd_soc_dapm_widget imx_hdmi_widgets[] = {
+ SND_SOC_DAPM_LINE("HDMI Jack", NULL),
+};
+
+static int imx_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_component *component = codec_dai->component;
+ struct imx_hdmi_data *data = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ data->hdmi_jack_pin.pin = "HDMI Jack";
+ data->hdmi_jack_pin.mask = SND_JACK_LINEOUT;
+ /* enable jack detection */
+ ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,
+ &data->hdmi_jack, &data->hdmi_jack_pin, 1);
+ if (ret) {
+ dev_err(card->dev, "Can't new HDMI Jack %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_component_set_jack(component, &data->hdmi_jack, NULL);
+ if (ret && ret != -EOPNOTSUPP) {
+ dev_err(card->dev, "Can't set HDMI Jack %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+};
+
+static int imx_hdmi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ bool hdmi_out = of_property_read_bool(np, "hdmi-out");
+ bool hdmi_in = of_property_read_bool(np, "hdmi-in");
+ struct snd_soc_dai_link_component *dlc;
+ struct platform_device *cpu_pdev;
+ struct device_node *cpu_np;
+ struct imx_hdmi_data *data;
+ int ret;
+
+ dlc = devm_kzalloc(&pdev->dev, 3 * sizeof(*dlc), GFP_KERNEL);
+ if (!dlc)
+ return -ENOMEM;
+
+ cpu_np = of_parse_phandle(np, "audio-cpu", 0);
+ if (!cpu_np) {
+ dev_err(&pdev->dev, "cpu dai phandle missing or invalid\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ cpu_pdev = of_find_device_by_node(cpu_np);
+ if (!cpu_pdev) {
+ dev_err(&pdev->dev, "failed to find SAI platform device\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ data->dai.cpus = &dlc[0];
+ data->dai.num_cpus = 1;
+ data->dai.platforms = &dlc[1];
+ data->dai.num_platforms = 1;
+ data->dai.codecs = &dlc[2];
+ data->dai.num_codecs = 1;
+
+ data->dai.name = "i.MX HDMI";
+ data->dai.stream_name = "i.MX HDMI";
+ data->dai.cpus->dai_name = dev_name(&cpu_pdev->dev);
+ data->dai.platforms->of_node = cpu_np;
+ data->dai.ops = &imx_hdmi_ops;
+ data->dai.playback_only = true;
+ data->dai.capture_only = false;
+ data->dai.init = imx_hdmi_init;
+
+ if (of_node_name_eq(cpu_np, "sai")) {
+ data->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
+ data->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
+ }
+
+ if (of_device_is_compatible(np, "fsl,imx-audio-sii902x")) {
+ data->dai_fmt = SND_SOC_DAIFMT_LEFT_J;
+ data->cpu_priv.slot_width = 24;
+ } else {
+ data->dai_fmt = SND_SOC_DAIFMT_I2S;
+ data->cpu_priv.slot_width = 32;
+ }
+
+ if ((hdmi_out && hdmi_in) || (!hdmi_out && !hdmi_in)) {
+ dev_err(&pdev->dev, "Invalid HDMI DAI link\n");
+ goto fail;
+ }
+
+ if (hdmi_out) {
+ data->dai.playback_only = true;
+ data->dai.capture_only = false;
+ data->dai.codecs->dai_name = "i2s-hifi";
+ data->dai.codecs->name = "hdmi-audio-codec.1";
+ data->dai.dai_fmt = data->dai_fmt |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS;
+ }
+
+ if (hdmi_in) {
+ data->dai.playback_only = false;
+ data->dai.capture_only = true;
+ data->dai.codecs->dai_name = "i2s-hifi";
+ data->dai.codecs->name = "hdmi-audio-codec.2";
+ data->dai.dai_fmt = data->dai_fmt |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+ }
+
+ data->card.dapm_widgets = imx_hdmi_widgets;
+ data->card.num_dapm_widgets = ARRAY_SIZE(imx_hdmi_widgets);
+ data->card.dev = &pdev->dev;
+ data->card.owner = THIS_MODULE;
+ ret = snd_soc_of_parse_card_name(&data->card, "model");
+ if (ret)
+ goto fail;
+
+ data->card.num_links = 1;
+ data->card.dai_link = &data->dai;
+
+ snd_soc_card_set_drvdata(&data->card, data);
+ ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ goto fail;
+ }
+
+fail:
+ if (cpu_np)
+ of_node_put(cpu_np);
+
+ return ret;
+}
+
+static const struct of_device_id imx_hdmi_dt_ids[] = {
+ { .compatible = "fsl,imx-audio-hdmi", },
+ { .compatible = "fsl,imx-audio-sii902x", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
+
+static struct platform_driver imx_hdmi_driver = {
+ .driver = {
+ .name = "imx-hdmi",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = imx_hdmi_dt_ids,
+ },
+ .probe = imx_hdmi_probe,
+};
+module_platform_driver(imx_hdmi_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale i.MX hdmi audio ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-hdmi");
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
deleted file mode 100644
index d9dca7bbcae3..000000000000
--- a/sound/soc/fsl/imx-mc13783.c
+++ /dev/null
@@ -1,156 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// imx-mc13783.c -- SoC audio for imx based boards with mc13783 codec
-//
-// Copyright 2012 Philippe Retornaz, <philippe.retornaz@epfl.ch>
-//
-// Heavly based on phycore-mc13783:
-// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <asm/mach-types.h>
-
-#include "../codecs/mc13783.h"
-#include "imx-ssi.h"
-#include "imx-audmux.h"
-
-#define FMT_SSI (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
- SND_SOC_DAIFMT_CBM_CFM)
-
-static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- int ret;
-
- ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 4, 16);
- if (ret)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, MC13783_CLK_CLIA, 26000000, 0);
- if (ret)
- return ret;
-
- return snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16);
-}
-
-static const struct snd_soc_ops imx_mc13783_hifi_ops = {
- .hw_params = imx_mc13783_hifi_hw_params,
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
- DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
- DAILINK_COMP_ARRAY(COMP_CODEC("mc13783-codec", "mc13783-hifi")),
- DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = {
- {
- .name = "MC13783",
- .stream_name = "Sound",
- .ops = &imx_mc13783_hifi_ops,
- .symmetric_rates = 1,
- .dai_fmt = FMT_SSI,
- SND_SOC_DAILINK_REG(hifi),
- },
-};
-
-static const struct snd_soc_dapm_widget imx_mc13783_widget[] = {
- SND_SOC_DAPM_MIC("Mic", NULL),
- SND_SOC_DAPM_HP("Headphone", NULL),
- SND_SOC_DAPM_SPK("Speaker", NULL),
-};
-
-static const struct snd_soc_dapm_route imx_mc13783_routes[] = {
- {"Speaker", NULL, "LSP"},
- {"Headphone", NULL, "HSL"},
- {"Headphone", NULL, "HSR"},
-
- {"MC1LIN", NULL, "MC1 Bias"},
- {"MC2IN", NULL, "MC2 Bias"},
- {"MC1 Bias", NULL, "Mic"},
- {"MC2 Bias", NULL, "Mic"},
-};
-
-static struct snd_soc_card imx_mc13783 = {
- .name = "imx_mc13783",
- .owner = THIS_MODULE,
- .dai_link = imx_mc13783_dai_mc13783,
- .num_links = ARRAY_SIZE(imx_mc13783_dai_mc13783),
- .dapm_widgets = imx_mc13783_widget,
- .num_dapm_widgets = ARRAY_SIZE(imx_mc13783_widget),
- .dapm_routes = imx_mc13783_routes,
- .num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes),
-};
-
-static int imx_mc13783_probe(struct platform_device *pdev)
-{
- int ret;
-
- imx_mc13783.dev = &pdev->dev;
-
- ret = devm_snd_soc_register_card(&pdev->dev, &imx_mc13783);
- if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
- ret);
- return ret;
- }
-
- if (machine_is_mx31_3ds() || machine_is_mx31moboard()) {
- imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
- IMX_AUDMUX_V2_PTCR_SYN,
- IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
- IMX_AUDMUX_V2_PDCR_MODE(1) |
- IMX_AUDMUX_V2_PDCR_INMMASK(0xfc));
- imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
- IMX_AUDMUX_V2_PTCR_SYN |
- IMX_AUDMUX_V2_PTCR_TFSDIR |
- IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
- IMX_AUDMUX_V2_PTCR_TCLKDIR |
- IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
- IMX_AUDMUX_V2_PTCR_RFSDIR |
- IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
- IMX_AUDMUX_V2_PTCR_RCLKDIR |
- IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4),
- IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4));
- } else if (machine_is_mx27_3ds()) {
- imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
- IMX_AUDMUX_V1_PCR_SYN |
- IMX_AUDMUX_V1_PCR_TFSDIR |
- IMX_AUDMUX_V1_PCR_TCLKDIR |
- IMX_AUDMUX_V1_PCR_RFSDIR |
- IMX_AUDMUX_V1_PCR_RCLKDIR |
- IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
- IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
- IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
- );
- imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
- IMX_AUDMUX_V1_PCR_SYN |
- IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
- );
- }
-
- return ret;
-}
-
-static struct platform_driver imx_mc13783_audio_driver = {
- .driver = {
- .name = "imx_mc13783",
- },
- .probe = imx_mc13783_probe,
-};
-
-module_platform_driver(imx_mc13783_audio_driver);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch");
-MODULE_DESCRIPTION("imx with mc13783 codec ALSA SoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx_mc13783");
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
deleted file mode 100644
index f8488e8f5f5b..000000000000
--- a/sound/soc/fsl/imx-ssi.c
+++ /dev/null
@@ -1,651 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// imx-ssi.c -- ALSA Soc Audio Layer
-//
-// Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
-//
-// This code is based on code copyrighted by Freescale,
-// Liam Girdwood, Javier Martin and probably others.
-//
-// The i.MX SSI core has some nasty limitations in AC97 mode. While most
-// sane processor vendors have a FIFO per AC97 slot, the i.MX has only
-// one FIFO which combines all valid receive slots. We cannot even select
-// which slots we want to receive. The WM9712 with which this driver
-// was developed with always sends GPIO status data in slot 12 which
-// we receive in our (PCM-) data stream. The only chance we have is to
-// manually skip this data in the FIQ handler. With sampling rates different
-// from 48000Hz not every frame has valid receive data, so the ratio
-// between pcm data and GPIO status data changes. Our FIQ handler is not
-// able to handle this, hence this driver only works with 48000Hz sampling
-// rate.
-// Reading and writing AC97 registers is another challenge. The core
-// provides us status bits when the read register is updated with *another*
-// value. When we read the same register two times (and the register still
-// contains the same value) these status bits are not set. We work
-// around this by not polling these bits but only wait a fixed delay.
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <linux/platform_data/asoc-imx-ssi.h>
-
-#include "imx-ssi.h"
-#include "fsl_utils.h"
-
-#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
-
-/*
- * SSI Network Mode or TDM slots configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
- unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
-{
- struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
- u32 sccr;
-
- sccr = readl(ssi->base + SSI_STCCR);
- sccr &= ~SSI_STCCR_DC_MASK;
- sccr |= SSI_STCCR_DC(slots - 1);
- writel(sccr, ssi->base + SSI_STCCR);
-
- sccr = readl(ssi->base + SSI_SRCCR);
- sccr &= ~SSI_STCCR_DC_MASK;
- sccr |= SSI_STCCR_DC(slots - 1);
- writel(sccr, ssi->base + SSI_SRCCR);
-
- writel(~tx_mask, ssi->base + SSI_STMSK);
- writel(~rx_mask, ssi->base + SSI_SRMSK);
-
- return 0;
-}
-
-/*
- * SSI DAI format configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
-{
- struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
- u32 strcr = 0, scr;
-
- scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
-
- /* DAI mode */
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- /* data on rising edge of bclk, frame low 1clk before data */
- strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSI |
- SSI_STCR_TEFS;
- scr |= SSI_SCR_NET;
- if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
- scr &= ~SSI_I2S_MODE_MASK;
- scr |= SSI_SCR_I2S_MODE_SLAVE;
- }
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- /* data on rising edge of bclk, frame high with data */
- strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP;
- break;
- case SND_SOC_DAIFMT_DSP_B:
- /* data on rising edge of bclk, frame high with data */
- strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL;
- break;
- case SND_SOC_DAIFMT_DSP_A:
- /* data on rising edge of bclk, frame high 1clk before data */
- strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP | SSI_STCR_TFSL |
- SSI_STCR_TEFS;
- break;
- }
-
- /* DAI clock inversion */
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_IB_IF:
- strcr ^= SSI_STCR_TSCKP | SSI_STCR_TFSI;
- break;
- case SND_SOC_DAIFMT_IB_NF:
- strcr ^= SSI_STCR_TSCKP;
- break;
- case SND_SOC_DAIFMT_NB_IF:
- strcr ^= SSI_STCR_TFSI;
- break;
- case SND_SOC_DAIFMT_NB_NF:
- break;
- }
-
- /* DAI clock master masks */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- break;
- default:
- /* Master mode not implemented, needs handling of clocks. */
- return -EINVAL;
- }
-
- strcr |= SSI_STCR_TFEN0;
-
- if (ssi->flags & IMX_SSI_NET)
- scr |= SSI_SCR_NET;
- if (ssi->flags & IMX_SSI_SYN)
- scr |= SSI_SCR_SYN;
-
- writel(strcr, ssi->base + SSI_STCR);
- writel(strcr, ssi->base + SSI_SRCR);
- writel(scr, ssi->base + SSI_SCR);
-
- return 0;
-}
-
-/*
- * SSI system clock configuration.
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
- u32 scr;
-
- scr = readl(ssi->base + SSI_SCR);
-
- switch (clk_id) {
- case IMX_SSP_SYS_CLK:
- if (dir == SND_SOC_CLOCK_OUT)
- scr |= SSI_SCR_SYS_CLK_EN;
- else
- scr &= ~SSI_SCR_SYS_CLK_EN;
- break;
- default:
- return -EINVAL;
- }
-
- writel(scr, ssi->base + SSI_SCR);
-
- return 0;
-}
-
-/*
- * SSI Clock dividers
- * Should only be called when port is inactive (i.e. SSIEN = 0).
- */
-static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
- int div_id, int div)
-{
- struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
- u32 stccr, srccr;
-
- stccr = readl(ssi->base + SSI_STCCR);
- srccr = readl(ssi->base + SSI_SRCCR);
-
- switch (div_id) {
- case IMX_SSI_TX_DIV_2:
- stccr &= ~SSI_STCCR_DIV2;
- stccr |= div;
- break;
- case IMX_SSI_TX_DIV_PSR:
- stccr &= ~SSI_STCCR_PSR;
- stccr |= div;
- break;
- case IMX_SSI_TX_DIV_PM:
- stccr &= ~0xff;
- stccr |= SSI_STCCR_PM(div);
- break;
- case IMX_SSI_RX_DIV_2:
- stccr &= ~SSI_STCCR_DIV2;
- stccr |= div;
- break;
- case IMX_SSI_RX_DIV_PSR:
- stccr &= ~SSI_STCCR_PSR;
- stccr |= div;
- break;
- case IMX_SSI_RX_DIV_PM:
- stccr &= ~0xff;
- stccr |= SSI_STCCR_PM(div);
- break;
- default:
- return -EINVAL;
- }
-
- writel(stccr, ssi->base + SSI_STCCR);
- writel(srccr, ssi->base + SSI_SRCCR);
-
- return 0;
-}
-
-/*
- * Should only be called when port is inactive (i.e. SSIEN = 0),
- * although can be called multiple times by upper layers.
- */
-static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *cpu_dai)
-{
- struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
- u32 reg, sccr;
-
- /* Tx/Rx config */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- reg = SSI_STCCR;
- else
- reg = SSI_SRCCR;
-
- if (ssi->flags & IMX_SSI_SYN)
- reg = SSI_STCCR;
-
- sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
-
- /* DAI data (word) size */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- sccr |= SSI_SRCCR_WL(16);
- break;
- case SNDRV_PCM_FORMAT_S20_3LE:
- sccr |= SSI_SRCCR_WL(20);
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- sccr |= SSI_SRCCR_WL(24);
- break;
- }
-
- writel(sccr, ssi->base + reg);
-
- return 0;
-}
-
-static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
- unsigned int sier_bits, sier;
- unsigned int scr;
-
- scr = readl(ssi->base + SSI_SCR);
- sier = readl(ssi->base + SSI_SIER);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (ssi->flags & IMX_SSI_DMA)
- sier_bits = SSI_SIER_TDMAE;
- else
- sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
- } else {
- if (ssi->flags & IMX_SSI_DMA)
- sier_bits = SSI_SIER_RDMAE;
- else
- sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
- }
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- scr |= SSI_SCR_TE;
- else
- scr |= SSI_SCR_RE;
- sier |= sier_bits;
-
- scr |= SSI_SCR_SSIEN;
-
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- scr &= ~SSI_SCR_TE;
- else
- scr &= ~SSI_SCR_RE;
- sier &= ~sier_bits;
-
- if (!(scr & (SSI_SCR_TE | SSI_SCR_RE)))
- scr &= ~SSI_SCR_SSIEN;
-
- break;
- default:
- return -EINVAL;
- }
-
- if (!(ssi->flags & IMX_SSI_USE_AC97))
- /* rx/tx are always enabled to access ac97 registers */
- writel(scr, ssi->base + SSI_SCR);
-
- writel(sier, ssi->base + SSI_SIER);
-
- return 0;
-}
-
-static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
- .hw_params = imx_ssi_hw_params,
- .set_fmt = imx_ssi_set_dai_fmt,
- .set_clkdiv = imx_ssi_set_dai_clkdiv,
- .set_sysclk = imx_ssi_set_dai_sysclk,
- .set_tdm_slot = imx_ssi_set_dai_tdm_slot,
- .trigger = imx_ssi_trigger,
-};
-
-static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
-{
- struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
- uint32_t val;
-
- snd_soc_dai_set_drvdata(dai, ssi);
-
- val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
- SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
- writel(val, ssi->base + SSI_SFCSR);
-
- /* Tx/Rx config */
- dai->playback_dma_data = &ssi->dma_params_tx;
- dai->capture_dma_data = &ssi->dma_params_rx;
-
- return 0;
-}
-
-static struct snd_soc_dai_driver imx_ssi_dai = {
- .probe = imx_ssi_dai_probe,
- .playback = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .ops = &imx_ssi_pcm_dai_ops,
-};
-
-static struct snd_soc_dai_driver imx_ac97_dai = {
- .probe = imx_ssi_dai_probe,
- .playback = {
- .stream_name = "AC97 Playback",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .stream_name = "AC97 Capture",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .ops = &imx_ssi_pcm_dai_ops,
-};
-
-static const struct snd_soc_component_driver imx_component = {
- .name = DRV_NAME,
-};
-
-static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
-{
- void __iomem *base = imx_ssi->base;
-
- writel(0x0, base + SSI_SCR);
- writel(0x0, base + SSI_STCR);
- writel(0x0, base + SSI_SRCR);
-
- writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
-
- writel(SSI_SFCSR_RFWM0(8) |
- SSI_SFCSR_TFWM0(8) |
- SSI_SFCSR_RFWM1(8) |
- SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
-
- writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
- writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
-
- writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
- writel(SSI_SOR_WAIT(3), base + SSI_SOR);
-
- writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
- SSI_SCR_TE | SSI_SCR_RE,
- base + SSI_SCR);
-
- writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
- writel(0xff, base + SSI_SACCDIS);
- writel(0x300, base + SSI_SACCEN);
-}
-
-static struct imx_ssi *ac97_ssi;
-
-static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
- unsigned short val)
-{
- struct imx_ssi *imx_ssi = ac97_ssi;
- void __iomem *base = imx_ssi->base;
- unsigned int lreg;
- unsigned int lval;
-
- if (reg > 0x7f)
- return;
-
- pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
-
- lreg = reg << 12;
- writel(lreg, base + SSI_SACADD);
-
- lval = val << 4;
- writel(lval , base + SSI_SACDAT);
-
- writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
- udelay(100);
-}
-
-static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
- unsigned short reg)
-{
- struct imx_ssi *imx_ssi = ac97_ssi;
- void __iomem *base = imx_ssi->base;
-
- unsigned short val = -1;
- unsigned int lreg;
-
- lreg = (reg & 0x7f) << 12 ;
- writel(lreg, base + SSI_SACADD);
- writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
-
- udelay(100);
-
- val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
-
- pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
-
- return val;
-}
-
-static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
-{
- struct imx_ssi *imx_ssi = ac97_ssi;
-
- if (imx_ssi->ac97_reset)
- imx_ssi->ac97_reset(ac97);
- /* First read sometimes fails, do a dummy read */
- imx_ssi_ac97_read(ac97, 0);
-}
-
-static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
-{
- struct imx_ssi *imx_ssi = ac97_ssi;
-
- if (imx_ssi->ac97_warm_reset)
- imx_ssi->ac97_warm_reset(ac97);
-
- /* First read sometimes fails, do a dummy read */
- imx_ssi_ac97_read(ac97, 0);
-}
-
-static struct snd_ac97_bus_ops imx_ssi_ac97_ops = {
- .read = imx_ssi_ac97_read,
- .write = imx_ssi_ac97_write,
- .reset = imx_ssi_ac97_reset,
- .warm_reset = imx_ssi_ac97_warm_reset
-};
-
-static int imx_ssi_probe(struct platform_device *pdev)
-{
- struct resource *res;
- struct imx_ssi *ssi;
- struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
- int ret = 0;
- struct snd_soc_dai_driver *dai;
-
- ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
- if (!ssi)
- return -ENOMEM;
- dev_set_drvdata(&pdev->dev, ssi);
-
- if (pdata) {
- ssi->ac97_reset = pdata->ac97_reset;
- ssi->ac97_warm_reset = pdata->ac97_warm_reset;
- ssi->flags = pdata->flags;
- }
-
- ssi->irq = platform_get_irq(pdev, 0);
- if (ssi->irq < 0)
- return ssi->irq;
-
- ssi->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(ssi->clk)) {
- ret = PTR_ERR(ssi->clk);
- dev_err(&pdev->dev, "Cannot get the clock: %d\n",
- ret);
- goto failed_clk;
- }
- ret = clk_prepare_enable(ssi->clk);
- if (ret)
- goto failed_clk;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ssi->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ssi->base)) {
- ret = PTR_ERR(ssi->base);
- goto failed_register;
- }
-
- if (ssi->flags & IMX_SSI_USE_AC97) {
- if (ac97_ssi) {
- dev_err(&pdev->dev, "AC'97 SSI already registered\n");
- ret = -EBUSY;
- goto failed_register;
- }
- ac97_ssi = ssi;
- setup_channel_to_ac97(ssi);
- dai = &imx_ac97_dai;
- } else
- dai = &imx_ssi_dai;
-
- writel(0x0, ssi->base + SSI_SIER);
-
- ssi->dma_params_rx.addr = res->start + SSI_SRX0;
- ssi->dma_params_tx.addr = res->start + SSI_STX0;
-
- ssi->dma_params_tx.maxburst = 6;
- ssi->dma_params_rx.maxburst = 4;
-
- ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
- ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
- if (res) {
- imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
- IMX_DMATYPE_SSI);
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
- if (res) {
- imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
- IMX_DMATYPE_SSI);
- }
-
- platform_set_drvdata(pdev, ssi);
-
- ret = snd_soc_set_ac97_ops(&imx_ssi_ac97_ops);
- if (ret != 0) {
- dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
- goto failed_register;
- }
-
- ret = snd_soc_register_component(&pdev->dev, &imx_component,
- dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "register DAI failed\n");
- goto failed_register;
- }
-
- ssi->fiq_params.irq = ssi->irq;
- ssi->fiq_params.base = ssi->base;
- ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
- ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
-
- ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
- ssi->dma_init = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE);
-
- if (ssi->fiq_init && ssi->dma_init) {
- ret = ssi->fiq_init;
- goto failed_pcm;
- }
-
- return 0;
-
-failed_pcm:
- snd_soc_unregister_component(&pdev->dev);
-failed_register:
- clk_disable_unprepare(ssi->clk);
-failed_clk:
- snd_soc_set_ac97_ops(NULL);
-
- return ret;
-}
-
-static int imx_ssi_remove(struct platform_device *pdev)
-{
- struct imx_ssi *ssi = platform_get_drvdata(pdev);
-
- if (!ssi->fiq_init)
- imx_pcm_fiq_exit(pdev);
-
- snd_soc_unregister_component(&pdev->dev);
-
- if (ssi->flags & IMX_SSI_USE_AC97)
- ac97_ssi = NULL;
-
- clk_disable_unprepare(ssi->clk);
- snd_soc_set_ac97_ops(NULL);
-
- return 0;
-}
-
-static struct platform_driver imx_ssi_driver = {
- .probe = imx_ssi_probe,
- .remove = imx_ssi_remove,
-
- .driver = {
- .name = "imx-ssi",
- },
-};
-
-module_platform_driver(imx_ssi_driver);
-
-/* Module information */
-MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-ssi");
diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c
deleted file mode 100644
index 8d3b1897370b..000000000000
--- a/sound/soc/fsl/mx27vis-aic32x4.c
+++ /dev/null
@@ -1,214 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// mx27vis-aic32x4.c
-//
-// Copyright 2011 Vista Silicon S.L.
-//
-// Author: Javier Martin <javier.martin@vista-silicon.com>
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/asoc-mx27vis.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-#include <asm/mach-types.h>
-
-#include "../codecs/tlv320aic32x4.h"
-#include "imx-ssi.h"
-#include "imx-audmux.h"
-
-#define MX27VIS_AMP_GAIN 0
-#define MX27VIS_AMP_MUTE 1
-
-static int mx27vis_amp_gain;
-static int mx27vis_amp_mute;
-static int mx27vis_amp_gain0_gpio;
-static int mx27vis_amp_gain1_gpio;
-static int mx27vis_amp_mutel_gpio;
-static int mx27vis_amp_muter_gpio;
-
-static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- int ret;
-
- ret = snd_soc_dai_set_sysclk(codec_dai, 0,
- 25000000, SND_SOC_CLOCK_OUT);
- if (ret) {
- pr_err("%s: failed setting codec sysclk\n", __func__);
- return ret;
- }
-
- ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
- SND_SOC_CLOCK_IN);
- if (ret) {
- pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct snd_soc_ops mx27vis_aic32x4_snd_ops = {
- .hw_params = mx27vis_aic32x4_hw_params,
-};
-
-static int mx27vis_amp_set(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int value = ucontrol->value.integer.value[0];
- unsigned int reg = mc->reg;
- int max = mc->max;
-
- if (value > max)
- return -EINVAL;
-
- switch (reg) {
- case MX27VIS_AMP_GAIN:
- gpio_set_value(mx27vis_amp_gain0_gpio, value & 1);
- gpio_set_value(mx27vis_amp_gain1_gpio, value >> 1);
- mx27vis_amp_gain = value;
- break;
- case MX27VIS_AMP_MUTE:
- gpio_set_value(mx27vis_amp_mutel_gpio, value & 1);
- gpio_set_value(mx27vis_amp_muter_gpio, value >> 1);
- mx27vis_amp_mute = value;
- break;
- }
- return 0;
-}
-
-static int mx27vis_amp_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
-
- switch (reg) {
- case MX27VIS_AMP_GAIN:
- ucontrol->value.integer.value[0] = mx27vis_amp_gain;
- break;
- case MX27VIS_AMP_MUTE:
- ucontrol->value.integer.value[0] = mx27vis_amp_mute;
- break;
- }
- return 0;
-}
-
-/* From 6dB to 24dB in steps of 6dB */
-static const DECLARE_TLV_DB_SCALE(mx27vis_amp_tlv, 600, 600, 0);
-
-static const struct snd_kcontrol_new mx27vis_aic32x4_controls[] = {
- SOC_DAPM_PIN_SWITCH("External Mic"),
- SOC_SINGLE_EXT_TLV("LO Ext Boost", MX27VIS_AMP_GAIN, 0, 3, 0,
- mx27vis_amp_get, mx27vis_amp_set, mx27vis_amp_tlv),
- SOC_DOUBLE_EXT("LO Ext Mute Switch", MX27VIS_AMP_MUTE, 0, 1, 1, 0,
- mx27vis_amp_get, mx27vis_amp_set),
-};
-
-static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
- SND_SOC_DAPM_MIC("External Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
- {"Mic Bias", NULL, "External Mic"},
- {"IN1_R", NULL, "Mic Bias"},
- {"IN2_R", NULL, "Mic Bias"},
- {"IN3_R", NULL, "Mic Bias"},
- {"IN1_L", NULL, "Mic Bias"},
- {"IN2_L", NULL, "Mic Bias"},
- {"IN3_L", NULL, "Mic Bias"},
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
- DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
- DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic32x4.0-0018",
- "tlv320aic32x4-hifi")),
- DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
- .name = "tlv320aic32x4",
- .stream_name = "TLV320AIC32X4",
- .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- .ops = &mx27vis_aic32x4_snd_ops,
- SND_SOC_DAILINK_REG(hifi),
-};
-
-static struct snd_soc_card mx27vis_aic32x4 = {
- .name = "visstrim_m10-audio",
- .owner = THIS_MODULE,
- .dai_link = &mx27vis_aic32x4_dai,
- .num_links = 1,
- .controls = mx27vis_aic32x4_controls,
- .num_controls = ARRAY_SIZE(mx27vis_aic32x4_controls),
- .dapm_widgets = aic32x4_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets),
- .dapm_routes = aic32x4_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
-};
-
-static int mx27vis_aic32x4_probe(struct platform_device *pdev)
-{
- struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data;
- int ret;
-
- if (!pdata) {
- dev_err(&pdev->dev, "No platform data supplied\n");
- return -EINVAL;
- }
-
- mx27vis_amp_gain0_gpio = pdata->amp_gain0_gpio;
- mx27vis_amp_gain1_gpio = pdata->amp_gain1_gpio;
- mx27vis_amp_mutel_gpio = pdata->amp_mutel_gpio;
- mx27vis_amp_muter_gpio = pdata->amp_muter_gpio;
-
- mx27vis_aic32x4.dev = &pdev->dev;
- ret = devm_snd_soc_register_card(&pdev->dev, &mx27vis_aic32x4);
- if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
- ret);
- return ret;
- }
-
- /* Connect SSI0 as clock slave to SSI1 external pins */
- imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
- IMX_AUDMUX_V1_PCR_SYN |
- IMX_AUDMUX_V1_PCR_TFSDIR |
- IMX_AUDMUX_V1_PCR_TCLKDIR |
- IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) |
- IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1)
- );
- imx_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1,
- IMX_AUDMUX_V1_PCR_SYN |
- IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
- );
-
- return ret;
-}
-
-static struct platform_driver mx27vis_aic32x4_audio_driver = {
- .driver = {
- .name = "mx27vis",
- },
- .probe = mx27vis_aic32x4_probe,
-};
-
-module_platform_driver(mx27vis_aic32x4_audio_driver);
-
-MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
-MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mx27vis");
diff --git a/sound/soc/fsl/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c
deleted file mode 100644
index e561f7ff1699..000000000000
--- a/sound/soc/fsl/phycore-ac97.c
+++ /dev/null
@@ -1,121 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// phycore-ac97.c -- SoC audio for imx_phycore in AC97 mode
-//
-// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/mach-types.h>
-
-#include "imx-audmux.h"
-
-static struct snd_soc_card imx_phycore;
-
-static const struct snd_soc_ops imx_phycore_hifi_ops = {
-};
-
-SND_SOC_DAILINK_DEFS(hifi,
- DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
- DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
- DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
- {
- .name = "HiFi",
- .stream_name = "HiFi",
- .ops = &imx_phycore_hifi_ops,
- SND_SOC_DAILINK_REG(hifi),
- },
-};
-
-static struct snd_soc_card imx_phycore = {
- .name = "PhyCORE-ac97-audio",
- .owner = THIS_MODULE,
- .dai_link = imx_phycore_dai_ac97,
- .num_links = ARRAY_SIZE(imx_phycore_dai_ac97),
-};
-
-static struct platform_device *imx_phycore_snd_ac97_device;
-static struct platform_device *imx_phycore_snd_device;
-
-static int __init imx_phycore_init(void)
-{
- int ret;
-
- if (machine_is_pca100()) {
- imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
- IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
- IMX_AUDMUX_V1_PCR_TFCSEL(3) |
- IMX_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */
- IMX_AUDMUX_V1_PCR_RXDSEL(3));
- imx_audmux_v1_configure_port(3,
- IMX_AUDMUX_V1_PCR_SYN | /* 4wire mode */
- IMX_AUDMUX_V1_PCR_TFCSEL(0) |
- IMX_AUDMUX_V1_PCR_TFSDIR |
- IMX_AUDMUX_V1_PCR_RXDSEL(0));
- } else if (machine_is_pcm043()) {
- imx_audmux_v2_configure_port(3,
- IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
- IMX_AUDMUX_V2_PTCR_TFSEL(0) |
- IMX_AUDMUX_V2_PTCR_TFSDIR,
- IMX_AUDMUX_V2_PDCR_RXDSEL(0));
- imx_audmux_v2_configure_port(0,
- IMX_AUDMUX_V2_PTCR_SYN | /* 4wire mode */
- IMX_AUDMUX_V2_PTCR_TCSEL(3) |
- IMX_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
- IMX_AUDMUX_V2_PDCR_RXDSEL(3));
- } else {
- /* return happy. We might run on a totally different machine */
- return 0;
- }
-
- imx_phycore_snd_ac97_device = platform_device_alloc("soc-audio", -1);
- if (!imx_phycore_snd_ac97_device)
- return -ENOMEM;
-
- platform_set_drvdata(imx_phycore_snd_ac97_device, &imx_phycore);
- ret = platform_device_add(imx_phycore_snd_ac97_device);
- if (ret)
- goto fail1;
-
- imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1);
- if (!imx_phycore_snd_device) {
- ret = -ENOMEM;
- goto fail2;
- }
- ret = platform_device_add(imx_phycore_snd_device);
-
- if (ret) {
- printk(KERN_ERR "ASoC: Platform device allocation failed\n");
- goto fail3;
- }
-
- return 0;
-
-fail3:
- platform_device_put(imx_phycore_snd_device);
-fail2:
- platform_device_del(imx_phycore_snd_ac97_device);
-fail1:
- platform_device_put(imx_phycore_snd_ac97_device);
- return ret;
-}
-
-static void __exit imx_phycore_exit(void)
-{
- platform_device_unregister(imx_phycore_snd_device);
- platform_device_unregister(imx_phycore_snd_ac97_device);
-}
-
-late_initcall(imx_phycore_init);
-module_exit(imx_phycore_exit);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("PhyCORE ALSA SoC driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
deleted file mode 100644
index 99611a037ada..000000000000
--- a/sound/soc/fsl/wm1133-ev1.c
+++ /dev/null
@@ -1,289 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// wm1133-ev1.c - Audio for WM1133-EV1 on i.MX31ADS
-//
-// Copyright (c) 2010 Wolfson Microelectronics plc
-// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
-//
-// Based on an earlier driver for the same hardware by Liam Girdwood.
-
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "imx-ssi.h"
-#include "../codecs/wm8350.h"
-#include "imx-audmux.h"
-
-/* There is a silicon mic on the board optionally connected via a solder pad
- * SP1. Define this to enable it.
- */
-#undef USE_SIMIC
-
-struct _wm8350_audio {
- unsigned int channels;
- snd_pcm_format_t format;
- unsigned int rate;
- unsigned int sysclk;
- unsigned int bclkdiv;
- unsigned int clkdiv;
- unsigned int lr_rate;
-};
-
-/* in order of power consumption per rate (lowest first) */
-static const struct _wm8350_audio wm8350_audio[] = {
- /* 16bit mono modes */
- {1, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000 >> 1,
- WM8350_BCLK_DIV_48, WM8350_DACDIV_3, 16,},
-
- /* 16 bit stereo modes */
- {2, SNDRV_PCM_FORMAT_S16_LE, 8000, 12288000,
- WM8350_BCLK_DIV_48, WM8350_DACDIV_6, 32,},
- {2, SNDRV_PCM_FORMAT_S16_LE, 16000, 12288000,
- WM8350_BCLK_DIV_24, WM8350_DACDIV_3, 32,},
- {2, SNDRV_PCM_FORMAT_S16_LE, 32000, 12288000,
- WM8350_BCLK_DIV_12, WM8350_DACDIV_1_5, 32,},
- {2, SNDRV_PCM_FORMAT_S16_LE, 48000, 12288000,
- WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
- {2, SNDRV_PCM_FORMAT_S16_LE, 96000, 24576000,
- WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
- {2, SNDRV_PCM_FORMAT_S16_LE, 11025, 11289600,
- WM8350_BCLK_DIV_32, WM8350_DACDIV_4, 32,},
- {2, SNDRV_PCM_FORMAT_S16_LE, 22050, 11289600,
- WM8350_BCLK_DIV_16, WM8350_DACDIV_2, 32,},
- {2, SNDRV_PCM_FORMAT_S16_LE, 44100, 11289600,
- WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
- {2, SNDRV_PCM_FORMAT_S16_LE, 88200, 22579200,
- WM8350_BCLK_DIV_8, WM8350_DACDIV_1, 32,},
-
- /* 24bit stereo modes */
- {2, SNDRV_PCM_FORMAT_S24_LE, 48000, 12288000,
- WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
- {2, SNDRV_PCM_FORMAT_S24_LE, 96000, 24576000,
- WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
- {2, SNDRV_PCM_FORMAT_S24_LE, 44100, 11289600,
- WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
- {2, SNDRV_PCM_FORMAT_S24_LE, 88200, 22579200,
- WM8350_BCLK_DIV_4, WM8350_DACDIV_1, 64,},
-};
-
-static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
- struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
- int i, found = 0;
- snd_pcm_format_t format = params_format(params);
- unsigned int rate = params_rate(params);
- unsigned int channels = params_channels(params);
-
- /* find the correct audio parameters */
- for (i = 0; i < ARRAY_SIZE(wm8350_audio); i++) {
- if (rate == wm8350_audio[i].rate &&
- format == wm8350_audio[i].format &&
- channels == wm8350_audio[i].channels) {
- found = 1;
- break;
- }
- }
- if (!found)
- return -EINVAL;
-
- /* codec FLL input is 14.75 MHz from MCLK */
- snd_soc_dai_set_pll(codec_dai, 0, 0, 14750000, wm8350_audio[i].sysclk);
-
- /* TODO: The SSI driver should figure this out for us */
- switch (channels) {
- case 2:
- snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0);
- break;
- case 1:
- snd_soc_dai_set_tdm_slot(cpu_dai, 0x1, 0x1, 1, 0);
- break;
- default:
- return -EINVAL;
- }
-
- /* set MCLK as the codec system clock for DAC and ADC */
- snd_soc_dai_set_sysclk(codec_dai, WM8350_MCLK_SEL_PLL_MCLK,
- wm8350_audio[i].sysclk, SND_SOC_CLOCK_IN);
-
- /* set codec BCLK division for sample rate */
- snd_soc_dai_set_clkdiv(codec_dai, WM8350_BCLK_CLKDIV,
- wm8350_audio[i].bclkdiv);
-
- /* DAI is synchronous and clocked with DAC LRCLK & ADC LRC */
- snd_soc_dai_set_clkdiv(codec_dai,
- WM8350_DACLR_CLKDIV, wm8350_audio[i].lr_rate);
- snd_soc_dai_set_clkdiv(codec_dai,
- WM8350_ADCLR_CLKDIV, wm8350_audio[i].lr_rate);
-
- /* now configure DAC and ADC clocks */
- snd_soc_dai_set_clkdiv(codec_dai,
- WM8350_DAC_CLKDIV, wm8350_audio[i].clkdiv);
-
- snd_soc_dai_set_clkdiv(codec_dai,
- WM8350_ADC_CLKDIV, wm8350_audio[i].clkdiv);
-
- return 0;
-}
-
-static const struct snd_soc_ops wm1133_ev1_ops = {
- .hw_params = wm1133_ev1_hw_params,
-};
-
-static const struct snd_soc_dapm_widget wm1133_ev1_widgets[] = {
-#ifdef USE_SIMIC
- SND_SOC_DAPM_MIC("SiMIC", NULL),
-#endif
- SND_SOC_DAPM_MIC("Mic1 Jack", NULL),
- SND_SOC_DAPM_MIC("Mic2 Jack", NULL),
- SND_SOC_DAPM_LINE("Line In Jack", NULL),
- SND_SOC_DAPM_LINE("Line Out Jack", NULL),
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
-};
-
-/* imx32ads soc_card audio map */
-static const struct snd_soc_dapm_route wm1133_ev1_map[] = {
-
-#ifdef USE_SIMIC
- /* SiMIC --> IN1LN (with automatic bias) via SP1 */
- { "IN1LN", NULL, "Mic Bias" },
- { "Mic Bias", NULL, "SiMIC" },
-#endif
-
- /* Mic 1 Jack --> IN1LN and IN1LP (with automatic bias) */
- { "IN1LN", NULL, "Mic Bias" },
- { "IN1LP", NULL, "Mic1 Jack" },
- { "Mic Bias", NULL, "Mic1 Jack" },
-
- /* Mic 2 Jack --> IN1RN and IN1RP (with automatic bias) */
- { "IN1RN", NULL, "Mic Bias" },
- { "IN1RP", NULL, "Mic2 Jack" },
- { "Mic Bias", NULL, "Mic2 Jack" },
-
- /* Line in Jack --> AUX (L+R) */
- { "IN3R", NULL, "Line In Jack" },
- { "IN3L", NULL, "Line In Jack" },
-
- /* Out1 --> Headphone Jack */
- { "Headphone Jack", NULL, "OUT1R" },
- { "Headphone Jack", NULL, "OUT1L" },
-
- /* Out1 --> Line Out Jack */
- { "Line Out Jack", NULL, "OUT2R" },
- { "Line Out Jack", NULL, "OUT2L" },
-};
-
-static struct snd_soc_jack hp_jack;
-
-static struct snd_soc_jack_pin hp_jack_pins[] = {
- { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE },
-};
-
-static struct snd_soc_jack mic_jack;
-
-static struct snd_soc_jack_pin mic_jack_pins[] = {
- { .pin = "Mic1 Jack", .mask = SND_JACK_MICROPHONE },
- { .pin = "Mic2 Jack", .mask = SND_JACK_MICROPHONE },
-};
-
-static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
-
- /* Headphone jack detection */
- snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE,
- &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
- wm8350_hp_jack_detect(component, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
-
- /* Microphone jack detection */
- snd_soc_card_jack_new(rtd->card, "Microphone",
- SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack,
- mic_jack_pins, ARRAY_SIZE(mic_jack_pins));
- wm8350_mic_jack_detect(component, &mic_jack, SND_JACK_MICROPHONE,
- SND_JACK_BTN_0);
-
- snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias");
-
- return 0;
-}
-
-
-SND_SOC_DAILINK_DEFS(ev1,
- DAILINK_COMP_ARRAY(COMP_CPU("imx-ssi.0")),
- DAILINK_COMP_ARRAY(COMP_CODEC("wm8350-codec.0-0x1a", "wm8350-hifi")),
- DAILINK_COMP_ARRAY(COMP_PLATFORM("imx-ssi.0")));
-
-static struct snd_soc_dai_link wm1133_ev1_dai = {
- .name = "WM1133-EV1",
- .stream_name = "Audio",
- .init = wm1133_ev1_init,
- .ops = &wm1133_ev1_ops,
- .symmetric_rates = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
- SND_SOC_DAILINK_REG(ev1),
-};
-
-static struct snd_soc_card wm1133_ev1 = {
- .name = "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;
-
-static int __init wm1133_ev1_audio_init(void)
-{
- int ret;
- unsigned int ptcr, pdcr;
-
- /* SSI0 mastered by port 5 */
- ptcr = IMX_AUDMUX_V2_PTCR_SYN |
- IMX_AUDMUX_V2_PTCR_TFSDIR |
- IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT5_SSI_PINS_5) |
- IMX_AUDMUX_V2_PTCR_TCLKDIR |
- IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
- pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT5_SSI_PINS_5);
- imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, ptcr, pdcr);
-
- ptcr = IMX_AUDMUX_V2_PTCR_SYN;
- pdcr = IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0);
- imx_audmux_v2_configure_port(MX31_AUDMUX_PORT5_SSI_PINS_5, ptcr, pdcr);
-
- wm1133_ev1_snd_device = platform_device_alloc("soc-audio", -1);
- if (!wm1133_ev1_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1);
- ret = platform_device_add(wm1133_ev1_snd_device);
-
- if (ret)
- platform_device_put(wm1133_ev1_snd_device);
-
- return ret;
-}
-module_init(wm1133_ev1_audio_init);
-
-static void __exit wm1133_ev1_audio_exit(void)
-{
- platform_device_unregister(wm1133_ev1_snd_device);
-}
-module_exit(wm1133_ev1_audio_exit);
-
-MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
-MODULE_DESCRIPTION("Audio for WM1133-EV1 on i.MX31ADS");
-MODULE_LICENSE("GPL");