ASoC: Rename "sh" to "renesas"
authorLad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Fri, 25 Oct 2024 15:05:07 +0000 (16:05 +0100)
committerMark Brown <broonie@kernel.org>
Wed, 30 Oct 2024 13:15:31 +0000 (13:15 +0000)
Rename the "sh" folder to "renesas" to better reflect the Renesas-specific
drivers.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Acked-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://patch.msgid.link/20241025150511.722040-2-prabhakar.mahadev-lad.rj@bp.renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
54 files changed:
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/renesas/Kconfig [new file with mode: 0644]
sound/soc/renesas/Makefile [new file with mode: 0644]
sound/soc/renesas/dma-sh7760.c [new file with mode: 0644]
sound/soc/renesas/fsi.c [new file with mode: 0644]
sound/soc/renesas/hac.c [new file with mode: 0644]
sound/soc/renesas/migor.c [new file with mode: 0644]
sound/soc/renesas/rcar/Makefile [new file with mode: 0644]
sound/soc/renesas/rcar/adg.c [new file with mode: 0644]
sound/soc/renesas/rcar/cmd.c [new file with mode: 0644]
sound/soc/renesas/rcar/core.c [new file with mode: 0644]
sound/soc/renesas/rcar/ctu.c [new file with mode: 0644]
sound/soc/renesas/rcar/debugfs.c [new file with mode: 0644]
sound/soc/renesas/rcar/dma.c [new file with mode: 0644]
sound/soc/renesas/rcar/dvc.c [new file with mode: 0644]
sound/soc/renesas/rcar/gen.c [new file with mode: 0644]
sound/soc/renesas/rcar/mix.c [new file with mode: 0644]
sound/soc/renesas/rcar/rsnd.h [new file with mode: 0644]
sound/soc/renesas/rcar/src.c [new file with mode: 0644]
sound/soc/renesas/rcar/ssi.c [new file with mode: 0644]
sound/soc/renesas/rcar/ssiu.c [new file with mode: 0644]
sound/soc/renesas/rz-ssi.c [new file with mode: 0644]
sound/soc/renesas/sh7760-ac97.c [new file with mode: 0644]
sound/soc/renesas/siu.h [new file with mode: 0644]
sound/soc/renesas/siu_dai.c [new file with mode: 0644]
sound/soc/renesas/siu_pcm.c [new file with mode: 0644]
sound/soc/renesas/ssi.c [new file with mode: 0644]
sound/soc/sh/Kconfig [deleted file]
sound/soc/sh/Makefile [deleted file]
sound/soc/sh/dma-sh7760.c [deleted file]
sound/soc/sh/fsi.c [deleted file]
sound/soc/sh/hac.c [deleted file]
sound/soc/sh/migor.c [deleted file]
sound/soc/sh/rcar/Makefile [deleted file]
sound/soc/sh/rcar/adg.c [deleted file]
sound/soc/sh/rcar/cmd.c [deleted file]
sound/soc/sh/rcar/core.c [deleted file]
sound/soc/sh/rcar/ctu.c [deleted file]
sound/soc/sh/rcar/debugfs.c [deleted file]
sound/soc/sh/rcar/dma.c [deleted file]
sound/soc/sh/rcar/dvc.c [deleted file]
sound/soc/sh/rcar/gen.c [deleted file]
sound/soc/sh/rcar/mix.c [deleted file]
sound/soc/sh/rcar/rsnd.h [deleted file]
sound/soc/sh/rcar/src.c [deleted file]
sound/soc/sh/rcar/ssi.c [deleted file]
sound/soc/sh/rcar/ssiu.c [deleted file]
sound/soc/sh/rz-ssi.c [deleted file]
sound/soc/sh/sh7760-ac97.c [deleted file]
sound/soc/sh/siu.h [deleted file]
sound/soc/sh/siu_dai.c [deleted file]
sound/soc/sh/siu_pcm.c [deleted file]
sound/soc/sh/ssi.c [deleted file]

index 8e01b42..5efba76 100644 (file)
@@ -106,10 +106,10 @@ source "sound/soc/meson/Kconfig"
 source "sound/soc/mxs/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/qcom/Kconfig"
+source "sound/soc/renesas/Kconfig"
 source "sound/soc/rockchip/Kconfig"
 source "sound/soc/samsung/Kconfig"
 source "sound/soc/sdca/Kconfig"
-source "sound/soc/sh/Kconfig"
 source "sound/soc/sof/Kconfig"
 source "sound/soc/spear/Kconfig"
 source "sound/soc/sprd/Kconfig"
index 5307b0b..08baaa1 100644 (file)
@@ -59,10 +59,10 @@ obj-$(CONFIG_SND_SOC)       += mxs/
 obj-$(CONFIG_SND_SOC)  += kirkwood/
 obj-$(CONFIG_SND_SOC)  += pxa/
 obj-$(CONFIG_SND_SOC)  += qcom/
+obj-$(CONFIG_SND_SOC)  += renesas/
 obj-$(CONFIG_SND_SOC)  += rockchip/
 obj-$(CONFIG_SND_SOC)  += samsung/
 obj-$(CONFIG_SND_SOC)  += sdca/
-obj-$(CONFIG_SND_SOC)  += sh/
 obj-$(CONFIG_SND_SOC)  += sof/
 obj-$(CONFIG_SND_SOC)  += spear/
 obj-$(CONFIG_SND_SOC)  += sprd/
diff --git a/sound/soc/renesas/Kconfig b/sound/soc/renesas/Kconfig
new file mode 100644 (file)
index 0000000..4266329
--- /dev/null
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: GPL-2.0
+menu "SoC Audio support for Renesas SoCs"
+       depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
+
+config SND_SOC_PCM_SH7760
+       tristate "SoC Audio support for Renesas SH7760"
+       depends on CPU_SUBTYPE_SH7760 && SH_DMABRG
+       help
+         Enable this option for SH7760 AC97/I2S audio support.
+
+
+##
+## Audio unit modules
+##
+
+config SND_SOC_SH4_HAC
+       tristate
+       select AC97_BUS
+       select SND_SOC_AC97_BUS
+
+config SND_SOC_SH4_SSI
+       tristate
+
+config SND_SOC_SH4_FSI
+       tristate "SH4 FSI support"
+       depends on SUPERH || COMMON_CLK
+       select SND_SIMPLE_CARD
+       help
+         This option enables FSI sound support
+
+config SND_SOC_SH4_SIU
+       tristate
+       depends on ARCH_SHMOBILE && HAVE_CLK
+       depends on DMADEVICES
+       select DMA_ENGINE
+       select SH_DMAE
+       select FW_LOADER
+
+config SND_SOC_RCAR
+       tristate "R-Car series SRU/SCU/SSIU/SSI support"
+       depends on COMMON_CLK
+       depends on OF
+       select SND_SIMPLE_CARD_UTILS
+       select SND_DMAENGINE_PCM
+       select REGMAP_MMIO
+       help
+         This option enables R-Car SRU/SCU/SSIU/SSI sound support
+
+config SND_SOC_RZ
+       tristate "RZ/G2L series SSIF-2 support"
+       depends on ARCH_RZG2L || COMPILE_TEST
+       help
+         This option enables RZ/G2L SSIF-2 sound support.
+
+##
+## Boards
+##
+
+config SND_SH7760_AC97
+       tristate "SH7760 AC97 sound support"
+       depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760
+       select SND_SOC_SH4_HAC
+       select SND_SOC_AC97_CODEC
+       help
+         This option enables generic sound support for the first
+         AC97 unit of the SH7760.
+
+config SND_SIU_MIGOR
+       tristate "SIU sound support on Migo-R"
+       depends on SH_MIGOR && I2C
+       select SND_SOC_SH4_SIU
+       select SND_SOC_WM8978
+       help
+         This option enables sound support for the SH7722 Migo-R board
+
+endmenu
diff --git a/sound/soc/renesas/Makefile b/sound/soc/renesas/Makefile
new file mode 100644 (file)
index 0000000..f0e19cb
--- /dev/null
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+## DMA engines
+snd-soc-dma-sh7760-y           := dma-sh7760.o
+obj-$(CONFIG_SND_SOC_PCM_SH7760)       += snd-soc-dma-sh7760.o
+
+## audio units found on some SH-4
+snd-soc-hac-y          := hac.o
+snd-soc-ssi-y          := ssi.o
+snd-soc-fsi-y          := fsi.o
+snd-soc-siu-y          := siu_pcm.o siu_dai.o
+obj-$(CONFIG_SND_SOC_SH4_HAC)  += snd-soc-hac.o
+obj-$(CONFIG_SND_SOC_SH4_SSI)  += snd-soc-ssi.o
+obj-$(CONFIG_SND_SOC_SH4_FSI)  += snd-soc-fsi.o
+obj-$(CONFIG_SND_SOC_SH4_SIU)  += snd-soc-siu.o
+
+## audio units for R-Car
+obj-$(CONFIG_SND_SOC_RCAR)     += rcar/
+
+## boards
+snd-soc-sh7760-ac97-y          := sh7760-ac97.o
+snd-soc-migor-y                        := migor.o
+
+obj-$(CONFIG_SND_SH7760_AC97)  += snd-soc-sh7760-ac97.o
+obj-$(CONFIG_SND_SIU_MIGOR)    += snd-soc-migor.o
+
+# RZ/G2L
+snd-soc-rz-ssi-y               := rz-ssi.o
+obj-$(CONFIG_SND_SOC_RZ)       += snd-soc-rz-ssi.o
diff --git a/sound/soc/renesas/dma-sh7760.c b/sound/soc/renesas/dma-sh7760.c
new file mode 100644 (file)
index 0000000..c535394
--- /dev/null
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// SH7760 ("camelot") DMABRG audio DMA unit support
+//
+// Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+//
+// The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
+// trigger an interrupt when one half of the programmed transfer size
+// has been xmitted.
+//
+// FIXME: little-endian only for now
+
+#include <linux/module.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/dmabrg.h>
+
+
+/* registers and bits */
+#define BRGATXSAR      0x00
+#define BRGARXDAR      0x04
+#define BRGATXTCR      0x08
+#define BRGARXTCR      0x0C
+#define BRGACR         0x10
+#define BRGATXTCNT     0x14
+#define BRGARXTCNT     0x18
+
+#define ACR_RAR                (1 << 18)
+#define ACR_RDS                (1 << 17)
+#define ACR_RDE                (1 << 16)
+#define ACR_TAR                (1 << 2)
+#define ACR_TDS                (1 << 1)
+#define ACR_TDE                (1 << 0)
+
+/* receiver/transmitter data alignment */
+#define ACR_RAM_NONE   (0 << 24)
+#define ACR_RAM_4BYTE  (1 << 24)
+#define ACR_RAM_2WORD  (2 << 24)
+#define ACR_TAM_NONE   (0 << 8)
+#define ACR_TAM_4BYTE  (1 << 8)
+#define ACR_TAM_2WORD  (2 << 8)
+
+
+struct camelot_pcm {
+       unsigned long mmio;  /* DMABRG audio channel control reg MMIO */
+       unsigned int txid;    /* ID of first DMABRG IRQ for this unit */
+
+       struct snd_pcm_substream *tx_ss;
+       unsigned long tx_period_size;
+       unsigned int  tx_period;
+
+       struct snd_pcm_substream *rx_ss;
+       unsigned long rx_period_size;
+       unsigned int  rx_period;
+
+} cam_pcm_data[2] = {
+       {
+               .mmio   =       0xFE3C0040,
+               .txid   =       DMABRGIRQ_A0TXF,
+       },
+       {
+               .mmio   =       0xFE3C0060,
+               .txid   =       DMABRGIRQ_A1TXF,
+       },
+};
+
+#define BRGREG(x)      (*(unsigned long *)(cam->mmio + (x)))
+
+/*
+ * set a minimum of 16kb per period, to avoid interrupt-"storm" and
+ * resulting skipping. In general, the bigger the minimum size, the
+ * better for overall system performance. (The SH7760 is a puny CPU
+ * with a slow SDRAM interface and poor internal bus bandwidth,
+ * *especially* when the LCDC is active).  The minimum for the DMAC
+ * is 8 bytes; 16kbytes are enough to get skip-free playback of a
+ * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain
+ * reasonable responsiveness in MPlayer.
+ */
+#define DMABRG_PERIOD_MIN              16 * 1024
+#define DMABRG_PERIOD_MAX              0x03fffffc
+#define DMABRG_PREALLOC_BUFFER         32 * 1024
+#define DMABRG_PREALLOC_BUFFER_MAX     32 * 1024
+
+static const struct snd_pcm_hardware camelot_pcm_hardware = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_BATCH),
+       .buffer_bytes_max =     DMABRG_PERIOD_MAX,
+       .period_bytes_min =     DMABRG_PERIOD_MIN,
+       .period_bytes_max =     DMABRG_PERIOD_MAX / 2,
+       .periods_min =          2,
+       .periods_max =          2,
+       .fifo_size =            128,
+};
+
+static void camelot_txdma(void *data)
+{
+       struct camelot_pcm *cam = data;
+       cam->tx_period ^= 1;
+       snd_pcm_period_elapsed(cam->tx_ss);
+}
+
+static void camelot_rxdma(void *data)
+{
+       struct camelot_pcm *cam = data;
+       cam->rx_period ^= 1;
+       snd_pcm_period_elapsed(cam->rx_ss);
+}
+
+static int camelot_pcm_open(struct snd_soc_component *component,
+                           struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       int ret, dmairq;
+
+       snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware);
+
+       /* DMABRG buffer half/full events */
+       dmairq = (recv) ? cam->txid + 2 : cam->txid;
+       if (recv) {
+               cam->rx_ss = substream;
+               ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
+               if (unlikely(ret)) {
+                       pr_debug("audio unit %d irqs already taken!\n",
+                            snd_soc_rtd_to_cpu(rtd, 0)->id);
+                       return -EBUSY;
+               }
+               (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
+       } else {
+               cam->tx_ss = substream;
+               ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
+               if (unlikely(ret)) {
+                       pr_debug("audio unit %d irqs already taken!\n",
+                            snd_soc_rtd_to_cpu(rtd, 0)->id);
+                       return -EBUSY;
+               }
+               (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
+       }
+       return 0;
+}
+
+static int camelot_pcm_close(struct snd_soc_component *component,
+                            struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       int dmairq;
+
+       dmairq = (recv) ? cam->txid + 2 : cam->txid;
+
+       if (recv)
+               cam->rx_ss = NULL;
+       else
+               cam->tx_ss = NULL;
+
+       dmabrg_free_irq(dmairq + 1);
+       dmabrg_free_irq(dmairq);
+
+       return 0;
+}
+
+static int camelot_hw_params(struct snd_soc_component *component,
+                            struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+
+       if (recv) {
+               cam->rx_period_size = params_period_bytes(hw_params);
+               cam->rx_period = 0;
+       } else {
+               cam->tx_period_size = params_period_bytes(hw_params);
+               cam->tx_period = 0;
+       }
+       return 0;
+}
+
+static int camelot_prepare(struct snd_soc_component *component,
+                          struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
+
+       pr_debug("PCM data: addr %pad len %zu\n", &runtime->dma_addr,
+                runtime->dma_bytes);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
+               BRGREG(BRGATXTCR) = runtime->dma_bytes;
+       } else {
+               BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area;
+               BRGREG(BRGARXTCR) = runtime->dma_bytes;
+       }
+
+       return 0;
+}
+
+static inline void dmabrg_play_dma_start(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* start DMABRG engine: XFER start, auto-addr-reload */
+       BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD;
+}
+
+static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* forcibly terminate data transmission */
+       BRGREG(BRGACR) = acr | ACR_TDS;
+}
+
+static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* start DMABRG engine: recv start, auto-reload */
+       BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD;
+}
+
+static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* forcibly terminate data receiver */
+       BRGREG(BRGACR) = acr | ACR_RDS;
+}
+
+static int camelot_trigger(struct snd_soc_component *component,
+                          struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (recv)
+                       dmabrg_rec_dma_start(cam);
+               else
+                       dmabrg_play_dma_start(cam);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (recv)
+                       dmabrg_rec_dma_stop(cam);
+               else
+                       dmabrg_play_dma_stop(cam);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t camelot_pos(struct snd_soc_component *component,
+                                    struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       unsigned long pos;
+
+       /* cannot use the DMABRG pointer register: under load, by the
+        * time ALSA comes around to read the register, it is already
+        * far ahead (or worse, already done with the fragment) of the
+        * position at the time the IRQ was triggered, which results in
+        * fast-playback sound in my test application (ScummVM)
+        */
+       if (recv)
+               pos = cam->rx_period ? cam->rx_period_size : 0;
+       else
+               pos = cam->tx_period ? cam->tx_period_size : 0;
+
+       return bytes_to_frames(runtime, pos);
+}
+
+static int camelot_pcm_new(struct snd_soc_component *component,
+                          struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_pcm *pcm = rtd->pcm;
+
+       /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
+        * in MMAP mode (i.e. aplay -M)
+        */
+       snd_pcm_set_managed_buffer_all(pcm,
+               SNDRV_DMA_TYPE_CONTINUOUS,
+               NULL,
+               DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX);
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver sh7760_soc_component = {
+       .open           = camelot_pcm_open,
+       .close          = camelot_pcm_close,
+       .hw_params      = camelot_hw_params,
+       .prepare        = camelot_prepare,
+       .trigger        = camelot_trigger,
+       .pointer        = camelot_pos,
+       .pcm_construct  = camelot_pcm_new,
+};
+
+static int sh7760_soc_platform_probe(struct platform_device *pdev)
+{
+       return devm_snd_soc_register_component(&pdev->dev, &sh7760_soc_component,
+                                              NULL, 0);
+}
+
+static struct platform_driver sh7760_pcm_driver = {
+       .driver = {
+                       .name = "sh7760-pcm-audio",
+       },
+
+       .probe = sh7760_soc_platform_probe,
+};
+
+module_platform_driver(sh7760_pcm_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c
new file mode 100644 (file)
index 0000000..221ce91
--- /dev/null
@@ -0,0 +1,2119 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Fifo-attached Serial Interface (FSI) support for SH7724
+//
+// Copyright (C) 2009 Renesas Solutions Corp.
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
+//
+// Based on ssi.c
+// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/scatterlist.h>
+#include <linux/sh_dma.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/sh_fsi.h>
+
+/* PortA/PortB register */
+#define REG_DO_FMT     0x0000
+#define REG_DOFF_CTL   0x0004
+#define REG_DOFF_ST    0x0008
+#define REG_DI_FMT     0x000C
+#define REG_DIFF_CTL   0x0010
+#define REG_DIFF_ST    0x0014
+#define REG_CKG1       0x0018
+#define REG_CKG2       0x001C
+#define REG_DIDT       0x0020
+#define REG_DODT       0x0024
+#define REG_MUTE_ST    0x0028
+#define REG_OUT_DMAC   0x002C
+#define REG_OUT_SEL    0x0030
+#define REG_IN_DMAC    0x0038
+
+/* master register */
+#define MST_CLK_RST    0x0210
+#define MST_SOFT_RST   0x0214
+#define MST_FIFO_SZ    0x0218
+
+/* core register (depend on FSI version) */
+#define A_MST_CTLR     0x0180
+#define B_MST_CTLR     0x01A0
+#define CPU_INT_ST     0x01F4
+#define CPU_IEMSK      0x01F8
+#define CPU_IMSK       0x01FC
+#define INT_ST         0x0200
+#define IEMSK          0x0204
+#define IMSK           0x0208
+
+/* DO_FMT */
+/* DI_FMT */
+#define CR_BWS_MASK    (0x3 << 20) /* FSI2 */
+#define CR_BWS_24      (0x0 << 20) /* FSI2 */
+#define CR_BWS_16      (0x1 << 20) /* FSI2 */
+#define CR_BWS_20      (0x2 << 20) /* FSI2 */
+
+#define CR_DTMD_PCM            (0x0 << 8) /* FSI2 */
+#define CR_DTMD_SPDIF_PCM      (0x1 << 8) /* FSI2 */
+#define CR_DTMD_SPDIF_STREAM   (0x2 << 8) /* FSI2 */
+
+#define CR_MONO                (0x0 << 4)
+#define CR_MONO_D      (0x1 << 4)
+#define CR_PCM         (0x2 << 4)
+#define CR_I2S         (0x3 << 4)
+#define CR_TDM         (0x4 << 4)
+#define CR_TDM_D       (0x5 << 4)
+
+/* OUT_DMAC */
+/* IN_DMAC */
+#define VDMD_MASK      (0x3 << 4)
+#define VDMD_FRONT     (0x0 << 4) /* Package in front */
+#define VDMD_BACK      (0x1 << 4) /* Package in back */
+#define VDMD_STREAM    (0x2 << 4) /* Stream mode(16bit * 2) */
+
+#define DMA_ON         (0x1 << 0)
+
+/* DOFF_CTL */
+/* DIFF_CTL */
+#define IRQ_HALF       0x00100000
+#define FIFO_CLR       0x00000001
+
+/* DOFF_ST */
+#define ERR_OVER       0x00000010
+#define ERR_UNDER      0x00000001
+#define ST_ERR         (ERR_OVER | ERR_UNDER)
+
+/* CKG1 */
+#define ACKMD_MASK     0x00007000
+#define BPFMD_MASK     0x00000700
+#define DIMD           (1 << 4)
+#define DOMD           (1 << 0)
+
+/* A/B MST_CTLR */
+#define BP     (1 << 4)        /* Fix the signal of Biphase output */
+#define SE     (1 << 0)        /* Fix the master clock */
+
+/* CLK_RST */
+#define CRB    (1 << 4)
+#define CRA    (1 << 0)
+
+/* IO SHIFT / MACRO */
+#define BI_SHIFT       12
+#define BO_SHIFT       8
+#define AI_SHIFT       4
+#define AO_SHIFT       0
+#define AB_IO(param, shift)    (param << shift)
+
+/* SOFT_RST */
+#define PBSR           (1 << 12) /* Port B Software Reset */
+#define PASR           (1 <<  8) /* Port A Software Reset */
+#define IR             (1 <<  4) /* Interrupt Reset */
+#define FSISR          (1 <<  0) /* Software Reset */
+
+/* OUT_SEL (FSI2) */
+#define DMMD           (1 << 4) /* SPDIF output timing 0: Biphase only */
+                                /*                     1: Biphase and serial */
+
+/* FIFO_SZ */
+#define FIFO_SZ_MASK   0x7
+
+#define FSI_RATES SNDRV_PCM_RATE_8000_96000
+
+#define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+
+/*
+ * bus options
+ *
+ * 0x000000BA
+ *
+ * A : sample widtht 16bit setting
+ * B : sample widtht 24bit setting
+ */
+
+#define SHIFT_16DATA           0
+#define SHIFT_24DATA           4
+
+#define PACKAGE_24BITBUS_BACK          0
+#define PACKAGE_24BITBUS_FRONT         1
+#define PACKAGE_16BITBUS_STREAM                2
+
+#define BUSOP_SET(s, a)        ((a) << SHIFT_ ## s ## DATA)
+#define BUSOP_GET(s, a)        (((a) >> SHIFT_ ## s ## DATA) & 0xF)
+
+/*
+ * FSI driver use below type name for variable
+ *
+ * xxx_num     : number of data
+ * xxx_pos     : position of data
+ * xxx_capa    : capacity of data
+ */
+
+/*
+ *     period/frame/sample image
+ *
+ * ex) PCM (2ch)
+ *
+ * period pos                                     period pos
+ *   [n]                                            [n + 1]
+ *   |<-------------------- period--------------------->|
+ * ==|============================================ ... =|==
+ *   |                                                 |
+ *   ||<-----  frame ----->|<------ frame ----->|  ... |
+ *   |+--------------------+--------------------+- ... |
+ *   ||[ sample ][ sample ]|[ sample ][ sample ]|  ... |
+ *   |+--------------------+--------------------+- ... |
+ * ==|============================================ ... =|==
+ */
+
+/*
+ *     FSI FIFO image
+ *
+ *     |            |
+ *     |            |
+ *     | [ sample ] |
+ *     | [ sample ] |
+ *     | [ sample ] |
+ *     | [ sample ] |
+ *             --> go to codecs
+ */
+
+/*
+ *     FSI clock
+ *
+ * FSIxCLK [CPG] (ick) ------->        |
+ *                             |-> FSI_DIV (div)-> FSI2
+ * FSIxCK [external] (xck) --->        |
+ */
+
+/*
+ *             struct
+ */
+
+struct fsi_stream_handler;
+struct fsi_stream {
+
+       /*
+        * these are initialized by fsi_stream_init()
+        */
+       struct snd_pcm_substream *substream;
+       int fifo_sample_capa;   /* sample capacity of FSI FIFO */
+       int buff_sample_capa;   /* sample capacity of ALSA buffer */
+       int buff_sample_pos;    /* sample position of ALSA buffer */
+       int period_samples;     /* sample number / 1 period */
+       int period_pos;         /* current period position */
+       int sample_width;       /* sample width */
+       int uerr_num;
+       int oerr_num;
+
+       /*
+        * bus options
+        */
+       u32 bus_option;
+
+       /*
+        * these are initialized by fsi_handler_init()
+        */
+       struct fsi_stream_handler *handler;
+       struct fsi_priv         *priv;
+
+       /*
+        * these are for DMAEngine
+        */
+       struct dma_chan         *chan;
+       int                     dma_id;
+};
+
+struct fsi_clk {
+       /* see [FSI clock] */
+       struct clk *own;
+       struct clk *xck;
+       struct clk *ick;
+       struct clk *div;
+       int (*set_rate)(struct device *dev,
+                       struct fsi_priv *fsi);
+
+       unsigned long rate;
+       unsigned int count;
+};
+
+struct fsi_priv {
+       void __iomem *base;
+       phys_addr_t phys;
+       struct fsi_master *master;
+
+       struct fsi_stream playback;
+       struct fsi_stream capture;
+
+       struct fsi_clk clock;
+
+       u32 fmt;
+
+       int chan_num:16;
+       unsigned int clk_master:1;
+       unsigned int clk_cpg:1;
+       unsigned int spdif:1;
+       unsigned int enable_stream:1;
+       unsigned int bit_clk_inv:1;
+       unsigned int lr_clk_inv:1;
+};
+
+struct fsi_stream_handler {
+       int (*init)(struct fsi_priv *fsi, struct fsi_stream *io);
+       int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io);
+       int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev);
+       int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
+       int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
+       int (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
+                          int enable);
+};
+#define fsi_stream_handler_call(io, func, args...)     \
+       (!(io) ? -ENODEV :                              \
+        !((io)->handler->func) ? 0 :                   \
+        (io)->handler->func(args))
+
+struct fsi_core {
+       int ver;
+
+       u32 int_st;
+       u32 iemsk;
+       u32 imsk;
+       u32 a_mclk;
+       u32 b_mclk;
+};
+
+struct fsi_master {
+       void __iomem *base;
+       struct fsi_priv fsia;
+       struct fsi_priv fsib;
+       const struct fsi_core *core;
+       spinlock_t lock;
+};
+
+static inline int fsi_stream_is_play(struct fsi_priv *fsi,
+                                    struct fsi_stream *io)
+{
+       return &fsi->playback == io;
+}
+
+
+/*
+ *             basic read write function
+ */
+
+static void __fsi_reg_write(u32 __iomem *reg, u32 data)
+{
+       /* valid data area is 24bit */
+       data &= 0x00ffffff;
+
+       __raw_writel(data, reg);
+}
+
+static u32 __fsi_reg_read(u32 __iomem *reg)
+{
+       return __raw_readl(reg);
+}
+
+static void __fsi_reg_mask_set(u32 __iomem *reg, u32 mask, u32 data)
+{
+       u32 val = __fsi_reg_read(reg);
+
+       val &= ~mask;
+       val |= data & mask;
+
+       __fsi_reg_write(reg, val);
+}
+
+#define fsi_reg_write(p, r, d)\
+       __fsi_reg_write((p->base + REG_##r), d)
+
+#define fsi_reg_read(p, r)\
+       __fsi_reg_read((p->base + REG_##r))
+
+#define fsi_reg_mask_set(p, r, m, d)\
+       __fsi_reg_mask_set((p->base + REG_##r), m, d)
+
+#define fsi_master_read(p, r) _fsi_master_read(p, MST_##r)
+#define fsi_core_read(p, r)   _fsi_master_read(p, p->core->r)
+static u32 _fsi_master_read(struct fsi_master *master, u32 reg)
+{
+       u32 ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&master->lock, flags);
+       ret = __fsi_reg_read(master->base + reg);
+       spin_unlock_irqrestore(&master->lock, flags);
+
+       return ret;
+}
+
+#define fsi_master_mask_set(p, r, m, d) _fsi_master_mask_set(p, MST_##r, m, d)
+#define fsi_core_mask_set(p, r, m, d)  _fsi_master_mask_set(p, p->core->r, m, d)
+static void _fsi_master_mask_set(struct fsi_master *master,
+                              u32 reg, u32 mask, u32 data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&master->lock, flags);
+       __fsi_reg_mask_set(master->base + reg, mask, data);
+       spin_unlock_irqrestore(&master->lock, flags);
+}
+
+/*
+ *             basic function
+ */
+static int fsi_version(struct fsi_master *master)
+{
+       return master->core->ver;
+}
+
+static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
+{
+       return fsi->master;
+}
+
+static int fsi_is_clk_master(struct fsi_priv *fsi)
+{
+       return fsi->clk_master;
+}
+
+static int fsi_is_port_a(struct fsi_priv *fsi)
+{
+       return fsi->master->base == fsi->base;
+}
+
+static int fsi_is_spdif(struct fsi_priv *fsi)
+{
+       return fsi->spdif;
+}
+
+static int fsi_is_enable_stream(struct fsi_priv *fsi)
+{
+       return fsi->enable_stream;
+}
+
+static int fsi_is_play(struct snd_pcm_substream *substream)
+{
+       return substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+}
+
+static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+
+       return  snd_soc_rtd_to_cpu(rtd, 0);
+}
+
+static struct fsi_priv *fsi_get_priv_frm_dai(struct snd_soc_dai *dai)
+{
+       struct fsi_master *master = snd_soc_dai_get_drvdata(dai);
+
+       if (dai->id == 0)
+               return &master->fsia;
+       else
+               return &master->fsib;
+}
+
+static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
+{
+       return fsi_get_priv_frm_dai(fsi_get_dai(substream));
+}
+
+static u32 fsi_get_port_shift(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       int is_play = fsi_stream_is_play(fsi, io);
+       int is_porta = fsi_is_port_a(fsi);
+       u32 shift;
+
+       if (is_porta)
+               shift = is_play ? AO_SHIFT : AI_SHIFT;
+       else
+               shift = is_play ? BO_SHIFT : BI_SHIFT;
+
+       return shift;
+}
+
+static int fsi_frame2sample(struct fsi_priv *fsi, int frames)
+{
+       return frames * fsi->chan_num;
+}
+
+static int fsi_sample2frame(struct fsi_priv *fsi, int samples)
+{
+       return samples / fsi->chan_num;
+}
+
+static int fsi_get_current_fifo_samples(struct fsi_priv *fsi,
+                                       struct fsi_stream *io)
+{
+       int is_play = fsi_stream_is_play(fsi, io);
+       u32 status;
+       int frames;
+
+       status = is_play ?
+               fsi_reg_read(fsi, DOFF_ST) :
+               fsi_reg_read(fsi, DIFF_ST);
+
+       frames = 0x1ff & (status >> 8);
+
+       return fsi_frame2sample(fsi, frames);
+}
+
+static void fsi_count_fifo_err(struct fsi_priv *fsi)
+{
+       u32 ostatus = fsi_reg_read(fsi, DOFF_ST);
+       u32 istatus = fsi_reg_read(fsi, DIFF_ST);
+
+       if (ostatus & ERR_OVER)
+               fsi->playback.oerr_num++;
+
+       if (ostatus & ERR_UNDER)
+               fsi->playback.uerr_num++;
+
+       if (istatus & ERR_OVER)
+               fsi->capture.oerr_num++;
+
+       if (istatus & ERR_UNDER)
+               fsi->capture.uerr_num++;
+
+       fsi_reg_write(fsi, DOFF_ST, 0);
+       fsi_reg_write(fsi, DIFF_ST, 0);
+}
+
+/*
+ *             fsi_stream_xx() function
+ */
+static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi,
+                                       struct snd_pcm_substream *substream)
+{
+       return fsi_is_play(substream) ? &fsi->playback : &fsi->capture;
+}
+
+static int fsi_stream_is_working(struct fsi_priv *fsi,
+                                struct fsi_stream *io)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&master->lock, flags);
+       ret = !!(io->substream && io->substream->runtime);
+       spin_unlock_irqrestore(&master->lock, flags);
+
+       return ret;
+}
+
+static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io)
+{
+       return io->priv;
+}
+
+static void fsi_stream_init(struct fsi_priv *fsi,
+                           struct fsi_stream *io,
+                           struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct fsi_master *master = fsi_get_master(fsi);
+       unsigned long flags;
+
+       spin_lock_irqsave(&master->lock, flags);
+       io->substream   = substream;
+       io->buff_sample_capa    = fsi_frame2sample(fsi, runtime->buffer_size);
+       io->buff_sample_pos     = 0;
+       io->period_samples      = fsi_frame2sample(fsi, runtime->period_size);
+       io->period_pos          = 0;
+       io->sample_width        = samples_to_bytes(runtime, 1);
+       io->bus_option          = 0;
+       io->oerr_num    = -1; /* ignore 1st err */
+       io->uerr_num    = -1; /* ignore 1st err */
+       fsi_stream_handler_call(io, init, fsi, io);
+       spin_unlock_irqrestore(&master->lock, flags);
+}
+
+static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+       struct fsi_master *master = fsi_get_master(fsi);
+       unsigned long flags;
+
+       spin_lock_irqsave(&master->lock, flags);
+
+       if (io->oerr_num > 0)
+               dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
+
+       if (io->uerr_num > 0)
+               dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
+
+       fsi_stream_handler_call(io, quit, fsi, io);
+       io->substream   = NULL;
+       io->buff_sample_capa    = 0;
+       io->buff_sample_pos     = 0;
+       io->period_samples      = 0;
+       io->period_pos          = 0;
+       io->sample_width        = 0;
+       io->bus_option          = 0;
+       io->oerr_num    = 0;
+       io->uerr_num    = 0;
+       spin_unlock_irqrestore(&master->lock, flags);
+}
+
+static int fsi_stream_transfer(struct fsi_stream *io)
+{
+       struct fsi_priv *fsi = fsi_stream_to_priv(io);
+       if (!fsi)
+               return -EIO;
+
+       return fsi_stream_handler_call(io, transfer, fsi, io);
+}
+
+#define fsi_stream_start(fsi, io)\
+       fsi_stream_handler_call(io, start_stop, fsi, io, 1)
+
+#define fsi_stream_stop(fsi, io)\
+       fsi_stream_handler_call(io, start_stop, fsi, io, 0)
+
+static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev)
+{
+       struct fsi_stream *io;
+       int ret1, ret2;
+
+       io = &fsi->playback;
+       ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev);
+
+       io = &fsi->capture;
+       ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev);
+
+       if (ret1 < 0)
+               return ret1;
+       if (ret2 < 0)
+               return ret2;
+
+       return 0;
+}
+
+static int fsi_stream_remove(struct fsi_priv *fsi)
+{
+       struct fsi_stream *io;
+       int ret1, ret2;
+
+       io = &fsi->playback;
+       ret1 = fsi_stream_handler_call(io, remove, fsi, io);
+
+       io = &fsi->capture;
+       ret2 = fsi_stream_handler_call(io, remove, fsi, io);
+
+       if (ret1 < 0)
+               return ret1;
+       if (ret2 < 0)
+               return ret2;
+
+       return 0;
+}
+
+/*
+ *     format/bus/dma setting
+ */
+static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io,
+                                u32 bus, struct device *dev)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+       int is_play = fsi_stream_is_play(fsi, io);
+       u32 fmt = fsi->fmt;
+
+       if (fsi_version(master) >= 2) {
+               u32 dma = 0;
+
+               /*
+                * FSI2 needs DMA/Bus setting
+                */
+               switch (bus) {
+               case PACKAGE_24BITBUS_FRONT:
+                       fmt |= CR_BWS_24;
+                       dma |= VDMD_FRONT;
+                       dev_dbg(dev, "24bit bus / package in front\n");
+                       break;
+               case PACKAGE_16BITBUS_STREAM:
+                       fmt |= CR_BWS_16;
+                       dma |= VDMD_STREAM;
+                       dev_dbg(dev, "16bit bus / stream mode\n");
+                       break;
+               case PACKAGE_24BITBUS_BACK:
+               default:
+                       fmt |= CR_BWS_24;
+                       dma |= VDMD_BACK;
+                       dev_dbg(dev, "24bit bus / package in back\n");
+                       break;
+               }
+
+               if (is_play)
+                       fsi_reg_write(fsi, OUT_DMAC,    dma);
+               else
+                       fsi_reg_write(fsi, IN_DMAC,     dma);
+       }
+
+       if (is_play)
+               fsi_reg_write(fsi, DO_FMT, fmt);
+       else
+               fsi_reg_write(fsi, DI_FMT, fmt);
+}
+
+/*
+ *             irq function
+ */
+
+static void fsi_irq_enable(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       u32 data = AB_IO(1, fsi_get_port_shift(fsi, io));
+       struct fsi_master *master = fsi_get_master(fsi);
+
+       fsi_core_mask_set(master, imsk,  data, data);
+       fsi_core_mask_set(master, iemsk, data, data);
+}
+
+static void fsi_irq_disable(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       u32 data = AB_IO(1, fsi_get_port_shift(fsi, io));
+       struct fsi_master *master = fsi_get_master(fsi);
+
+       fsi_core_mask_set(master, imsk,  data, 0);
+       fsi_core_mask_set(master, iemsk, data, 0);
+}
+
+static u32 fsi_irq_get_status(struct fsi_master *master)
+{
+       return fsi_core_read(master, int_st);
+}
+
+static void fsi_irq_clear_status(struct fsi_priv *fsi)
+{
+       u32 data = 0;
+       struct fsi_master *master = fsi_get_master(fsi);
+
+       data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->playback));
+       data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->capture));
+
+       /* clear interrupt factor */
+       fsi_core_mask_set(master, int_st, data, 0);
+}
+
+/*
+ *             SPDIF master clock function
+ *
+ * These functions are used later FSI2
+ */
+static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+       u32 mask, val;
+
+       mask = BP | SE;
+       val = enable ? mask : 0;
+
+       fsi_is_port_a(fsi) ?
+               fsi_core_mask_set(master, a_mclk, mask, val) :
+               fsi_core_mask_set(master, b_mclk, mask, val);
+}
+
+/*
+ *             clock function
+ */
+static int fsi_clk_init(struct device *dev,
+                       struct fsi_priv *fsi,
+                       int xck,
+                       int ick,
+                       int div,
+                       int (*set_rate)(struct device *dev,
+                                       struct fsi_priv *fsi))
+{
+       struct fsi_clk *clock = &fsi->clock;
+       int is_porta = fsi_is_port_a(fsi);
+
+       clock->xck      = NULL;
+       clock->ick      = NULL;
+       clock->div      = NULL;
+       clock->rate     = 0;
+       clock->count    = 0;
+       clock->set_rate = set_rate;
+
+       clock->own = devm_clk_get(dev, NULL);
+       if (IS_ERR(clock->own))
+               return -EINVAL;
+
+       /* external clock */
+       if (xck) {
+               clock->xck = devm_clk_get(dev, is_porta ? "xcka" : "xckb");
+               if (IS_ERR(clock->xck)) {
+                       dev_err(dev, "can't get xck clock\n");
+                       return -EINVAL;
+               }
+               if (clock->xck == clock->own) {
+                       dev_err(dev, "cpu doesn't support xck clock\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* FSIACLK/FSIBCLK */
+       if (ick) {
+               clock->ick = devm_clk_get(dev,  is_porta ? "icka" : "ickb");
+               if (IS_ERR(clock->ick)) {
+                       dev_err(dev, "can't get ick clock\n");
+                       return -EINVAL;
+               }
+               if (clock->ick == clock->own) {
+                       dev_err(dev, "cpu doesn't support ick clock\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* FSI-DIV */
+       if (div) {
+               clock->div = devm_clk_get(dev,  is_porta ? "diva" : "divb");
+               if (IS_ERR(clock->div)) {
+                       dev_err(dev, "can't get div clock\n");
+                       return -EINVAL;
+               }
+               if (clock->div == clock->own) {
+                       dev_err(dev, "cpu doesn't support div clock\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+#define fsi_clk_invalid(fsi) fsi_clk_valid(fsi, 0)
+static void fsi_clk_valid(struct fsi_priv *fsi, unsigned long rate)
+{
+       fsi->clock.rate = rate;
+}
+
+static int fsi_clk_is_valid(struct fsi_priv *fsi)
+{
+       return  fsi->clock.set_rate &&
+               fsi->clock.rate;
+}
+
+static int fsi_clk_enable(struct device *dev,
+                         struct fsi_priv *fsi)
+{
+       struct fsi_clk *clock = &fsi->clock;
+       int ret = -EINVAL;
+
+       if (!fsi_clk_is_valid(fsi))
+               return ret;
+
+       if (0 == clock->count) {
+               ret = clock->set_rate(dev, fsi);
+               if (ret < 0) {
+                       fsi_clk_invalid(fsi);
+                       return ret;
+               }
+
+               ret = clk_enable(clock->xck);
+               if (ret)
+                       goto err;
+               ret = clk_enable(clock->ick);
+               if (ret)
+                       goto disable_xck;
+               ret = clk_enable(clock->div);
+               if (ret)
+                       goto disable_ick;
+
+               clock->count++;
+       }
+
+       return ret;
+
+disable_ick:
+       clk_disable(clock->ick);
+disable_xck:
+       clk_disable(clock->xck);
+err:
+       return ret;
+}
+
+static int fsi_clk_disable(struct device *dev,
+                           struct fsi_priv *fsi)
+{
+       struct fsi_clk *clock = &fsi->clock;
+
+       if (!fsi_clk_is_valid(fsi))
+               return -EINVAL;
+
+       if (1 == clock->count--) {
+               clk_disable(clock->xck);
+               clk_disable(clock->ick);
+               clk_disable(clock->div);
+       }
+
+       return 0;
+}
+
+static int fsi_clk_set_ackbpf(struct device *dev,
+                             struct fsi_priv *fsi,
+                             int ackmd, int bpfmd)
+{
+       u32 data = 0;
+
+       /* check ackmd/bpfmd relationship */
+       if (bpfmd > ackmd) {
+               dev_err(dev, "unsupported rate (%d/%d)\n", ackmd, bpfmd);
+               return -EINVAL;
+       }
+
+       /*  ACKMD */
+       switch (ackmd) {
+       case 512:
+               data |= (0x0 << 12);
+               break;
+       case 256:
+               data |= (0x1 << 12);
+               break;
+       case 128:
+               data |= (0x2 << 12);
+               break;
+       case 64:
+               data |= (0x3 << 12);
+               break;
+       case 32:
+               data |= (0x4 << 12);
+               break;
+       default:
+               dev_err(dev, "unsupported ackmd (%d)\n", ackmd);
+               return -EINVAL;
+       }
+
+       /* BPFMD */
+       switch (bpfmd) {
+       case 32:
+               data |= (0x0 << 8);
+               break;
+       case 64:
+               data |= (0x1 << 8);
+               break;
+       case 128:
+               data |= (0x2 << 8);
+               break;
+       case 256:
+               data |= (0x3 << 8);
+               break;
+       case 512:
+               data |= (0x4 << 8);
+               break;
+       case 16:
+               data |= (0x7 << 8);
+               break;
+       default:
+               dev_err(dev, "unsupported bpfmd (%d)\n", bpfmd);
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "ACKMD/BPFMD = %d/%d\n", ackmd, bpfmd);
+
+       fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
+       udelay(10);
+
+       return 0;
+}
+
+static int fsi_clk_set_rate_external(struct device *dev,
+                                    struct fsi_priv *fsi)
+{
+       struct clk *xck = fsi->clock.xck;
+       struct clk *ick = fsi->clock.ick;
+       unsigned long rate = fsi->clock.rate;
+       unsigned long xrate;
+       int ackmd, bpfmd;
+       int ret = 0;
+
+       /* check clock rate */
+       xrate = clk_get_rate(xck);
+       if (xrate % rate) {
+               dev_err(dev, "unsupported clock rate\n");
+               return -EINVAL;
+       }
+
+       clk_set_parent(ick, xck);
+       clk_set_rate(ick, xrate);
+
+       bpfmd = fsi->chan_num * 32;
+       ackmd = xrate / rate;
+
+       dev_dbg(dev, "external/rate = %ld/%ld\n", xrate, rate);
+
+       ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd);
+       if (ret < 0)
+               dev_err(dev, "%s failed", __func__);
+
+       return ret;
+}
+
+static int fsi_clk_set_rate_cpg(struct device *dev,
+                               struct fsi_priv *fsi)
+{
+       struct clk *ick = fsi->clock.ick;
+       struct clk *div = fsi->clock.div;
+       unsigned long rate = fsi->clock.rate;
+       unsigned long target = 0; /* 12288000 or 11289600 */
+       unsigned long actual, cout;
+       unsigned long diff, min;
+       unsigned long best_cout, best_act;
+       int adj;
+       int ackmd, bpfmd;
+       int ret = -EINVAL;
+
+       if (!(12288000 % rate))
+               target = 12288000;
+       if (!(11289600 % rate))
+               target = 11289600;
+       if (!target) {
+               dev_err(dev, "unsupported rate\n");
+               return ret;
+       }
+
+       bpfmd = fsi->chan_num * 32;
+       ackmd = target / rate;
+       ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd);
+       if (ret < 0) {
+               dev_err(dev, "%s failed", __func__);
+               return ret;
+       }
+
+       /*
+        * The clock flow is
+        *
+        * [CPG] = cout => [FSI_DIV] = audio => [FSI] => [codec]
+        *
+        * But, it needs to find best match of CPG and FSI_DIV
+        * combination, since it is difficult to generate correct
+        * frequency of audio clock from ick clock only.
+        * Because ick is created from its parent clock.
+        *
+        * target       = rate x [512/256/128/64]fs
+        * cout         = round(target x adjustment)
+        * actual       = cout / adjustment (by FSI-DIV) ~= target
+        * audio        = actual
+        */
+       min = ~0;
+       best_cout = 0;
+       best_act = 0;
+       for (adj = 1; adj < 0xffff; adj++) {
+
+               cout = target * adj;
+               if (cout > 100000000) /* max clock = 100MHz */
+                       break;
+
+               /* cout/actual audio clock */
+               cout    = clk_round_rate(ick, cout);
+               actual  = cout / adj;
+
+               /* find best frequency */
+               diff = abs(actual - target);
+               if (diff < min) {
+                       min             = diff;
+                       best_cout       = cout;
+                       best_act        = actual;
+               }
+       }
+
+       ret = clk_set_rate(ick, best_cout);
+       if (ret < 0) {
+               dev_err(dev, "ick clock failed\n");
+               return -EIO;
+       }
+
+       ret = clk_set_rate(div, clk_round_rate(div, best_act));
+       if (ret < 0) {
+               dev_err(dev, "div clock failed\n");
+               return -EIO;
+       }
+
+       dev_dbg(dev, "ick/div = %ld/%ld\n",
+               clk_get_rate(ick), clk_get_rate(div));
+
+       return ret;
+}
+
+static void fsi_pointer_update(struct fsi_stream *io, int size)
+{
+       io->buff_sample_pos += size;
+
+       if (io->buff_sample_pos >=
+           io->period_samples * (io->period_pos + 1)) {
+               struct snd_pcm_substream *substream = io->substream;
+               struct snd_pcm_runtime *runtime = substream->runtime;
+
+               io->period_pos++;
+
+               if (io->period_pos >= runtime->periods) {
+                       io->buff_sample_pos = 0;
+                       io->period_pos = 0;
+               }
+
+               snd_pcm_period_elapsed(substream);
+       }
+}
+
+/*
+ *             pio data transfer handler
+ */
+static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples)
+{
+       int i;
+
+       if (fsi_is_enable_stream(fsi)) {
+               /*
+                * stream mode
+                * see
+                *      fsi_pio_push_init()
+                */
+               u32 *buf = (u32 *)_buf;
+
+               for (i = 0; i < samples / 2; i++)
+                       fsi_reg_write(fsi, DODT, buf[i]);
+       } else {
+               /* normal mode */
+               u16 *buf = (u16 *)_buf;
+
+               for (i = 0; i < samples; i++)
+                       fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
+       }
+}
+
+static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples)
+{
+       u16 *buf = (u16 *)_buf;
+       int i;
+
+       for (i = 0; i < samples; i++)
+               *(buf + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8);
+}
+
+static void fsi_pio_push32(struct fsi_priv *fsi, u8 *_buf, int samples)
+{
+       u32 *buf = (u32 *)_buf;
+       int i;
+
+       for (i = 0; i < samples; i++)
+               fsi_reg_write(fsi, DODT, *(buf + i));
+}
+
+static void fsi_pio_pop32(struct fsi_priv *fsi, u8 *_buf, int samples)
+{
+       u32 *buf = (u32 *)_buf;
+       int i;
+
+       for (i = 0; i < samples; i++)
+               *(buf + i) = fsi_reg_read(fsi, DIDT);
+}
+
+static u8 *fsi_pio_get_area(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       struct snd_pcm_runtime *runtime = io->substream->runtime;
+
+       return runtime->dma_area +
+               samples_to_bytes(runtime, io->buff_sample_pos);
+}
+
+static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io,
+               void (*run16)(struct fsi_priv *fsi, u8 *buf, int samples),
+               void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples),
+               int samples)
+{
+       u8 *buf;
+
+       if (!fsi_stream_is_working(fsi, io))
+               return -EINVAL;
+
+       buf = fsi_pio_get_area(fsi, io);
+
+       switch (io->sample_width) {
+       case 2:
+               run16(fsi, buf, samples);
+               break;
+       case 4:
+               run32(fsi, buf, samples);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       fsi_pointer_update(io, samples);
+
+       return 0;
+}
+
+static int fsi_pio_pop(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       int sample_residues;    /* samples in FSI fifo */
+       int sample_space;       /* ALSA free samples space */
+       int samples;
+
+       sample_residues = fsi_get_current_fifo_samples(fsi, io);
+       sample_space    = io->buff_sample_capa - io->buff_sample_pos;
+
+       samples = min(sample_residues, sample_space);
+
+       return fsi_pio_transfer(fsi, io,
+                                 fsi_pio_pop16,
+                                 fsi_pio_pop32,
+                                 samples);
+}
+
+static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       int sample_residues;    /* ALSA residue samples */
+       int sample_space;       /* FSI fifo free samples space */
+       int samples;
+
+       sample_residues = io->buff_sample_capa - io->buff_sample_pos;
+       sample_space    = io->fifo_sample_capa -
+               fsi_get_current_fifo_samples(fsi, io);
+
+       samples = min(sample_residues, sample_space);
+
+       return fsi_pio_transfer(fsi, io,
+                                 fsi_pio_push16,
+                                 fsi_pio_push32,
+                                 samples);
+}
+
+static int fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
+                              int enable)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+       u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
+
+       if (enable)
+               fsi_irq_enable(fsi, io);
+       else
+               fsi_irq_disable(fsi, io);
+
+       if (fsi_is_clk_master(fsi))
+               fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
+
+       return 0;
+}
+
+static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       /*
+        * we can use 16bit stream mode
+        * when "playback" and "16bit data"
+        * and platform allows "stream mode"
+        * see
+        *      fsi_pio_push16()
+        */
+       if (fsi_is_enable_stream(fsi))
+               io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+                                BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
+       else
+               io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+                                BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
+       return 0;
+}
+
+static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       /*
+        * always 24bit bus, package back when "capture"
+        */
+       io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+                        BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
+       return 0;
+}
+
+static struct fsi_stream_handler fsi_pio_push_handler = {
+       .init           = fsi_pio_push_init,
+       .transfer       = fsi_pio_push,
+       .start_stop     = fsi_pio_start_stop,
+};
+
+static struct fsi_stream_handler fsi_pio_pop_handler = {
+       .init           = fsi_pio_pop_init,
+       .transfer       = fsi_pio_pop,
+       .start_stop     = fsi_pio_start_stop,
+};
+
+static irqreturn_t fsi_interrupt(int irq, void *data)
+{
+       struct fsi_master *master = data;
+       u32 int_st = fsi_irq_get_status(master);
+
+       /* clear irq status */
+       fsi_master_mask_set(master, SOFT_RST, IR, 0);
+       fsi_master_mask_set(master, SOFT_RST, IR, IR);
+
+       if (int_st & AB_IO(1, AO_SHIFT))
+               fsi_stream_transfer(&master->fsia.playback);
+       if (int_st & AB_IO(1, BO_SHIFT))
+               fsi_stream_transfer(&master->fsib.playback);
+       if (int_st & AB_IO(1, AI_SHIFT))
+               fsi_stream_transfer(&master->fsia.capture);
+       if (int_st & AB_IO(1, BI_SHIFT))
+               fsi_stream_transfer(&master->fsib.capture);
+
+       fsi_count_fifo_err(&master->fsia);
+       fsi_count_fifo_err(&master->fsib);
+
+       fsi_irq_clear_status(&master->fsia);
+       fsi_irq_clear_status(&master->fsib);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ *             dma data transfer handler
+ */
+static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       /*
+        * 24bit data : 24bit bus / package in back
+        * 16bit data : 16bit bus / stream mode
+        */
+       io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+                        BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
+
+       return 0;
+}
+
+static void fsi_dma_complete(void *data)
+{
+       struct fsi_stream *io = (struct fsi_stream *)data;
+       struct fsi_priv *fsi = fsi_stream_to_priv(io);
+
+       fsi_pointer_update(io, io->period_samples);
+
+       fsi_count_fifo_err(fsi);
+}
+
+static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+       struct snd_pcm_substream *substream = io->substream;
+       struct dma_async_tx_descriptor *desc;
+       int is_play = fsi_stream_is_play(fsi, io);
+       enum dma_transfer_direction dir;
+       int ret = -EIO;
+
+       if (is_play)
+               dir = DMA_MEM_TO_DEV;
+       else
+               dir = DMA_DEV_TO_MEM;
+
+       desc = dmaengine_prep_dma_cyclic(io->chan,
+                                        substream->runtime->dma_addr,
+                                        snd_pcm_lib_buffer_bytes(substream),
+                                        snd_pcm_lib_period_bytes(substream),
+                                        dir,
+                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_err(dai->dev, "dmaengine_prep_dma_cyclic() fail\n");
+               goto fsi_dma_transfer_err;
+       }
+
+       desc->callback          = fsi_dma_complete;
+       desc->callback_param    = io;
+
+       if (dmaengine_submit(desc) < 0) {
+               dev_err(dai->dev, "tx_submit() fail\n");
+               goto fsi_dma_transfer_err;
+       }
+
+       dma_async_issue_pending(io->chan);
+
+       /*
+        * FIXME
+        *
+        * In DMAEngine case, codec and FSI cannot be started simultaneously
+        * since FSI is using the scheduler work queue.
+        * Therefore, in capture case, probably FSI FIFO will have got
+        * overflow error in this point.
+        * in that case, DMA cannot start transfer until error was cleared.
+        */
+       if (!is_play) {
+               if (ERR_OVER & fsi_reg_read(fsi, DIFF_ST)) {
+                       fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR);
+                       fsi_reg_write(fsi, DIFF_ST, 0);
+               }
+       }
+
+       ret = 0;
+
+fsi_dma_transfer_err:
+       return ret;
+}
+
+static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
+                                int start)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+       u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
+       u32 enable = start ? DMA_ON : 0;
+
+       fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable);
+
+       dmaengine_terminate_all(io->chan);
+
+       if (fsi_is_clk_master(fsi))
+               fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
+
+       return 0;
+}
+
+static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
+{
+       int is_play = fsi_stream_is_play(fsi, io);
+
+#ifdef CONFIG_SUPERH
+       dma_cap_mask_t mask;
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       io->chan = dma_request_channel(mask, shdma_chan_filter,
+                                      (void *)io->dma_id);
+#else
+       io->chan = dma_request_chan(dev, is_play ? "tx" : "rx");
+       if (IS_ERR(io->chan))
+               io->chan = NULL;
+#endif
+       if (io->chan) {
+               struct dma_slave_config cfg = {};
+               int ret;
+
+               if (is_play) {
+                       cfg.dst_addr            = fsi->phys + REG_DODT;
+                       cfg.dst_addr_width      = DMA_SLAVE_BUSWIDTH_4_BYTES;
+                       cfg.direction           = DMA_MEM_TO_DEV;
+               } else {
+                       cfg.src_addr            = fsi->phys + REG_DIDT;
+                       cfg.src_addr_width      = DMA_SLAVE_BUSWIDTH_4_BYTES;
+                       cfg.direction           = DMA_DEV_TO_MEM;
+               }
+
+               ret = dmaengine_slave_config(io->chan, &cfg);
+               if (ret < 0) {
+                       dma_release_channel(io->chan);
+                       io->chan = NULL;
+               }
+       }
+
+       if (!io->chan) {
+
+               /* switch to PIO handler */
+               if (is_play)
+                       fsi->playback.handler   = &fsi_pio_push_handler;
+               else
+                       fsi->capture.handler    = &fsi_pio_pop_handler;
+
+               dev_info(dev, "switch handler (dma => pio)\n");
+
+               /* probe again */
+               return fsi_stream_probe(fsi, dev);
+       }
+
+       return 0;
+}
+
+static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+       fsi_stream_stop(fsi, io);
+
+       if (io->chan)
+               dma_release_channel(io->chan);
+
+       io->chan = NULL;
+       return 0;
+}
+
+static struct fsi_stream_handler fsi_dma_push_handler = {
+       .init           = fsi_dma_init,
+       .probe          = fsi_dma_probe,
+       .transfer       = fsi_dma_transfer,
+       .remove         = fsi_dma_remove,
+       .start_stop     = fsi_dma_push_start_stop,
+};
+
+/*
+ *             dai ops
+ */
+static void fsi_fifo_init(struct fsi_priv *fsi,
+                         struct fsi_stream *io,
+                         struct device *dev)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+       int is_play = fsi_stream_is_play(fsi, io);
+       u32 shift, i;
+       int frame_capa;
+
+       /* get on-chip RAM capacity */
+       shift = fsi_master_read(master, FIFO_SZ);
+       shift >>= fsi_get_port_shift(fsi, io);
+       shift &= FIFO_SZ_MASK;
+       frame_capa = 256 << shift;
+       dev_dbg(dev, "fifo = %d words\n", frame_capa);
+
+       /*
+        * The maximum number of sample data varies depending
+        * on the number of channels selected for the format.
+        *
+        * FIFOs are used in 4-channel units in 3-channel mode
+        * and in 8-channel units in 5- to 7-channel mode
+        * meaning that more FIFOs than the required size of DPRAM
+        * are used.
+        *
+        * ex) if 256 words of DP-RAM is connected
+        * 1 channel:  256 (256 x 1 = 256)
+        * 2 channels: 128 (128 x 2 = 256)
+        * 3 channels:  64 ( 64 x 3 = 192)
+        * 4 channels:  64 ( 64 x 4 = 256)
+        * 5 channels:  32 ( 32 x 5 = 160)
+        * 6 channels:  32 ( 32 x 6 = 192)
+        * 7 channels:  32 ( 32 x 7 = 224)
+        * 8 channels:  32 ( 32 x 8 = 256)
+        */
+       for (i = 1; i < fsi->chan_num; i <<= 1)
+               frame_capa >>= 1;
+       dev_dbg(dev, "%d channel %d store\n",
+               fsi->chan_num, frame_capa);
+
+       io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa);
+
+       /*
+        * set interrupt generation factor
+        * clear FIFO
+        */
+       if (is_play) {
+               fsi_reg_write(fsi,      DOFF_CTL, IRQ_HALF);
+               fsi_reg_mask_set(fsi,   DOFF_CTL, FIFO_CLR, FIFO_CLR);
+       } else {
+               fsi_reg_write(fsi,      DIFF_CTL, IRQ_HALF);
+               fsi_reg_mask_set(fsi,   DIFF_CTL, FIFO_CLR, FIFO_CLR);
+       }
+}
+
+static int fsi_hw_startup(struct fsi_priv *fsi,
+                         struct fsi_stream *io,
+                         struct device *dev)
+{
+       u32 data = 0;
+
+       /* clock setting */
+       if (fsi_is_clk_master(fsi))
+               data = DIMD | DOMD;
+
+       fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
+
+       /* clock inversion (CKG2) */
+       data = 0;
+       if (fsi->bit_clk_inv)
+               data |= (1 << 0);
+       if (fsi->lr_clk_inv)
+               data |= (1 << 4);
+       if (fsi_is_clk_master(fsi))
+               data <<= 8;
+       fsi_reg_write(fsi, CKG2, data);
+
+       /* spdif ? */
+       if (fsi_is_spdif(fsi)) {
+               fsi_spdif_clk_ctrl(fsi, 1);
+               fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
+       }
+
+       /*
+        * get bus settings
+        */
+       data = 0;
+       switch (io->sample_width) {
+       case 2:
+               data = BUSOP_GET(16, io->bus_option);
+               break;
+       case 4:
+               data = BUSOP_GET(24, io->bus_option);
+               break;
+       }
+       fsi_format_bus_setup(fsi, io, data, dev);
+
+       /* irq clear */
+       fsi_irq_disable(fsi, io);
+       fsi_irq_clear_status(fsi);
+
+       /* fifo init */
+       fsi_fifo_init(fsi, io, dev);
+
+       /* start master clock */
+       if (fsi_is_clk_master(fsi))
+               return fsi_clk_enable(dev, fsi);
+
+       return 0;
+}
+
+static int fsi_hw_shutdown(struct fsi_priv *fsi,
+                           struct device *dev)
+{
+       /* stop master clock */
+       if (fsi_is_clk_master(fsi))
+               return fsi_clk_disable(dev, fsi);
+
+       return 0;
+}
+
+static int fsi_dai_startup(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
+{
+       struct fsi_priv *fsi = fsi_get_priv(substream);
+
+       fsi_clk_invalid(fsi);
+
+       return 0;
+}
+
+static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct fsi_priv *fsi = fsi_get_priv(substream);
+
+       fsi_clk_invalid(fsi);
+}
+
+static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                          struct snd_soc_dai *dai)
+{
+       struct fsi_priv *fsi = fsi_get_priv(substream);
+       struct fsi_stream *io = fsi_stream_get(fsi, substream);
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               fsi_stream_init(fsi, io, substream);
+               if (!ret)
+                       ret = fsi_hw_startup(fsi, io, dai->dev);
+               if (!ret)
+                       ret = fsi_stream_start(fsi, io);
+               if (!ret)
+                       ret = fsi_stream_transfer(io);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (!ret)
+                       ret = fsi_hw_shutdown(fsi, dai->dev);
+               fsi_stream_stop(fsi, io);
+               fsi_stream_quit(fsi, io);
+               break;
+       }
+
+       return ret;
+}
+
+static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
+{
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               fsi->fmt = CR_I2S;
+               fsi->chan_num = 2;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               fsi->fmt = CR_PCM;
+               fsi->chan_num = 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
+{
+       struct fsi_master *master = fsi_get_master(fsi);
+
+       if (fsi_version(master) < 2)
+               return -EINVAL;
+
+       fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM;
+       fsi->chan_num = 2;
+
+       return 0;
+}
+
+static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai);
+       int ret;
+
+       /* set clock master audio interface */
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
+               break;
+       case SND_SOC_DAIFMT_BP_FP:
+               fsi->clk_master = 1; /* cpu is master */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_IF:
+               fsi->bit_clk_inv = 0;
+               fsi->lr_clk_inv = 1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               fsi->bit_clk_inv = 1;
+               fsi->lr_clk_inv = 0;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               fsi->bit_clk_inv = 1;
+               fsi->lr_clk_inv = 1;
+               break;
+       case SND_SOC_DAIFMT_NB_NF:
+       default:
+               fsi->bit_clk_inv = 0;
+               fsi->lr_clk_inv = 0;
+               break;
+       }
+
+       if (fsi_is_clk_master(fsi)) {
+               if (fsi->clk_cpg)
+                       fsi_clk_init(dai->dev, fsi, 0, 1, 1,
+                                    fsi_clk_set_rate_cpg);
+               else
+                       fsi_clk_init(dai->dev, fsi, 1, 1, 0,
+                                    fsi_clk_set_rate_external);
+       }
+
+       /* set format */
+       if (fsi_is_spdif(fsi))
+               ret = fsi_set_fmt_spdif(fsi);
+       else
+               ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+
+       return ret;
+}
+
+static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct fsi_priv *fsi = fsi_get_priv(substream);
+
+       if (fsi_is_clk_master(fsi))
+               fsi_clk_valid(fsi, params_rate(params));
+
+       return 0;
+}
+
+/*
+ * Select below from Sound Card, not auto
+ *     SND_SOC_DAIFMT_CBC_CFC
+ *     SND_SOC_DAIFMT_CBP_CFP
+ */
+static const u64 fsi_dai_formats =
+       SND_SOC_POSSIBLE_DAIFMT_I2S     |
+       SND_SOC_POSSIBLE_DAIFMT_LEFT_J  |
+       SND_SOC_POSSIBLE_DAIFMT_NB_NF   |
+       SND_SOC_POSSIBLE_DAIFMT_NB_IF   |
+       SND_SOC_POSSIBLE_DAIFMT_IB_NF   |
+       SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
+static const struct snd_soc_dai_ops fsi_dai_ops = {
+       .startup        = fsi_dai_startup,
+       .shutdown       = fsi_dai_shutdown,
+       .trigger        = fsi_dai_trigger,
+       .set_fmt        = fsi_dai_set_fmt,
+       .hw_params      = fsi_dai_hw_params,
+       .auto_selectable_formats        = &fsi_dai_formats,
+       .num_auto_selectable_formats    = 1,
+};
+
+/*
+ *             pcm ops
+ */
+
+static const struct snd_pcm_hardware fsi_pcm_hardware = {
+       .info =         SNDRV_PCM_INFO_INTERLEAVED      |
+                       SNDRV_PCM_INFO_MMAP             |
+                       SNDRV_PCM_INFO_MMAP_VALID,
+       .buffer_bytes_max       = 64 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8192,
+       .periods_min            = 1,
+       .periods_max            = 32,
+       .fifo_size              = 256,
+};
+
+static int fsi_pcm_open(struct snd_soc_component *component,
+                       struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret = 0;
+
+       snd_soc_set_runtime_hwparams(substream, &fsi_pcm_hardware);
+
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+
+       return ret;
+}
+
+static snd_pcm_uframes_t fsi_pointer(struct snd_soc_component *component,
+                                    struct snd_pcm_substream *substream)
+{
+       struct fsi_priv *fsi = fsi_get_priv(substream);
+       struct fsi_stream *io = fsi_stream_get(fsi, substream);
+
+       return fsi_sample2frame(fsi, io->buff_sample_pos);
+}
+
+/*
+ *             snd_soc_component
+ */
+
+#define PREALLOC_BUFFER                (32 * 1024)
+#define PREALLOC_BUFFER_MAX    (32 * 1024)
+
+static int fsi_pcm_new(struct snd_soc_component *component,
+                      struct snd_soc_pcm_runtime *rtd)
+{
+       snd_pcm_set_managed_buffer_all(
+               rtd->pcm,
+               SNDRV_DMA_TYPE_DEV,
+               rtd->card->snd_card->dev,
+               PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+       return 0;
+}
+
+/*
+ *             alsa struct
+ */
+
+static struct snd_soc_dai_driver fsi_soc_dai[] = {
+       {
+               .name                   = "fsia-dai",
+               .playback = {
+                       .rates          = FSI_RATES,
+                       .formats        = FSI_FMTS,
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+               },
+               .capture = {
+                       .rates          = FSI_RATES,
+                       .formats        = FSI_FMTS,
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+               },
+               .ops = &fsi_dai_ops,
+       },
+       {
+               .name                   = "fsib-dai",
+               .playback = {
+                       .rates          = FSI_RATES,
+                       .formats        = FSI_FMTS,
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+               },
+               .capture = {
+                       .rates          = FSI_RATES,
+                       .formats        = FSI_FMTS,
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+               },
+               .ops = &fsi_dai_ops,
+       },
+};
+
+static const struct snd_soc_component_driver fsi_soc_component = {
+       .name           = "fsi",
+       .open           = fsi_pcm_open,
+       .pointer        = fsi_pointer,
+       .pcm_construct  = fsi_pcm_new,
+};
+
+/*
+ *             platform function
+ */
+static void fsi_of_parse(char *name,
+                        struct device_node *np,
+                        struct sh_fsi_port_info *info,
+                        struct device *dev)
+{
+       int i;
+       char prop[128];
+       unsigned long flags = 0;
+       struct {
+               char *name;
+               unsigned int val;
+       } of_parse_property[] = {
+               { "spdif-connection",           SH_FSI_FMT_SPDIF },
+               { "stream-mode-support",        SH_FSI_ENABLE_STREAM_MODE },
+               { "use-internal-clock",         SH_FSI_CLK_CPG },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(of_parse_property); i++) {
+               sprintf(prop, "%s,%s", name, of_parse_property[i].name);
+               if (of_property_present(np, prop))
+                       flags |= of_parse_property[i].val;
+       }
+       info->flags = flags;
+
+       dev_dbg(dev, "%s flags : %lx\n", name, info->flags);
+}
+
+static void fsi_port_info_init(struct fsi_priv *fsi,
+                              struct sh_fsi_port_info *info)
+{
+       if (info->flags & SH_FSI_FMT_SPDIF)
+               fsi->spdif = 1;
+
+       if (info->flags & SH_FSI_CLK_CPG)
+               fsi->clk_cpg = 1;
+
+       if (info->flags & SH_FSI_ENABLE_STREAM_MODE)
+               fsi->enable_stream = 1;
+}
+
+static void fsi_handler_init(struct fsi_priv *fsi,
+                            struct sh_fsi_port_info *info)
+{
+       fsi->playback.handler   = &fsi_pio_push_handler; /* default PIO */
+       fsi->playback.priv      = fsi;
+       fsi->capture.handler    = &fsi_pio_pop_handler;  /* default PIO */
+       fsi->capture.priv       = fsi;
+
+       if (info->tx_id) {
+               fsi->playback.dma_id  = info->tx_id;
+               fsi->playback.handler = &fsi_dma_push_handler;
+       }
+}
+
+static const struct fsi_core fsi1_core = {
+       .ver    = 1,
+
+       /* Interrupt */
+       .int_st = INT_ST,
+       .iemsk  = IEMSK,
+       .imsk   = IMSK,
+};
+
+static const struct fsi_core fsi2_core = {
+       .ver    = 2,
+
+       /* Interrupt */
+       .int_st = CPU_INT_ST,
+       .iemsk  = CPU_IEMSK,
+       .imsk   = CPU_IMSK,
+       .a_mclk = A_MST_CTLR,
+       .b_mclk = B_MST_CTLR,
+};
+
+static const struct of_device_id fsi_of_match[] = {
+       { .compatible = "renesas,sh_fsi",       .data = &fsi1_core},
+       { .compatible = "renesas,sh_fsi2",      .data = &fsi2_core},
+       {},
+};
+MODULE_DEVICE_TABLE(of, fsi_of_match);
+
+static const struct platform_device_id fsi_id_table[] = {
+       { "sh_fsi",     (kernel_ulong_t)&fsi1_core },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, fsi_id_table);
+
+static int fsi_probe(struct platform_device *pdev)
+{
+       struct fsi_master *master;
+       struct device_node *np = pdev->dev.of_node;
+       struct sh_fsi_platform_info info;
+       const struct fsi_core *core;
+       struct fsi_priv *fsi;
+       struct resource *res;
+       unsigned int irq;
+       int ret;
+
+       memset(&info, 0, sizeof(info));
+
+       core = NULL;
+       if (np) {
+               core = of_device_get_match_data(&pdev->dev);
+               fsi_of_parse("fsia", np, &info.port_a, &pdev->dev);
+               fsi_of_parse("fsib", np, &info.port_b, &pdev->dev);
+       } else {
+               const struct platform_device_id *id_entry = pdev->id_entry;
+               if (id_entry)
+                       core = (struct fsi_core *)id_entry->driver_data;
+
+               if (pdev->dev.platform_data)
+                       memcpy(&info, pdev->dev.platform_data, sizeof(info));
+       }
+
+       if (!core) {
+               dev_err(&pdev->dev, "unknown fsi device\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (!res || (int)irq <= 0) {
+               dev_err(&pdev->dev, "Not enough FSI platform resources.\n");
+               return -ENODEV;
+       }
+
+       master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
+       if (!master)
+               return -ENOMEM;
+
+       master->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!master->base) {
+               dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n");
+               return -ENXIO;
+       }
+
+       /* master setting */
+       master->core            = core;
+       spin_lock_init(&master->lock);
+
+       /* FSI A setting */
+       fsi             = &master->fsia;
+       fsi->base       = master->base;
+       fsi->phys       = res->start;
+       fsi->master     = master;
+       fsi_port_info_init(fsi, &info.port_a);
+       fsi_handler_init(fsi, &info.port_a);
+       ret = fsi_stream_probe(fsi, &pdev->dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "FSIA stream probe failed\n");
+               return ret;
+       }
+
+       /* FSI B setting */
+       fsi             = &master->fsib;
+       fsi->base       = master->base + 0x40;
+       fsi->phys       = res->start + 0x40;
+       fsi->master     = master;
+       fsi_port_info_init(fsi, &info.port_b);
+       fsi_handler_init(fsi, &info.port_b);
+       ret = fsi_stream_probe(fsi, &pdev->dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "FSIB stream probe failed\n");
+               goto exit_fsia;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       dev_set_drvdata(&pdev->dev, master);
+
+       ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0,
+                              dev_name(&pdev->dev), master);
+       if (ret) {
+               dev_err(&pdev->dev, "irq request err\n");
+               goto exit_fsib;
+       }
+
+       ret = devm_snd_soc_register_component(&pdev->dev, &fsi_soc_component,
+                                   fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
+       if (ret < 0) {
+               dev_err(&pdev->dev, "cannot snd component register\n");
+               goto exit_fsib;
+       }
+
+       return ret;
+
+exit_fsib:
+       pm_runtime_disable(&pdev->dev);
+       fsi_stream_remove(&master->fsib);
+exit_fsia:
+       fsi_stream_remove(&master->fsia);
+
+       return ret;
+}
+
+static void fsi_remove(struct platform_device *pdev)
+{
+       struct fsi_master *master;
+
+       master = dev_get_drvdata(&pdev->dev);
+
+       pm_runtime_disable(&pdev->dev);
+
+       fsi_stream_remove(&master->fsia);
+       fsi_stream_remove(&master->fsib);
+}
+
+static void __fsi_suspend(struct fsi_priv *fsi,
+                         struct fsi_stream *io,
+                         struct device *dev)
+{
+       if (!fsi_stream_is_working(fsi, io))
+               return;
+
+       fsi_stream_stop(fsi, io);
+       fsi_hw_shutdown(fsi, dev);
+}
+
+static void __fsi_resume(struct fsi_priv *fsi,
+                        struct fsi_stream *io,
+                        struct device *dev)
+{
+       if (!fsi_stream_is_working(fsi, io))
+               return;
+
+       fsi_hw_startup(fsi, io, dev);
+       fsi_stream_start(fsi, io);
+}
+
+static int fsi_suspend(struct device *dev)
+{
+       struct fsi_master *master = dev_get_drvdata(dev);
+       struct fsi_priv *fsia = &master->fsia;
+       struct fsi_priv *fsib = &master->fsib;
+
+       __fsi_suspend(fsia, &fsia->playback, dev);
+       __fsi_suspend(fsia, &fsia->capture, dev);
+
+       __fsi_suspend(fsib, &fsib->playback, dev);
+       __fsi_suspend(fsib, &fsib->capture, dev);
+
+       return 0;
+}
+
+static int fsi_resume(struct device *dev)
+{
+       struct fsi_master *master = dev_get_drvdata(dev);
+       struct fsi_priv *fsia = &master->fsia;
+       struct fsi_priv *fsib = &master->fsib;
+
+       __fsi_resume(fsia, &fsia->playback, dev);
+       __fsi_resume(fsia, &fsia->capture, dev);
+
+       __fsi_resume(fsib, &fsib->playback, dev);
+       __fsi_resume(fsib, &fsib->capture, dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops fsi_pm_ops = {
+       .suspend                = fsi_suspend,
+       .resume                 = fsi_resume,
+};
+
+static struct platform_driver fsi_driver = {
+       .driver         = {
+               .name   = "fsi-pcm-audio",
+               .pm     = &fsi_pm_ops,
+               .of_match_table = fsi_of_match,
+       },
+       .probe          = fsi_probe,
+       .remove         = fsi_remove,
+       .id_table       = fsi_id_table,
+};
+
+module_platform_driver(fsi_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SuperH onchip FSI audio driver");
+MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
+MODULE_ALIAS("platform:fsi-pcm-audio");
diff --git a/sound/soc/renesas/hac.c b/sound/soc/renesas/hac.c
new file mode 100644 (file)
index 0000000..db618c0
--- /dev/null
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Hitachi Audio Controller (AC97) support for SH7760/SH7780
+//
+// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+//
+// dont forget to set IPSEL/OMSEL register bits (in your board code) to
+// enable HAC output pins!
+
+/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
+ * the FIRST can be used since ASoC does not pass any information to the
+ * ac97_read/write() functions regarding WHICH unit to use.  You'll have
+ * to edit the code a bit to use the other AC97 unit.          --mlau
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+/* regs and bits */
+#define HACCR          0x08
+#define HACCSAR                0x20
+#define HACCSDR                0x24
+#define HACPCML                0x28
+#define HACPCMR                0x2C
+#define HACTIER                0x50
+#define        HACTSR          0x54
+#define HACRIER                0x58
+#define HACRSR         0x5C
+#define HACACR         0x60
+
+#define CR_CR          (1 << 15)       /* "codec-ready" indicator */
+#define CR_CDRT                (1 << 11)       /* cold reset */
+#define CR_WMRT                (1 << 10)       /* warm reset */
+#define CR_B9          (1 << 9)        /* the mysterious "bit 9" */
+#define CR_ST          (1 << 5)        /* AC97 link start bit */
+
+#define CSAR_RD                (1 << 19)       /* AC97 data read bit */
+#define CSAR_WR                (0)
+
+#define TSR_CMDAMT     (1 << 31)
+#define TSR_CMDDMT     (1 << 30)
+
+#define RSR_STARY      (1 << 22)
+#define RSR_STDRY      (1 << 21)
+
+#define ACR_DMARX16    (1 << 30)
+#define ACR_DMATX16    (1 << 29)
+#define ACR_TX12ATOM   (1 << 26)
+#define ACR_DMARX20    ((1 << 24) | (1 << 22))
+#define ACR_DMATX20    ((1 << 23) | (1 << 21))
+
+#define CSDR_SHIFT     4
+#define CSDR_MASK      (0xffff << CSDR_SHIFT)
+#define CSAR_SHIFT     12
+#define CSAR_MASK      (0x7f << CSAR_SHIFT)
+
+#define AC97_WRITE_RETRY       1
+#define AC97_READ_RETRY                5
+
+/* manual-suggested AC97 codec access timeouts (us) */
+#define TMO_E1 500     /* 21 < E1 < 1000 */
+#define TMO_E2 13      /* 13 < E2 */
+#define TMO_E3 21      /* 21 < E3 */
+#define TMO_E4 500     /* 21 < E4 < 1000 */
+
+struct hac_priv {
+       unsigned long mmio;     /* HAC base address */
+} hac_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+       {
+               .mmio   = 0xFE240000,
+       },
+       {
+               .mmio   = 0xFE250000,
+       },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+       {
+               .mmio   = 0xFFE40000,
+       },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+#define HACREG(reg)    (*(unsigned long *)(hac->mmio + (reg)))
+
+/*
+ * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906)
+ */
+static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
+                             unsigned short *v)
+{
+       unsigned int to1, to2, i;
+       unsigned short adr;
+
+       for (i = AC97_READ_RETRY; i; i--) {
+               *v = 0;
+               /* wait for HAC to receive something from the codec */
+               for (to1 = TMO_E4;
+                    to1 && !(HACREG(HACRSR) & RSR_STARY);
+                    --to1)
+                       udelay(1);
+               for (to2 = TMO_E4; 
+                    to2 && !(HACREG(HACRSR) & RSR_STDRY);
+                    --to2)
+                       udelay(1);
+
+               if (!to1 && !to2)
+                       return 0;       /* codec comm is down */
+
+               adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT);
+               *v  = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT);
+
+               HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+
+               if (r == adr)
+                       break;
+
+               /* manual says: wait at least 21 usec before retrying */
+               udelay(21);
+       }
+       HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+       return i;
+}
+
+static unsigned short hac_read_codec_aux(struct hac_priv *hac,
+                                        unsigned short reg)
+{
+       unsigned short val;
+       unsigned int i, to;
+
+       for (i = AC97_READ_RETRY; i; i--) {
+               /* send_read_request */
+               local_irq_disable();
+               HACREG(HACTSR) &= ~(TSR_CMDAMT);
+               HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD;
+               local_irq_enable();
+
+               for (to = TMO_E3;
+                    to && !(HACREG(HACTSR) & TSR_CMDAMT);
+                    --to)
+                       udelay(1);
+
+               HACREG(HACTSR) &= ~TSR_CMDAMT;
+               val = 0;
+               if (hac_get_codec_data(hac, reg, &val) != 0)
+                       break;
+       }
+
+       return i ? val : ~0;
+}
+
+static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+                          unsigned short val)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac = &hac_cpu_data[unit_id];
+       unsigned int i, to;
+       /* write_codec_aux */
+       for (i = AC97_WRITE_RETRY; i; i--) {
+               /* send_write_request */
+               local_irq_disable();
+               HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
+               HACREG(HACCSDR) = (val << CSDR_SHIFT);
+               HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD);
+               local_irq_enable();
+
+               /* poll-wait for CMDAMT and CMDDMT */
+               for (to = TMO_E1;
+                    to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT));
+                    --to)
+                       udelay(1);
+
+               HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT);
+               if (to)
+                       break;
+               /* timeout, try again */
+       }
+}
+
+static unsigned short hac_ac97_read(struct snd_ac97 *ac97,
+                                   unsigned short reg)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac = &hac_cpu_data[unit_id];
+       return hac_read_codec_aux(hac, reg);
+}
+
+static void hac_ac97_warmrst(struct snd_ac97 *ac97)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac = &hac_cpu_data[unit_id];
+       unsigned int tmo;
+
+       HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9;
+       msleep(10);
+       HACREG(HACCR) = CR_ST | CR_B9;
+       for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--)
+               udelay(1);
+
+       if (!tmo)
+               printk(KERN_INFO "hac: reset: AC97 link down!\n");
+       /* settings this bit lets us have a conversation with codec */
+       HACREG(HACACR) |= ACR_TX12ATOM;
+}
+
+static void hac_ac97_coldrst(struct snd_ac97 *ac97)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac;
+       hac = &hac_cpu_data[unit_id];
+
+       HACREG(HACCR) = 0;
+       HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9;
+       msleep(10);
+       hac_ac97_warmrst(ac97);
+}
+
+static struct snd_ac97_bus_ops hac_ac97_ops = {
+       .read   = hac_ac97_read,
+       .write  = hac_ac97_write,
+       .reset  = hac_ac97_coldrst,
+       .warm_reset = hac_ac97_warmrst,
+};
+
+static int hac_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params,
+                        struct snd_soc_dai *dai)
+{
+       struct hac_priv *hac = &hac_cpu_data[dai->id];
+       int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+       switch (params->msbits) {
+       case 16:
+               HACREG(HACACR) |= d ?  ACR_DMARX16 :  ACR_DMATX16;
+               HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20;
+               break;
+       case 20:
+               HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16;
+               HACREG(HACACR) |= d ?  ACR_DMARX20 :  ACR_DMATX20;
+               break;
+       default:
+               pr_debug("hac: invalid depth %d bit\n", params->msbits);
+               return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+#define AC97_RATES     \
+       SNDRV_PCM_RATE_8000_192000
+
+#define AC97_FMTS      \
+       SNDRV_PCM_FMTBIT_S16_LE
+
+static const struct snd_soc_dai_ops hac_dai_ops = {
+       .hw_params      = hac_hw_params,
+};
+
+static struct snd_soc_dai_driver sh4_hac_dai[] = {
+{
+       .name                   = "hac-dai.0",
+       .playback = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .capture = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .ops = &hac_dai_ops,
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+       .name                   = "hac-dai.1",
+       .id                     = 1,
+       .playback = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .capture = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .ops = &hac_dai_ops,
+
+},
+#endif
+};
+
+static const struct snd_soc_component_driver sh4_hac_component = {
+       .name                   = "sh4-hac",
+       .legacy_dai_naming      = 1,
+};
+
+static int hac_soc_platform_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = snd_soc_set_ac97_ops(&hac_ac97_ops);
+       if (ret != 0)
+               return ret;
+
+       return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component,
+                                         sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+}
+
+static void hac_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_set_ac97_ops(NULL);
+}
+
+static struct platform_driver hac_pcm_driver = {
+       .driver = {
+                       .name = "hac-pcm-audio",
+       },
+
+       .probe = hac_soc_platform_probe,
+       .remove = hac_soc_platform_remove,
+};
+
+module_platform_driver(hac_pcm_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/renesas/migor.c b/sound/soc/renesas/migor.c
new file mode 100644 (file)
index 0000000..5a0bc6e
--- /dev/null
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ALSA SoC driver for Migo-R
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+
+#include <asm/clock.h>
+
+#include <cpu/sh7722.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm8978.h"
+#include "siu.h"
+
+/* Default 8000Hz sampling frequency */
+static unsigned long codec_freq = 8000 * 512;
+
+static unsigned int use_count;
+
+/* External clock, sourced from the codec at the SIUMCKB pin */
+static unsigned long siumckb_recalc(struct clk *clk)
+{
+       return codec_freq;
+}
+
+static struct sh_clk_ops siumckb_clk_ops = {
+       .recalc = siumckb_recalc,
+};
+
+static struct clk siumckb_clk = {
+       .ops            = &siumckb_clk_ops,
+       .rate           = 0, /* initialised at run-time */
+};
+
+static struct clk_lookup *siumckb_lookup;
+
+static int migor_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+       int ret;
+       unsigned int rate = params_rate(params);
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512);
+       if (ret < 0)
+               return ret;
+
+       codec_freq = rate * 512;
+       /*
+        * This propagates the parent frequency change to children and
+        * recalculates the frequency table
+        */
+       clk_set_rate(&siumckb_clk, codec_freq);
+       dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
+
+       ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), SIU_CLKB_EXT,
+                                    codec_freq / 2, SND_SOC_CLOCK_IN);
+
+       if (!ret)
+               use_count++;
+
+       return ret;
+}
+
+static int migor_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+
+       if (use_count) {
+               use_count--;
+
+               if (!use_count)
+                       snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0,
+                                              SND_SOC_CLOCK_IN);
+       } else {
+               dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n");
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops migor_dai_ops = {
+       .hw_params = migor_hw_params,
+       .hw_free = migor_hw_free,
+};
+
+static const struct snd_soc_dapm_widget migor_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Onboard Microphone", NULL),
+       SND_SOC_DAPM_MIC("External Microphone", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Headphone output connected to LHP/RHP, enable OUT4 for VMID */
+       { "Headphone", NULL,  "OUT4 VMID" },
+       { "OUT4 VMID", NULL,  "LHP" },
+       { "OUT4 VMID", NULL,  "RHP" },
+
+       /* On-board microphone */
+       { "RMICN", NULL, "Mic Bias" },
+       { "RMICP", NULL, "Mic Bias" },
+       { "Mic Bias", NULL, "Onboard Microphone" },
+
+       /* External microphone */
+       { "LMICN", NULL, "Mic Bias" },
+       { "LMICP", NULL, "Mic Bias" },
+       { "Mic Bias", NULL, "External Microphone" },
+};
+
+/* migor digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEFS(wm8978,
+       DAILINK_COMP_ARRAY(COMP_CPU("siu-pcm-audio")),
+       DAILINK_COMP_ARRAY(COMP_CODEC("wm8978.0-001a", "wm8978-hifi")),
+       DAILINK_COMP_ARRAY(COMP_PLATFORM("siu-pcm-audio")));
+
+static struct snd_soc_dai_link migor_dai = {
+       .name = "wm8978",
+       .stream_name = "WM8978",
+       .dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S |
+                  SND_SOC_DAIFMT_CBS_CFS,
+       .ops = &migor_dai_ops,
+       SND_SOC_DAILINK_REG(wm8978),
+};
+
+/* migor audio machine driver */
+static struct snd_soc_card snd_soc_migor = {
+       .name = "Migo-R",
+       .owner = THIS_MODULE,
+       .dai_link = &migor_dai,
+       .num_links = 1,
+
+       .dapm_widgets = migor_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(migor_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static struct platform_device *migor_snd_device;
+
+static int __init migor_init(void)
+{
+       int ret;
+
+       ret = clk_register(&siumckb_clk);
+       if (ret < 0)
+               return ret;
+
+       siumckb_lookup = clkdev_create(&siumckb_clk, "siumckb_clk", NULL);
+       if (!siumckb_lookup) {
+               ret = -ENOMEM;
+               goto eclkdevalloc;
+       }
+
+       /* Port number used on this machine: port B */
+       migor_snd_device = platform_device_alloc("soc-audio", 1);
+       if (!migor_snd_device) {
+               ret = -ENOMEM;
+               goto epdevalloc;
+       }
+
+       platform_set_drvdata(migor_snd_device, &snd_soc_migor);
+
+       ret = platform_device_add(migor_snd_device);
+       if (ret)
+               goto epdevadd;
+
+       return 0;
+
+epdevadd:
+       platform_device_put(migor_snd_device);
+epdevalloc:
+       clkdev_drop(siumckb_lookup);
+eclkdevalloc:
+       clk_unregister(&siumckb_clk);
+       return ret;
+}
+
+static void __exit migor_exit(void)
+{
+       clkdev_drop(siumckb_lookup);
+       clk_unregister(&siumckb_clk);
+       platform_device_unregister(migor_snd_device);
+}
+
+module_init(migor_init);
+module_exit(migor_exit);
+
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_DESCRIPTION("ALSA SoC Migor");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/renesas/rcar/Makefile b/sound/soc/renesas/rcar/Makefile
new file mode 100644 (file)
index 0000000..45eb875
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+snd-soc-rcar-y         := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o
+obj-$(CONFIG_SND_SOC_RCAR)     += snd-soc-rcar.o
diff --git a/sound/soc/renesas/rcar/adg.c b/sound/soc/renesas/rcar/adg.c
new file mode 100644 (file)
index 0000000..0f190ab
--- /dev/null
@@ -0,0 +1,775 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Helper routines for R-Car sound ADG.
+//
+//  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include "rsnd.h"
+
+#define CLKA   0
+#define CLKB   1
+#define CLKC   2
+#define CLKI   3
+#define CLKINMAX 4
+
+#define CLKOUT 0
+#define CLKOUT1        1
+#define CLKOUT2        2
+#define CLKOUT3        3
+#define CLKOUTMAX 4
+
+#define BRRx_MASK(x) (0x3FF & x)
+
+static struct rsnd_mod_ops adg_ops = {
+       .name = "adg",
+};
+
+#define ADG_HZ_441     0
+#define ADG_HZ_48      1
+#define ADG_HZ_SIZE    2
+
+struct rsnd_adg {
+       struct clk *clkin[CLKINMAX];
+       struct clk *clkout[CLKOUTMAX];
+       struct clk *null_clk;
+       struct clk_onecell_data onecell;
+       struct rsnd_mod mod;
+       int clkin_rate[CLKINMAX];
+       int clkin_size;
+       int clkout_size;
+       u32 ckr;
+       u32 brga;
+       u32 brgb;
+
+       int brg_rate[ADG_HZ_SIZE]; /* BRGA / BRGB */
+};
+
+#define for_each_rsnd_clkin(pos, adg, i)       \
+       for (i = 0;                             \
+            (i < adg->clkin_size) &&           \
+            ((pos) = adg->clkin[i]);           \
+            i++)
+#define for_each_rsnd_clkout(pos, adg, i)      \
+       for (i = 0;                             \
+            (i < adg->clkout_size) &&          \
+            ((pos) = adg->clkout[i]);  \
+            i++)
+#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
+
+static const char * const clkin_name_gen4[] = {
+       [CLKA]  = "clkin",
+};
+
+static const char * const clkin_name_gen2[] = {
+       [CLKA]  = "clk_a",
+       [CLKB]  = "clk_b",
+       [CLKC]  = "clk_c",
+       [CLKI]  = "clk_i",
+};
+
+static const char * const clkout_name_gen2[] = {
+       [CLKOUT]  = "audio_clkout",
+       [CLKOUT1] = "audio_clkout1",
+       [CLKOUT2] = "audio_clkout2",
+       [CLKOUT3] = "audio_clkout3",
+};
+
+static u32 rsnd_adg_calculate_brgx(unsigned long div)
+{
+       int i;
+
+       if (!div)
+               return 0;
+
+       for (i = 3; i >= 0; i--) {
+               int ratio = 2 << (i * 2);
+               if (0 == (div % ratio))
+                       return (u32)((i << 8) | ((div / ratio) - 1));
+       }
+
+       return ~0;
+}
+
+static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+       int id = rsnd_mod_id(ssi_mod);
+       int ws = id;
+
+       if (rsnd_ssi_is_pin_sharing(io)) {
+               switch (id) {
+               case 1:
+               case 2:
+               case 9:
+                       ws = 0;
+                       break;
+               case 4:
+                       ws = 3;
+                       break;
+               case 8:
+                       ws = 7;
+                       break;
+               }
+       } else {
+               /*
+                * SSI8 is not connected to ADG.
+                * Thus SSI9 is using ws = 8
+                */
+               if (id == 9)
+                       ws = 8;
+       }
+
+       return (0x6 + ws) << 8;
+}
+
+static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
+                                      struct rsnd_dai_stream *io,
+                                      unsigned int target_rate,
+                                      unsigned int *target_val,
+                                      unsigned int *target_en)
+{
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int sel;
+       unsigned int val, en;
+       unsigned int min, diff;
+       unsigned int sel_rate[] = {
+               adg->clkin_rate[CLKA],  /* 0000: CLKA */
+               adg->clkin_rate[CLKB],  /* 0001: CLKB */
+               adg->clkin_rate[CLKC],  /* 0010: CLKC */
+               adg->brg_rate[ADG_HZ_441],      /* 0011: BRGA */
+               adg->brg_rate[ADG_HZ_48],       /* 0100: BRGB */
+       };
+
+       min = ~0;
+       val = 0;
+       en = 0;
+       for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
+               int idx = 0;
+               int step = 2;
+               int div;
+
+               if (!sel_rate[sel])
+                       continue;
+
+               for (div = 2; div <= 98304; div += step) {
+                       diff = abs(target_rate - sel_rate[sel] / div);
+                       if (min > diff) {
+                               val = (sel << 8) | idx;
+                               min = diff;
+                               en = 1 << (sel + 1); /* fixme */
+                       }
+
+                       /*
+                        * step of 0_0000 / 0_0001 / 0_1101
+                        * are out of order
+                        */
+                       if ((idx > 2) && (idx % 2))
+                               step *= 2;
+                       if (idx == 0x1c) {
+                               div += step;
+                               step *= 2;
+                       }
+                       idx++;
+               }
+       }
+
+       if (min == ~0) {
+               dev_err(dev, "no Input clock\n");
+               return;
+       }
+
+       *target_val = val;
+       if (target_en)
+               *target_en = en;
+}
+
+static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
+                                      struct rsnd_dai_stream *io,
+                                      unsigned int in_rate,
+                                      unsigned int out_rate,
+                                      u32 *in, u32 *out, u32 *en)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       unsigned int target_rate;
+       u32 *target_val;
+       u32 _in;
+       u32 _out;
+       u32 _en;
+
+       /* default = SSI WS */
+       _in =
+       _out = rsnd_adg_ssi_ws_timing_gen2(io);
+
+       target_rate = 0;
+       target_val = NULL;
+       _en = 0;
+       if (runtime->rate != in_rate) {
+               target_rate = out_rate;
+               target_val  = &_out;
+       } else if (runtime->rate != out_rate) {
+               target_rate = in_rate;
+               target_val  = &_in;
+       }
+
+       if (target_rate)
+               __rsnd_adg_get_timesel_ratio(priv, io,
+                                            target_rate,
+                                            target_val, &_en);
+
+       if (in)
+               *in = _in;
+       if (out)
+               *out = _out;
+       if (en)
+               *en = _en;
+}
+
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
+                                struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+       int id = rsnd_mod_id(cmd_mod);
+       int shift = (id % 2) ? 16 : 0;
+       u32 mask, val;
+
+       rsnd_adg_get_timesel_ratio(priv, io,
+                                  rsnd_src_get_in_rate(priv, io),
+                                  rsnd_src_get_out_rate(priv, io),
+                                  NULL, &val, NULL);
+
+       val  = val      << shift;
+       mask = 0x0f1f   << shift;
+
+       rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val);
+
+       return 0;
+}
+
+int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
+                                 struct rsnd_dai_stream *io,
+                                 unsigned int in_rate,
+                                 unsigned int out_rate)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+       u32 in, out;
+       u32 mask, en;
+       int id = rsnd_mod_id(src_mod);
+       int shift = (id % 2) ? 16 : 0;
+
+       rsnd_mod_make_sure(src_mod, RSND_MOD_SRC);
+
+       rsnd_adg_get_timesel_ratio(priv, io,
+                                  in_rate, out_rate,
+                                  &in, &out, &en);
+
+       in   = in       << shift;
+       out  = out      << shift;
+       mask = 0x0f1f   << shift;
+
+       rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2),  mask, in);
+       rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out);
+
+       if (en)
+               rsnd_mod_bset(adg_mod, DIV_EN, en, en);
+
+       return 0;
+}
+
+static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int id = rsnd_mod_id(ssi_mod);
+       int shift = (id % 4) * 8;
+       u32 mask = 0xFF << shift;
+
+       rsnd_mod_make_sure(ssi_mod, RSND_MOD_SSI);
+
+       val = val << shift;
+
+       /*
+        * SSI 8 is not connected to ADG.
+        * it works with SSI 7
+        */
+       if (id == 8)
+               return;
+
+       rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val);
+
+       dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
+}
+
+int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
+{
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct clk *clk;
+       int i;
+       int sel_table[] = {
+               [CLKA] = 0x1,
+               [CLKB] = 0x2,
+               [CLKC] = 0x3,
+               [CLKI] = 0x0,
+       };
+
+       /*
+        * find suitable clock from
+        * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
+        */
+       for_each_rsnd_clkin(clk, adg, i)
+               if (rate == adg->clkin_rate[i])
+                       return sel_table[i];
+
+       /*
+        * find divided clock from BRGA/BRGB
+        */
+       if (rate == adg->brg_rate[ADG_HZ_441])
+               return 0x10;
+
+       if (rate == adg->brg_rate[ADG_HZ_48])
+               return 0x20;
+
+       return -EIO;
+}
+
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
+{
+       rsnd_adg_set_ssi_clk(ssi_mod, 0);
+
+       return 0;
+}
+
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+       int data;
+       u32 ckr = 0;
+
+       data = rsnd_adg_clk_query(priv, rate);
+       if (data < 0)
+               return data;
+
+       rsnd_adg_set_ssi_clk(ssi_mod, data);
+
+       if (0 == (rate % 8000))
+               ckr = 0x80000000; /* BRGB output = 48kHz */
+
+       rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
+
+       dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
+               (ckr) ? 'B' : 'A',
+               (ckr) ? adg->brg_rate[ADG_HZ_48] :
+                       adg->brg_rate[ADG_HZ_441]);
+
+       return 0;
+}
+
+void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
+{
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
+       struct clk *clk;
+       int i;
+
+       if (enable) {
+               rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr);
+               rsnd_mod_write(adg_mod, BRRA,  adg->brga);
+               rsnd_mod_write(adg_mod, BRRB,  adg->brgb);
+       }
+
+       for_each_rsnd_clkin(clk, adg, i) {
+               if (enable) {
+                       clk_prepare_enable(clk);
+
+                       /*
+                        * We shouldn't use clk_get_rate() under
+                        * atomic context. Let's keep it when
+                        * rsnd_adg_clk_enable() was called
+                        */
+                       adg->clkin_rate[i] = clk_get_rate(clk);
+               } else {
+                       clk_disable_unprepare(clk);
+               }
+       }
+}
+
+static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv,
+                                           const char * const name,
+                                           const char *parent)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+
+       clk = clk_register_fixed_rate(dev, name, parent, 0, 0);
+       if (IS_ERR_OR_NULL(clk)) {
+               dev_err(dev, "create null clk error\n");
+               return ERR_CAST(clk);
+       }
+
+       return clk;
+}
+
+static struct clk *rsnd_adg_null_clk_get(struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg = priv->adg;
+
+       if (!adg->null_clk) {
+               static const char * const name = "rsnd_adg_null";
+
+               adg->null_clk = rsnd_adg_create_null_clk(priv, name, NULL);
+       }
+
+       return adg->null_clk;
+}
+
+static void rsnd_adg_null_clk_clean(struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg = priv->adg;
+
+       if (adg->null_clk)
+               clk_unregister_fixed_rate(adg->null_clk);
+}
+
+static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg = priv->adg;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+       const char * const *clkin_name;
+       int clkin_size;
+       int i;
+
+       clkin_name = clkin_name_gen2;
+       clkin_size = ARRAY_SIZE(clkin_name_gen2);
+       if (rsnd_is_gen4(priv)) {
+               clkin_name = clkin_name_gen4;
+               clkin_size = ARRAY_SIZE(clkin_name_gen4);
+       }
+
+       for (i = 0; i < clkin_size; i++) {
+               clk = devm_clk_get(dev, clkin_name[i]);
+
+               if (IS_ERR_OR_NULL(clk))
+                       clk = rsnd_adg_null_clk_get(priv);
+               if (IS_ERR_OR_NULL(clk))
+                       goto err;
+
+               adg->clkin[i] = clk;
+       }
+
+       adg->clkin_size = clkin_size;
+
+       return 0;
+
+err:
+       dev_err(dev, "adg clock IN get failed\n");
+
+       rsnd_adg_null_clk_clean(priv);
+
+       return -EIO;
+}
+
+static void rsnd_adg_unregister_clkout(struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg = priv->adg;
+       struct clk *clk;
+       int i;
+
+       for_each_rsnd_clkout(clk, adg, i)
+               clk_unregister_fixed_rate(clk);
+}
+
+static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg = priv->adg;
+       struct clk *clk;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *np = dev->of_node;
+       struct property *prop;
+       u32 ckr, brgx, brga, brgb;
+       u32 req_rate[ADG_HZ_SIZE] = {};
+       uint32_t count = 0;
+       unsigned long req_Hz[ADG_HZ_SIZE];
+       int clkout_size;
+       int i, req_size;
+       int approximate = 0;
+       const char *parent_clk_name = NULL;
+       const char * const *clkout_name;
+       int brg_table[] = {
+               [CLKA] = 0x0,
+               [CLKB] = 0x1,
+               [CLKC] = 0x4,
+               [CLKI] = 0x2,
+       };
+
+       ckr = 0;
+       brga = 0xff; /* default */
+       brgb = 0xff; /* default */
+
+       /*
+        * ADG supports BRRA/BRRB output only
+        * this means all clkout0/1/2/3 will be same rate
+        */
+       prop = of_find_property(np, "clock-frequency", NULL);
+       if (!prop)
+               goto rsnd_adg_get_clkout_end;
+
+       req_size = prop->length / sizeof(u32);
+       if (req_size > ADG_HZ_SIZE) {
+               dev_err(dev, "too many clock-frequency\n");
+               return -EINVAL;
+       }
+
+       of_property_read_u32_array(np, "clock-frequency", req_rate, req_size);
+       req_Hz[ADG_HZ_48]  = 0;
+       req_Hz[ADG_HZ_441] = 0;
+       for (i = 0; i < req_size; i++) {
+               if (0 == (req_rate[i] % 44100))
+                       req_Hz[ADG_HZ_441] = req_rate[i];
+               if (0 == (req_rate[i] % 48000))
+                       req_Hz[ADG_HZ_48] = req_rate[i];
+       }
+
+       /*
+        * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
+        * have 44.1kHz or 48kHz base clocks for now.
+        *
+        * SSI itself can divide parent clock by 1/1 - 1/16
+        * see
+        *      rsnd_adg_ssi_clk_try_start()
+        *      rsnd_ssi_master_clk_start()
+        */
+
+       /*
+        * [APPROXIMATE]
+        *
+        * clk_i (internal clock) can't create accurate rate, it will be approximate rate.
+        *
+        * <Note>
+        *
+        * clk_i needs x2 of required maximum rate.
+        * see
+        *      - Minimum division of BRRA/BRRB
+        *      - rsnd_ssi_clk_query()
+        *
+        * Sample Settings for TDM 8ch, 32bit width
+        *
+        *      8(ch) x 32(bit) x 44100(Hz) x 2<Note> = 22579200
+        *      8(ch) x 32(bit) x 48000(Hz) x 2<Note> = 24576000
+        *
+        *      clock-frequency = <22579200 24576000>;
+        */
+       for_each_rsnd_clkin(clk, adg, i) {
+               u32 rate, div;
+
+               rate = clk_get_rate(clk);
+
+               if (0 == rate) /* not used */
+                       continue;
+
+               /* BRGA */
+
+               if (i == CLKI)
+                       /* see [APPROXIMATE] */
+                       rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441];
+               if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) {
+                       div = rate / req_Hz[ADG_HZ_441];
+                       brgx = rsnd_adg_calculate_brgx(div);
+                       if (BRRx_MASK(brgx) == brgx) {
+                               brga = brgx;
+                               adg->brg_rate[ADG_HZ_441] = rate / div;
+                               ckr |= brg_table[i] << 20;
+                               if (req_Hz[ADG_HZ_441])
+                                       parent_clk_name = __clk_get_name(clk);
+                               if (i == CLKI)
+                                       approximate = 1;
+                       }
+               }
+
+               /* BRGB */
+
+               if (i == CLKI)
+                       /* see [APPROXIMATE] */
+                       rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48];
+               if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) {
+                       div = rate / req_Hz[ADG_HZ_48];
+                       brgx = rsnd_adg_calculate_brgx(div);
+                       if (BRRx_MASK(brgx) == brgx) {
+                               brgb = brgx;
+                               adg->brg_rate[ADG_HZ_48] = rate / div;
+                               ckr |= brg_table[i] << 16;
+                               if (req_Hz[ADG_HZ_48])
+                                       parent_clk_name = __clk_get_name(clk);
+                               if (i == CLKI)
+                                       approximate = 1;
+                       }
+               }
+       }
+
+       if (!(adg->brg_rate[ADG_HZ_48]  && req_Hz[ADG_HZ_48]) &&
+           !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441]))
+               goto rsnd_adg_get_clkout_end;
+
+       if (approximate)
+               dev_info(dev, "It uses CLK_I as approximate rate");
+
+       clkout_name = clkout_name_gen2;
+       clkout_size = ARRAY_SIZE(clkout_name_gen2);
+       if (rsnd_is_gen4(priv))
+               clkout_size = 1; /* reuse clkout_name_gen2[] */
+
+       /*
+        * ADG supports BRRA/BRRB output only.
+        * this means all clkout0/1/2/3 will be * same rate
+        */
+
+       of_property_read_u32(np, "#clock-cells", &count);
+       /*
+        * for clkout
+        */
+       if (!count) {
+               clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
+                                             parent_clk_name, 0, req_rate[0]);
+               if (IS_ERR_OR_NULL(clk))
+                       goto err;
+
+               adg->clkout[CLKOUT] = clk;
+               adg->clkout_size = 1;
+               of_clk_add_provider(np, of_clk_src_simple_get, clk);
+       }
+       /*
+        * for clkout0/1/2/3
+        */
+       else {
+               for (i = 0; i < clkout_size; i++) {
+                       clk = clk_register_fixed_rate(dev, clkout_name[i],
+                                                     parent_clk_name, 0,
+                                                     req_rate[0]);
+                       if (IS_ERR_OR_NULL(clk))
+                               goto err;
+
+                       adg->clkout[i] = clk;
+               }
+               adg->onecell.clks       = adg->clkout;
+               adg->onecell.clk_num    = clkout_size;
+               adg->clkout_size        = clkout_size;
+               of_clk_add_provider(np, of_clk_src_onecell_get,
+                                   &adg->onecell);
+       }
+
+rsnd_adg_get_clkout_end:
+       adg->ckr = ckr;
+       adg->brga = brga;
+       adg->brgb = brgb;
+
+       return 0;
+
+err:
+       dev_err(dev, "adg clock OUT get failed\n");
+
+       rsnd_adg_unregister_clkout(priv);
+
+       return -EIO;
+}
+
+#if defined(DEBUG) || defined(CONFIG_DEBUG_FS)
+__printf(3, 4)
+static void dbg_msg(struct device *dev, struct seq_file *m,
+                                  const char *fmt, ...)
+{
+       char msg[128];
+       va_list args;
+
+       va_start(args, fmt);
+       vsnprintf(msg, sizeof(msg), fmt, args);
+       va_end(args);
+
+       if (m)
+               seq_puts(m, msg);
+       else
+               dev_dbg(dev, "%s", msg);
+}
+
+void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m)
+{
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+       int i;
+
+       for_each_rsnd_clkin(clk, adg, i)
+               dbg_msg(dev, m, "%-18s : %pa : %ld\n",
+                       __clk_get_name(clk), clk, clk_get_rate(clk));
+
+       dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
+               adg->ckr, adg->brga, adg->brgb);
+       dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->brg_rate[ADG_HZ_441]);
+       dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->brg_rate[ADG_HZ_48]);
+
+       /*
+        * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
+        * by BRGCKR::BRGCKR_31
+        */
+       for_each_rsnd_clkout(clk, adg, i)
+               dbg_msg(dev, m, "%-18s : %pa : %ld\n",
+                       __clk_get_name(clk), clk, clk_get_rate(clk));
+}
+#else
+#define rsnd_adg_clk_dbg_info(priv, m)
+#endif
+
+int rsnd_adg_probe(struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int ret;
+
+       adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
+       if (!adg)
+               return -ENOMEM;
+
+       ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
+                     NULL, 0, 0);
+       if (ret)
+               return ret;
+
+       priv->adg = adg;
+
+       ret = rsnd_adg_get_clkin(priv);
+       if (ret)
+               return ret;
+
+       ret = rsnd_adg_get_clkout(priv);
+       if (ret)
+               return ret;
+
+       rsnd_adg_clk_enable(priv);
+       rsnd_adg_clk_dbg_info(priv, NULL);
+
+       return 0;
+}
+
+void rsnd_adg_remove(struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *np = dev->of_node;
+
+       rsnd_adg_unregister_clkout(priv);
+
+       of_clk_del_provider(np);
+
+       rsnd_adg_clk_disable(priv);
+
+       /* It should be called after rsnd_adg_clk_disable() */
+       rsnd_adg_null_clk_clean(priv);
+}
diff --git a/sound/soc/renesas/rcar/cmd.c b/sound/soc/renesas/rcar/cmd.c
new file mode 100644 (file)
index 0000000..8d9a1e3
--- /dev/null
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car CMD support
+//
+// Copyright (C) 2015 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+#include "rsnd.h"
+
+struct rsnd_cmd {
+       struct rsnd_mod mod;
+};
+
+#define CMD_NAME "cmd"
+
+#define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
+#define for_each_rsnd_cmd(pos, priv, i)                                        \
+       for ((i) = 0;                                                   \
+            ((i) < rsnd_cmd_nr(priv)) &&                               \
+                    ((pos) = (struct rsnd_cmd *)(priv)->cmd + i);      \
+            i++)
+
+static int rsnd_cmd_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+       struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 data;
+       static const u32 path[] = {
+               [1] = 1 << 0,
+               [5] = 1 << 8,
+               [6] = 1 << 12,
+               [9] = 1 << 15,
+       };
+
+       if (!mix && !dvc)
+               return 0;
+
+       if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1)
+               return -ENXIO;
+
+       if (mix) {
+               struct rsnd_dai *rdai;
+               int i;
+
+               /*
+                * it is assuming that integrater is well understanding about
+                * data path. Here doesn't check impossible connection,
+                * like src2 + src5
+                */
+               data = 0;
+               for_each_rsnd_dai(rdai, priv, i) {
+                       struct rsnd_dai_stream *tio = &rdai->playback;
+                       struct rsnd_mod *src = rsnd_io_to_mod_src(tio);
+
+                       if (mix == rsnd_io_to_mod_mix(tio))
+                               data |= path[rsnd_mod_id(src)];
+
+                       tio = &rdai->capture;
+                       src = rsnd_io_to_mod_src(tio);
+                       if (mix == rsnd_io_to_mod_mix(tio))
+                               data |= path[rsnd_mod_id(src)];
+               }
+
+       } else {
+               struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+
+               static const u8 cmd_case[] = {
+                       [0] = 0x3,
+                       [1] = 0x3,
+                       [2] = 0x4,
+                       [3] = 0x1,
+                       [4] = 0x2,
+                       [5] = 0x4,
+                       [6] = 0x1,
+                       [9] = 0x2,
+               };
+
+               if (unlikely(!src))
+                       return -EIO;
+
+               data = path[rsnd_mod_id(src)] |
+                       cmd_case[rsnd_mod_id(src)] << 16;
+       }
+
+       dev_dbg(dev, "ctu/mix path = 0x%08x\n", data);
+
+       rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
+       rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1);
+       rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
+
+       rsnd_adg_set_cmd_timsel_gen2(mod, io);
+
+       return 0;
+}
+
+static int rsnd_cmd_start(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
+                         struct rsnd_priv *priv)
+{
+       rsnd_mod_write(mod, CMD_CTRL, 0x10);
+
+       return 0;
+}
+
+static int rsnd_cmd_stop(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_mod_write(mod, CMD_CTRL, 0);
+
+       return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_cmd_debug_info(struct seq_file *m,
+                               struct rsnd_dai_stream *io,
+                               struct rsnd_mod *mod)
+{
+       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
+                                 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30);
+}
+#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
+static struct rsnd_mod_ops rsnd_cmd_ops = {
+       .name           = CMD_NAME,
+       .init           = rsnd_cmd_init,
+       .start          = rsnd_cmd_start,
+       .stop           = rsnd_cmd_stop,
+       .get_status     = rsnd_mod_get_status,
+       DEBUG_INFO
+};
+
+static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
+               id = 0;
+
+       return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
+}
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
+
+       return rsnd_dai_connect(mod, io, mod->type);
+}
+
+int rsnd_cmd_probe(struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_cmd *cmd;
+       int i, nr;
+
+       /* same number as DVC */
+       nr = priv->dvc_nr;
+       if (!nr)
+               return 0;
+
+       cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       priv->cmd_nr    = nr;
+       priv->cmd       = cmd;
+
+       for_each_rsnd_cmd(cmd, priv, i) {
+               int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
+                                       &rsnd_cmd_ops, NULL,
+                                       RSND_MOD_CMD, i);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void rsnd_cmd_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_cmd *cmd;
+       int i;
+
+       for_each_rsnd_cmd(cmd, priv, i) {
+               rsnd_mod_quit(rsnd_mod_get(cmd));
+       }
+}
diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c
new file mode 100644 (file)
index 0000000..c32e88d
--- /dev/null
@@ -0,0 +1,2112 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SRU/SCU/SSIU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on fsi.c
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
+
+/*
+ * Renesas R-Car sound device structure
+ *
+ * Gen1
+ *
+ * SRU         : Sound Routing Unit
+ *  - SRC      : Sampling Rate Converter
+ *  - CMD
+ *    - CTU    : Channel Count Conversion Unit
+ *    - MIX    : Mixer
+ *    - DVC    : Digital Volume and Mute Function
+ *  - SSI      : Serial Sound Interface
+ *
+ * Gen2
+ *
+ * SCU         : Sampling Rate Converter Unit
+ *  - SRC      : Sampling Rate Converter
+ *  - CMD
+ *   - CTU     : Channel Count Conversion Unit
+ *   - MIX     : Mixer
+ *   - DVC     : Digital Volume and Mute Function
+ * SSIU                : Serial Sound Interface Unit
+ *  - SSI      : Serial Sound Interface
+ */
+
+/*
+ *     driver data Image
+ *
+ * rsnd_priv
+ *   |
+ *   | ** this depends on Gen1/Gen2
+ *   |
+ *   +- gen
+ *   |
+ *   | ** these depend on data path
+ *   | ** gen and platform data control it
+ *   |
+ *   +- rdai[0]
+ *   |   |              sru     ssiu      ssi
+ *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
+ *   |   |
+ *   |   |              sru     ssiu      ssi
+ *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
+ *   |
+ *   +- rdai[1]
+ *   |   |              sru     ssiu      ssi
+ *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
+ *   |   |
+ *   |   |              sru     ssiu      ssi
+ *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
+ *   ...
+ *   |
+ *   | ** these control ssi
+ *   |
+ *   +- ssi
+ *   |  |
+ *   |  +- ssi[0]
+ *   |  +- ssi[1]
+ *   |  +- ssi[2]
+ *   |  ...
+ *   |
+ *   | ** these control src
+ *   |
+ *   +- src
+ *      |
+ *      +- src[0]
+ *      +- src[1]
+ *      +- src[2]
+ *      ...
+ *
+ *
+ * for_each_rsnd_dai(xx, priv, xx)
+ *  rdai[0] => rdai[1] => rdai[2] => ...
+ *
+ * for_each_rsnd_mod(xx, rdai, xx)
+ *  [mod] => [mod] => [mod] => ...
+ *
+ * rsnd_dai_call(xxx, fn )
+ *  [mod]->fn() -> [mod]->fn() -> [mod]->fn()...
+ *
+ */
+
+#include <linux/pm_runtime.h>
+#include <linux/of_graph.h>
+#include "rsnd.h"
+
+#define RSND_RATES SNDRV_PCM_RATE_8000_192000
+#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\
+                  SNDRV_PCM_FMTBIT_S16_LE |\
+                  SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct of_device_id rsnd_of_match[] = {
+       { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
+       { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
+       { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 },
+       { .compatible = "renesas,rcar_sound-gen4", .data = (void *)RSND_GEN4 },
+       /* Special Handling */
+       { .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rsnd_of_match);
+
+/*
+ *     rsnd_mod functions
+ */
+void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
+{
+       if (mod->type != type) {
+               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+               struct device *dev = rsnd_priv_to_dev(priv);
+
+               dev_warn(dev, "%s is not your expected module\n",
+                        rsnd_mod_name(mod));
+       }
+}
+
+struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
+                                 struct rsnd_mod *mod)
+{
+       if (!mod || !mod->ops || !mod->ops->dma_req)
+               return NULL;
+
+       return mod->ops->dma_req(io, mod);
+}
+
+#define MOD_NAME_NUM   5
+#define MOD_NAME_SIZE 16
+char *rsnd_mod_name(struct rsnd_mod *mod)
+{
+       static char names[MOD_NAME_NUM][MOD_NAME_SIZE];
+       static int num;
+       char *name = names[num];
+
+       num++;
+       if (num >= MOD_NAME_NUM)
+               num = 0;
+
+       /*
+        * Let's use same char to avoid pointlessness memory
+        * Thus, rsnd_mod_name() should be used immediately
+        * Don't keep pointer
+        */
+       if ((mod)->ops->id_sub) {
+               snprintf(name, MOD_NAME_SIZE, "%s[%d%d]",
+                        mod->ops->name,
+                        rsnd_mod_id(mod),
+                        rsnd_mod_id_sub(mod));
+       } else {
+               snprintf(name, MOD_NAME_SIZE, "%s[%d]",
+                        mod->ops->name,
+                        rsnd_mod_id(mod));
+       }
+
+       return name;
+}
+
+u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        enum rsnd_mod_type type)
+{
+       return &mod->status;
+}
+
+int rsnd_mod_id_raw(struct rsnd_mod *mod)
+{
+       return mod->id;
+}
+
+int rsnd_mod_id(struct rsnd_mod *mod)
+{
+       if ((mod)->ops->id)
+               return (mod)->ops->id(mod);
+
+       return rsnd_mod_id_raw(mod);
+}
+
+int rsnd_mod_id_sub(struct rsnd_mod *mod)
+{
+       if ((mod)->ops->id_sub)
+               return (mod)->ops->id_sub(mod);
+
+       return 0;
+}
+
+int rsnd_mod_init(struct rsnd_priv *priv,
+                 struct rsnd_mod *mod,
+                 struct rsnd_mod_ops *ops,
+                 struct clk *clk,
+                 enum rsnd_mod_type type,
+                 int id)
+{
+       int ret = clk_prepare(clk);
+
+       if (ret)
+               return ret;
+
+       mod->id         = id;
+       mod->ops        = ops;
+       mod->type       = type;
+       mod->clk        = clk;
+       mod->priv       = priv;
+
+       return 0;
+}
+
+void rsnd_mod_quit(struct rsnd_mod *mod)
+{
+       clk_unprepare(mod->clk);
+       mod->clk = NULL;
+}
+
+void rsnd_mod_interrupt(struct rsnd_mod *mod,
+                       void (*callback)(struct rsnd_mod *mod,
+                                        struct rsnd_dai_stream *io))
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dai *rdai;
+       int i;
+
+       for_each_rsnd_dai(rdai, priv, i) {
+               struct rsnd_dai_stream *io = &rdai->playback;
+
+               if (mod == io->mod[mod->type])
+                       callback(mod, io);
+
+               io = &rdai->capture;
+               if (mod == io->mod[mod->type])
+                       callback(mod, io);
+       }
+}
+
+int rsnd_io_is_working(struct rsnd_dai_stream *io)
+{
+       /* see rsnd_dai_stream_init/quit() */
+       if (io->substream)
+               return snd_pcm_running(io->substream);
+
+       return 0;
+}
+
+int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
+                                             struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+
+       /*
+        * params will be added when refine
+        * see
+        *      __rsnd_soc_hw_rule_rate()
+        *      __rsnd_soc_hw_rule_channels()
+        */
+       if (params)
+               return params_channels(params);
+       else if (runtime)
+               return runtime->channels;
+       return 0;
+}
+
+int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
+                                              struct snd_pcm_hw_params *params)
+{
+       int chan = rsnd_runtime_channel_original_with_params(io, params);
+       struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
+
+       if (ctu_mod) {
+               u32 converted_chan = rsnd_io_converted_chan(io);
+
+               /*
+                * !! Note !!
+                *
+                * converted_chan will be used for CTU,
+                * or TDM Split mode.
+                * User shouldn't use CTU with TDM Split mode.
+                */
+               if (rsnd_runtime_is_tdm_split(io)) {
+                       struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
+
+                       dev_err(dev, "CTU and TDM Split should be used\n");
+               }
+
+               if (converted_chan)
+                       return converted_chan;
+       }
+
+       return chan;
+}
+
+int rsnd_channel_normalization(int chan)
+{
+       if (WARN_ON((chan > 8) || (chan < 0)))
+               return 0;
+
+       /* TDM Extend Mode needs 8ch */
+       if (chan == 6)
+               chan = 8;
+
+       return chan;
+}
+
+int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
+                                            struct snd_pcm_hw_params *params)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       int chan = rsnd_io_is_play(io) ?
+               rsnd_runtime_channel_after_ctu_with_params(io, params) :
+               rsnd_runtime_channel_original_with_params(io, params);
+
+       /* Use Multi SSI */
+       if (rsnd_runtime_is_multi_ssi(io))
+               chan /= rsnd_rdai_ssi_lane_get(rdai);
+
+       return rsnd_channel_normalization(chan);
+}
+
+int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       int lane = rsnd_rdai_ssi_lane_get(rdai);
+       int chan = rsnd_io_is_play(io) ?
+               rsnd_runtime_channel_after_ctu(io) :
+               rsnd_runtime_channel_original(io);
+
+       return (chan > 2) && (lane > 1);
+}
+
+int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io)
+{
+       return rsnd_runtime_channel_for_ssi(io) >= 6;
+}
+
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io)
+{
+       return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT);
+}
+
+/*
+ *     ADINR function
+ */
+u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       switch (snd_pcm_format_width(runtime->format)) {
+       case 8:
+               return 16 << 16;
+       case 16:
+               return 8 << 16;
+       case 24:
+               return 0 << 16;
+       }
+
+       dev_warn(dev, "not supported sample bits\n");
+
+       return 0;
+}
+
+/*
+ *     DALIGN function
+ */
+u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
+{
+       static const u32 dalign_values[8] = {
+               0x76543210, 0x00000032, 0x00007654, 0x00000076,
+               0xfedcba98, 0x000000ba, 0x0000fedc, 0x000000fe,
+       };
+       int id = 0;
+       struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
+       struct rsnd_mod *target;
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       u32 dalign;
+
+       /*
+        * *Hardware* L/R and *Software* L/R are inverted for 16bit data.
+        *          31..16 15...0
+        *      HW: [L ch] [R ch]
+        *      SW: [R ch] [L ch]
+        * We need to care about inversion timing to control
+        * Playback/Capture correctly.
+        * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R
+        *
+        * sL/R : software L/R
+        * hL/R : hardware L/R
+        * (*)  : conversion timing
+        *
+        * Playback
+        *           sL/R (*) hL/R     hL/R     hL/R      hL/R     hL/R
+        *      [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec
+        *
+        * Capture
+        *           hL/R     hL/R      hL/R     hL/R     hL/R (*) sL/R
+        *      codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM]
+        */
+       if (rsnd_io_is_play(io)) {
+               struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+
+               target = src ? src : ssiu;
+       } else {
+               struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io);
+
+               target = cmd ? cmd : ssiu;
+       }
+
+       if (mod == ssiu)
+               id = rsnd_mod_id_sub(mod);
+
+       dalign = dalign_values[id];
+
+       if (mod == target && snd_pcm_format_width(runtime->format) == 16) {
+               /* Target mod needs inverted DALIGN when 16bit */
+               dalign = (dalign & 0xf0f0f0f0) >> 4 |
+                        (dalign & 0x0f0f0f0f) << 4;
+       }
+
+       return dalign;
+}
+
+u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
+{
+       static const enum rsnd_mod_type playback_mods[] = {
+               RSND_MOD_SRC,
+               RSND_MOD_CMD,
+               RSND_MOD_SSIU,
+       };
+       static const enum rsnd_mod_type capture_mods[] = {
+               RSND_MOD_CMD,
+               RSND_MOD_SRC,
+               RSND_MOD_SSIU,
+       };
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_mod *tmod = NULL;
+       const enum rsnd_mod_type *mods =
+               rsnd_io_is_play(io) ?
+               playback_mods : capture_mods;
+       int i;
+
+       /*
+        * This is needed for 24bit data
+        * We need to shift 8bit
+        *
+        * Linux 24bit data is located as 0x00******
+        * HW    24bit data is located as 0x******00
+        *
+        */
+       if (snd_pcm_format_width(runtime->format) != 24)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
+               tmod = rsnd_io_to_mod(io, mods[i]);
+               if (tmod)
+                       break;
+       }
+
+       if (tmod != mod)
+               return 0;
+
+       if (rsnd_io_is_play(io))
+               return  (0 << 20) | /* shift to Left */
+                       (8 << 16);  /* 8bit */
+       else
+               return  (1 << 20) | /* shift to Right */
+                       (8 << 16);  /* 8bit */
+}
+
+/*
+ *     rsnd_dai functions
+ */
+struct rsnd_mod *rsnd_mod_next(int *iterator,
+                              struct rsnd_dai_stream *io,
+                              enum rsnd_mod_type *array,
+                              int array_size)
+{
+       int max = array ? array_size : RSND_MOD_MAX;
+
+       for (; *iterator < max; (*iterator)++) {
+               enum rsnd_mod_type type = (array) ? array[*iterator] : *iterator;
+               struct rsnd_mod *mod = rsnd_io_to_mod(io, type);
+
+               if (mod)
+                       return mod;
+       }
+
+       return NULL;
+}
+
+static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
+       {
+               /* CAPTURE */
+               RSND_MOD_AUDMAPP,
+               RSND_MOD_AUDMA,
+               RSND_MOD_DVC,
+               RSND_MOD_MIX,
+               RSND_MOD_CTU,
+               RSND_MOD_CMD,
+               RSND_MOD_SRC,
+               RSND_MOD_SSIU,
+               RSND_MOD_SSIM3,
+               RSND_MOD_SSIM2,
+               RSND_MOD_SSIM1,
+               RSND_MOD_SSIP,
+               RSND_MOD_SSI,
+       }, {
+               /* PLAYBACK */
+               RSND_MOD_AUDMAPP,
+               RSND_MOD_AUDMA,
+               RSND_MOD_SSIM3,
+               RSND_MOD_SSIM2,
+               RSND_MOD_SSIM1,
+               RSND_MOD_SSIP,
+               RSND_MOD_SSI,
+               RSND_MOD_SSIU,
+               RSND_MOD_DVC,
+               RSND_MOD_MIX,
+               RSND_MOD_CTU,
+               RSND_MOD_CMD,
+               RSND_MOD_SRC,
+       },
+};
+
+static int rsnd_status_update(struct rsnd_dai_stream *io,
+                             struct rsnd_mod *mod, enum rsnd_mod_type type,
+                             int shift, int add, int timing)
+{
+       u32 *status     = mod->ops->get_status(mod, io, type);
+       u32 mask        = 0xF << shift;
+       u8 val          = (*status >> shift) & 0xF;
+       u8 next_val     = (val + add) & 0xF;
+       int func_call   = (val == timing);
+
+       /* no status update */
+       if (add == 0 || shift == 28)
+               return 1;
+
+       if (next_val == 0xF) /* underflow case */
+               func_call = -1;
+       else
+               *status = (*status & ~mask) + (next_val << shift);
+
+       return func_call;
+}
+
+#define rsnd_dai_call(fn, io, param...)                                        \
+({                                                                     \
+       struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));     \
+       struct rsnd_mod *mod;                                           \
+       int is_play = rsnd_io_is_play(io);                              \
+       int ret = 0, i;                                                 \
+       enum rsnd_mod_type *types = rsnd_mod_sequence[is_play];         \
+       for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) {     \
+               int tmp = 0;                                            \
+               int func_call = rsnd_status_update(io, mod, types[i],   \
+                                               __rsnd_mod_shift_##fn,  \
+                                               __rsnd_mod_add_##fn,    \
+                                               __rsnd_mod_call_##fn);  \
+               if (func_call > 0 && (mod)->ops->fn)                    \
+                       tmp = (mod)->ops->fn(mod, io, param);           \
+               if (unlikely(func_call < 0) ||                          \
+                   unlikely(tmp && (tmp != -EPROBE_DEFER)))            \
+                       dev_err(dev, "%s : %s error (%d, %d)\n",        \
+                               rsnd_mod_name(mod), #fn, tmp, func_call);\
+               ret |= tmp;                                             \
+       }                                                               \
+       ret;                                                            \
+})
+
+int rsnd_dai_connect(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
+                    enum rsnd_mod_type type)
+{
+       struct rsnd_priv *priv;
+       struct device *dev;
+
+       if (!mod)
+               return -EIO;
+
+       if (io->mod[type] == mod)
+               return 0;
+
+       if (io->mod[type])
+               return -EINVAL;
+
+       priv = rsnd_mod_to_priv(mod);
+       dev = rsnd_priv_to_dev(priv);
+
+       io->mod[type] = mod;
+
+       dev_dbg(dev, "%s is connected to io (%s)\n",
+               rsnd_mod_name(mod),
+               rsnd_io_is_play(io) ? "Playback" : "Capture");
+
+       return 0;
+}
+
+static void rsnd_dai_disconnect(struct rsnd_mod *mod,
+                               struct rsnd_dai_stream *io,
+                               enum rsnd_mod_type type)
+{
+       io->mod[type] = NULL;
+}
+
+int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai,
+                           int max_channels)
+{
+       if (max_channels > 0)
+               rdai->max_channels = max_channels;
+
+       return rdai->max_channels;
+}
+
+int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
+                           int ssi_lane)
+{
+       if (ssi_lane > 0)
+               rdai->ssi_lane = ssi_lane;
+
+       return rdai->ssi_lane;
+}
+
+int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width)
+{
+       if (width > 0)
+               rdai->chan_width = width;
+
+       return rdai->chan_width;
+}
+
+struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
+{
+       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
+               return NULL;
+
+       return priv->rdai + id;
+}
+
+static struct snd_soc_dai_driver
+*rsnd_daidrv_get(struct rsnd_priv *priv, int id)
+{
+       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
+               return NULL;
+
+       return priv->daidrv + id;
+}
+
+#define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai)
+static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
+{
+       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
+
+       return rsnd_rdai_get(priv, dai->id);
+}
+
+static void rsnd_dai_stream_init(struct rsnd_dai_stream *io,
+                               struct snd_pcm_substream *substream)
+{
+       io->substream           = substream;
+}
+
+static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io)
+{
+       io->substream           = NULL;
+}
+
+static
+struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+
+       return snd_soc_rtd_to_cpu(rtd, 0);
+}
+
+static
+struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai,
+                                       struct snd_pcm_substream *substream)
+{
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return &rdai->playback;
+       else
+               return &rdai->capture;
+}
+
+static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                           struct snd_soc_dai *dai)
+{
+       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               ret = rsnd_dai_call(init, io, priv);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_dai_call(start, io, priv);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_dai_call(irq, io, priv, 1);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               ret = rsnd_dai_call(irq, io, priv, 0);
+
+               ret |= rsnd_dai_call(stop, io, priv);
+
+               ret |= rsnd_dai_call(quit, io, priv);
+
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+dai_trigger_end:
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return ret;
+}
+
+static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+
+       /* set clock master for audio interface */
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
+               rdai->clk_master = 0;
+               break;
+       case SND_SOC_DAIFMT_BP_FP:
+               rdai->clk_master = 1; /* cpu is master */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set format */
+       rdai->bit_clk_inv = 0;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               rdai->sys_delay = 0;
+               rdai->data_alignment = 0;
+               rdai->frm_clk_inv = 0;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_DSP_B:
+               rdai->sys_delay = 1;
+               rdai->data_alignment = 0;
+               rdai->frm_clk_inv = 1;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               rdai->sys_delay = 1;
+               rdai->data_alignment = 1;
+               rdai->frm_clk_inv = 1;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               rdai->sys_delay = 0;
+               rdai->data_alignment = 0;
+               rdai->frm_clk_inv = 1;
+               break;
+       }
+
+       /* set clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_IF:
+               rdai->frm_clk_inv = !rdai->frm_clk_inv;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               rdai->bit_clk_inv = !rdai->bit_clk_inv;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               rdai->bit_clk_inv = !rdai->bit_clk_inv;
+               rdai->frm_clk_inv = !rdai->frm_clk_inv;
+               break;
+       case SND_SOC_DAIFMT_NB_NF:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
+                                    u32 tx_mask, u32 rx_mask,
+                                    int slots, int slot_width)
+{
+       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       switch (slot_width) {
+       case 16:
+       case 24:
+       case 32:
+               break;
+       default:
+               /* use default */
+               /*
+                * Indicate warning if DT has "dai-tdm-slot-width"
+                * but the value was not expected.
+                */
+               if (slot_width)
+                       dev_warn(dev, "unsupported TDM slot width (%d), force to use default 32\n",
+                                slot_width);
+               slot_width = 32;
+       }
+
+       switch (slots) {
+       case 2:
+               /* TDM Split Mode */
+       case 6:
+       case 8:
+               /* TDM Extend Mode */
+               rsnd_rdai_channels_set(rdai, slots);
+               rsnd_rdai_ssi_lane_set(rdai, 1);
+               rsnd_rdai_width_set(rdai, slot_width);
+               break;
+       default:
+               dev_err(dev, "unsupported TDM slots (%d)\n", slots);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static unsigned int rsnd_soc_hw_channels_list[] = {
+       2, 6, 8,
+};
+
+static unsigned int rsnd_soc_hw_rate_list[] = {
+         8000,
+        11025,
+        16000,
+        22050,
+        32000,
+        44100,
+        48000,
+        64000,
+        88200,
+        96000,
+       176400,
+       192000,
+};
+
+static int rsnd_soc_hw_rule(struct rsnd_dai *rdai,
+                           unsigned int *list, int list_num,
+                           struct snd_interval *baseline, struct snd_interval *iv,
+                           struct rsnd_dai_stream *io, char *unit)
+{
+       struct snd_interval p;
+       unsigned int rate;
+       int i;
+
+       snd_interval_any(&p);
+       p.min = UINT_MAX;
+       p.max = 0;
+
+       for (i = 0; i < list_num; i++) {
+
+               if (!snd_interval_test(iv, list[i]))
+                       continue;
+
+               rate = rsnd_ssi_clk_query(rdai,
+                                         baseline->min, list[i], NULL);
+               if (rate > 0) {
+                       p.min = min(p.min, list[i]);
+                       p.max = max(p.max, list[i]);
+               }
+
+               rate = rsnd_ssi_clk_query(rdai,
+                                         baseline->max, list[i], NULL);
+               if (rate > 0) {
+                       p.min = min(p.min, list[i]);
+                       p.max = max(p.max, list[i]);
+               }
+       }
+
+       /* Indicate error once if it can't handle */
+       if (!rsnd_flags_has(io, RSND_HW_RULE_ERR) && (p.min > p.max)) {
+               struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+               struct device *dev = rsnd_priv_to_dev(priv);
+
+               dev_warn(dev, "It can't handle %d %s <-> %d %s\n",
+                        baseline->min, unit, baseline->max, unit);
+               rsnd_flags_set(io, RSND_HW_RULE_ERR);
+       }
+
+       return snd_interval_refine(iv, &p);
+}
+
+static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
+                                struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval ic;
+       struct rsnd_dai_stream *io = rule->private;
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+
+       /*
+        * possible sampling rate limitation is same as
+        * 2ch if it supports multi ssi
+        * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
+        */
+       ic = *ic_;
+       ic.min =
+       ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
+
+       return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list,
+                               ARRAY_SIZE(rsnd_soc_hw_rate_list),
+                               &ic, ir, io, "ch");
+}
+
+static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
+                                    struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval ic;
+       struct rsnd_dai_stream *io = rule->private;
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+
+       /*
+        * possible sampling rate limitation is same as
+        * 2ch if it supports multi ssi
+        * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
+        */
+       ic = *ic_;
+       ic.min =
+       ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
+
+       return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list,
+                               ARRAY_SIZE(rsnd_soc_hw_channels_list),
+                               ir, &ic, io, "Hz");
+}
+
+static const struct snd_pcm_hardware rsnd_pcm_hardware = {
+       .info =         SNDRV_PCM_INFO_INTERLEAVED      |
+                       SNDRV_PCM_INFO_MMAP             |
+                       SNDRV_PCM_INFO_MMAP_VALID,
+       .buffer_bytes_max       = 64 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8192,
+       .periods_min            = 1,
+       .periods_max            = 32,
+       .fifo_size              = 256,
+};
+
+static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+       struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int max_channels = rsnd_rdai_channels_get(rdai);
+       int i;
+
+       rsnd_flags_del(io, RSND_HW_RULE_ERR);
+
+       rsnd_dai_stream_init(io, substream);
+
+       /*
+        * Channel Limitation
+        * It depends on Platform design
+        */
+       constraint->list        = rsnd_soc_hw_channels_list;
+       constraint->count       = 0;
+       constraint->mask        = 0;
+
+       for (i = 0; i < ARRAY_SIZE(rsnd_soc_hw_channels_list); i++) {
+               if (rsnd_soc_hw_channels_list[i] > max_channels)
+                       break;
+               constraint->count = i + 1;
+       }
+
+       snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
+
+       snd_pcm_hw_constraint_list(runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_CHANNELS, constraint);
+
+       snd_pcm_hw_constraint_integer(runtime,
+                                     SNDRV_PCM_HW_PARAM_PERIODS);
+
+       /*
+        * Sampling Rate / Channel Limitation
+        * It depends on Clock Master Mode
+        */
+       if (rsnd_rdai_is_clk_master(rdai)) {
+               int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+
+               snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                   rsnd_soc_hw_rule_rate,
+                                   is_play ? &rdai->playback : &rdai->capture,
+                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+               snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                   rsnd_soc_hw_rule_channels,
+                                   is_play ? &rdai->playback : &rdai->capture,
+                                   SNDRV_PCM_HW_PARAM_RATE, -1);
+       }
+
+       return 0;
+}
+
+static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+
+       /*
+        * call rsnd_dai_call without spinlock
+        */
+       rsnd_dai_call(cleanup, io, priv);
+
+       rsnd_dai_stream_quit(io);
+}
+
+static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+
+       return rsnd_dai_call(prepare, io, priv);
+}
+
+static const u64 rsnd_soc_dai_formats[] = {
+       /*
+        * 1st Priority
+        *
+        * Well tested formats.
+        * Select below from Sound Card, not auto
+        *      SND_SOC_DAIFMT_CBC_CFC
+        *      SND_SOC_DAIFMT_CBP_CFP
+        */
+       SND_SOC_POSSIBLE_DAIFMT_I2S     |
+       SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+       SND_SOC_POSSIBLE_DAIFMT_LEFT_J  |
+       SND_SOC_POSSIBLE_DAIFMT_NB_NF   |
+       SND_SOC_POSSIBLE_DAIFMT_NB_IF   |
+       SND_SOC_POSSIBLE_DAIFMT_IB_NF   |
+       SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+       /*
+        * 2nd Priority
+        *
+        * Supported, but not well tested
+        */
+       SND_SOC_POSSIBLE_DAIFMT_DSP_A   |
+       SND_SOC_POSSIBLE_DAIFMT_DSP_B,
+};
+
+static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
+                                     struct rsnd_dai_stream *io,
+                                     struct device_node *dai_np)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *ssiu_np = rsnd_ssiu_of_node(priv);
+       struct device_node *np;
+       int is_play = rsnd_io_is_play(io);
+       int i;
+
+       if (!ssiu_np)
+               return;
+
+       /*
+        * This driver assumes that it is TDM Split mode
+        * if it includes ssiu node
+        */
+       for (i = 0;; i++) {
+               struct device_node *node = is_play ?
+                       of_parse_phandle(dai_np, "playback", i) :
+                       of_parse_phandle(dai_np, "capture",  i);
+
+               if (!node)
+                       break;
+
+               for_each_child_of_node(ssiu_np, np) {
+                       if (np == node) {
+                               rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
+                               dev_dbg(dev, "%s is part of TDM Split\n", io->name);
+                       }
+               }
+
+               of_node_put(node);
+       }
+
+       of_node_put(ssiu_np);
+}
+
+static void rsnd_parse_connect_simple(struct rsnd_priv *priv,
+                                     struct rsnd_dai_stream *io,
+                                     struct device_node *dai_np)
+{
+       if (!rsnd_io_to_mod_ssi(io))
+               return;
+
+       rsnd_parse_tdm_split_mode(priv, io, dai_np);
+}
+
+static void rsnd_parse_connect_graph(struct rsnd_priv *priv,
+                                    struct rsnd_dai_stream *io,
+                                    struct device_node *endpoint)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *remote_node;
+
+       if (!rsnd_io_to_mod_ssi(io))
+               return;
+
+       remote_node = of_graph_get_remote_port_parent(endpoint);
+
+       /* HDMI0 */
+       if (strstr(remote_node->full_name, "hdmi@fead0000")) {
+               rsnd_flags_set(io, RSND_STREAM_HDMI0);
+               dev_dbg(dev, "%s connected to HDMI0\n", io->name);
+       }
+
+       /* HDMI1 */
+       if (strstr(remote_node->full_name, "hdmi@feae0000")) {
+               rsnd_flags_set(io, RSND_STREAM_HDMI1);
+               dev_dbg(dev, "%s connected to HDMI1\n", io->name);
+       }
+
+       rsnd_parse_tdm_split_mode(priv, io, endpoint);
+
+       of_node_put(remote_node);
+}
+
+void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
+               struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
+               struct device_node *node,
+               struct device_node *playback,
+               struct device_node *capture)
+{
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *np;
+       int i;
+
+       if (!node)
+               return;
+
+       i = 0;
+       for_each_child_of_node(node, np) {
+               struct rsnd_mod *mod;
+
+               i = rsnd_node_fixed_index(dev, np, name, i);
+               if (i < 0) {
+                       of_node_put(np);
+                       break;
+               }
+
+               mod = mod_get(priv, i);
+
+               if (np == playback)
+                       rsnd_dai_connect(mod, &rdai->playback, mod->type);
+               if (np == capture)
+                       rsnd_dai_connect(mod, &rdai->capture, mod->type);
+               i++;
+       }
+
+       of_node_put(node);
+}
+
+int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx)
+{
+       char node_name[16];
+
+       /*
+        * rsnd is assuming each device nodes are sequential numbering,
+        * but some of them are not.
+        * This function adjusts index for it.
+        *
+        * ex)
+        * Normal case,         special case
+        *      ssi-0
+        *      ssi-1
+        *      ssi-2
+        *      ssi-3           ssi-3
+        *      ssi-4           ssi-4
+        *      ...
+        *
+        * assume Max 64 node
+        */
+       for (; idx < 64; idx++) {
+               snprintf(node_name, sizeof(node_name), "%s-%d", name, idx);
+
+               if (strncmp(node_name, of_node_full_name(node), sizeof(node_name)) == 0)
+                       return idx;
+       }
+
+       dev_err(dev, "strange node numbering (%s)",
+               of_node_full_name(node));
+       return -EINVAL;
+}
+
+int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *np;
+       int i;
+
+       i = 0;
+       for_each_child_of_node(node, np) {
+               i = rsnd_node_fixed_index(dev, np, name, i);
+               if (i < 0) {
+                       of_node_put(np);
+                       return 0;
+               }
+               i++;
+       }
+
+       return i;
+}
+
+static struct device_node*
+       rsnd_pick_endpoint_node_for_ports(struct device_node *e_ports,
+                                         struct device_node *e_port)
+{
+       if (of_node_name_eq(e_ports, "ports"))
+               return e_ports;
+
+       if (of_node_name_eq(e_ports, "port"))
+               return e_port;
+
+       return NULL;
+}
+
+static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *np = dev->of_node;
+       struct device_node *ports, *node;
+       int nr = 0;
+       int i = 0;
+
+       *is_graph = 0;
+
+       /*
+        * parse both previous dai (= rcar_sound,dai), and
+        * graph dai (= ports/port)
+        */
+
+       /*
+        * Simple-Card
+        */
+       node = of_get_child_by_name(np, RSND_NODE_DAI);
+       if (!node)
+               goto audio_graph;
+
+       of_node_put(node);
+
+       for_each_child_of_node(np, node) {
+               if (!of_node_name_eq(node, RSND_NODE_DAI))
+                       continue;
+
+               priv->component_dais[i] = of_get_child_count(node);
+               nr += priv->component_dais[i];
+               i++;
+               if (i >= RSND_MAX_COMPONENT) {
+                       dev_info(dev, "reach to max component\n");
+                       of_node_put(node);
+                       break;
+               }
+       }
+
+       return nr;
+
+audio_graph:
+       /*
+        * Audio-Graph-Card
+        */
+       for_each_child_of_node(np, ports) {
+               node = rsnd_pick_endpoint_node_for_ports(ports, np);
+               if (!node)
+                       continue;
+               priv->component_dais[i] = of_graph_get_endpoint_count(node);
+               nr += priv->component_dais[i];
+               i++;
+               if (i >= RSND_MAX_COMPONENT) {
+                       dev_info(dev, "reach to max component\n");
+                       of_node_put(ports);
+                       break;
+               }
+       }
+
+       *is_graph = 1;
+
+       return nr;
+}
+
+
+#define PREALLOC_BUFFER                (32 * 1024)
+#define PREALLOC_BUFFER_MAX    (32 * 1024)
+
+static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd,
+                                 struct rsnd_dai_stream *io,
+                                 int stream)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct snd_pcm_substream *substream;
+
+       /*
+        * use Audio-DMAC dev if we can use IPMMU
+        * see
+        *      rsnd_dmaen_attach()
+        */
+       if (io->dmac_dev)
+               dev = io->dmac_dev;
+
+       for (substream = rtd->pcm->streams[stream].substream;
+            substream;
+            substream = substream->next) {
+               snd_pcm_set_managed_buffer(substream,
+                                          SNDRV_DMA_TYPE_DEV,
+                                          dev,
+                                          PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+       }
+
+       return 0;
+}
+
+static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       int ret;
+
+       ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd);
+       if (ret)
+               return ret;
+
+       ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd);
+       if (ret)
+               return ret;
+
+       ret = rsnd_preallocate_pages(rtd, &rdai->playback,
+                                    SNDRV_PCM_STREAM_PLAYBACK);
+       if (ret)
+               return ret;
+
+       ret = rsnd_preallocate_pages(rtd, &rdai->capture,
+                                    SNDRV_PCM_STREAM_CAPTURE);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+       .pcm_new                        = rsnd_soc_dai_pcm_new,
+       .startup                        = rsnd_soc_dai_startup,
+       .shutdown                       = rsnd_soc_dai_shutdown,
+       .trigger                        = rsnd_soc_dai_trigger,
+       .set_fmt                        = rsnd_soc_dai_set_fmt,
+       .set_tdm_slot                   = rsnd_soc_set_dai_tdm_slot,
+       .prepare                        = rsnd_soc_dai_prepare,
+       .auto_selectable_formats        = rsnd_soc_dai_formats,
+       .num_auto_selectable_formats    = ARRAY_SIZE(rsnd_soc_dai_formats),
+};
+
+static void __rsnd_dai_probe(struct rsnd_priv *priv,
+                            struct device_node *dai_np,
+                            struct device_node *node_np,
+                            uint32_t node_arg,
+                            int dai_i)
+{
+       struct rsnd_dai_stream *io_playback;
+       struct rsnd_dai_stream *io_capture;
+       struct snd_soc_dai_driver *drv;
+       struct rsnd_dai *rdai;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int playback_exist = 0, capture_exist = 0;
+       int io_i;
+
+       rdai            = rsnd_rdai_get(priv, dai_i);
+       drv             = rsnd_daidrv_get(priv, dai_i);
+       io_playback     = &rdai->playback;
+       io_capture      = &rdai->capture;
+
+       snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
+
+       /* for multi Component */
+       rdai->dai_args.np               = node_np;
+       rdai->dai_args.args_count       = 1;
+       rdai->dai_args.args[0]          = node_arg;
+
+       rdai->priv      = priv;
+       drv->name       = rdai->name;
+       drv->ops        = &rsnd_soc_dai_ops;
+       drv->id         = dai_i;
+       drv->dai_args   = &rdai->dai_args;
+
+       io_playback->rdai               = rdai;
+       io_capture->rdai                = rdai;
+       rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
+       rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
+       rsnd_rdai_width_set(rdai, 32);   /* default 32bit width */
+
+       for (io_i = 0;; io_i++) {
+               struct device_node *playback = of_parse_phandle(dai_np, "playback", io_i);
+               struct device_node *capture  = of_parse_phandle(dai_np, "capture", io_i);
+
+               if (!playback && !capture)
+                       break;
+
+               if (io_i == 0) {
+                       /* check whether playback/capture property exists */
+                       if (playback)
+                               playback_exist = 1;
+                       if (capture)
+                               capture_exist = 1;
+               }
+
+               rsnd_parse_connect_ssi(rdai, playback, capture);
+               rsnd_parse_connect_ssiu(rdai, playback, capture);
+               rsnd_parse_connect_src(rdai, playback, capture);
+               rsnd_parse_connect_ctu(rdai, playback, capture);
+               rsnd_parse_connect_mix(rdai, playback, capture);
+               rsnd_parse_connect_dvc(rdai, playback, capture);
+
+               of_node_put(playback);
+               of_node_put(capture);
+       }
+
+       if (playback_exist) {
+               snprintf(io_playback->name, RSND_DAI_NAME_SIZE, "DAI%d Playback", dai_i);
+               drv->playback.rates             = RSND_RATES;
+               drv->playback.formats           = RSND_FMTS;
+               drv->playback.channels_min      = 2;
+               drv->playback.channels_max      = 8;
+               drv->playback.stream_name       = io_playback->name;
+       }
+       if (capture_exist) {
+               snprintf(io_capture->name, RSND_DAI_NAME_SIZE, "DAI%d Capture", dai_i);
+               drv->capture.rates              = RSND_RATES;
+               drv->capture.formats            = RSND_FMTS;
+               drv->capture.channels_min       = 2;
+               drv->capture.channels_max       = 8;
+               drv->capture.stream_name        = io_capture->name;
+       }
+
+       if (rsnd_ssi_is_pin_sharing(io_capture) ||
+           rsnd_ssi_is_pin_sharing(io_playback)) {
+               /* should have symmetric_rate if pin sharing */
+               drv->symmetric_rate = 1;
+       }
+
+       dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
+               rsnd_io_to_mod_ssi(io_playback) ? "play"    : " -- ",
+               rsnd_io_to_mod_ssi(io_capture) ? "capture" : "  --   ");
+}
+
+static int rsnd_dai_probe(struct rsnd_priv *priv)
+{
+       struct snd_soc_dai_driver *rdrv;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *np = dev->of_node;
+       struct rsnd_dai *rdai;
+       int nr = 0;
+       int is_graph;
+       int dai_i;
+
+       nr = rsnd_dai_of_node(priv, &is_graph);
+       if (!nr)
+               return -EINVAL;
+
+       rdrv = devm_kcalloc(dev, nr, sizeof(*rdrv), GFP_KERNEL);
+       rdai = devm_kcalloc(dev, nr, sizeof(*rdai), GFP_KERNEL);
+       if (!rdrv || !rdai)
+               return -ENOMEM;
+
+       priv->rdai_nr   = nr;
+       priv->daidrv    = rdrv;
+       priv->rdai      = rdai;
+
+       /*
+        * parse all dai
+        */
+       dai_i = 0;
+       if (is_graph) {
+               struct device_node *dai_np_port;
+               struct device_node *ports;
+               struct device_node *dai_np;
+
+               for_each_child_of_node(np, ports) {
+                       dai_np_port = rsnd_pick_endpoint_node_for_ports(ports, np);
+                       if (!dai_np_port)
+                               continue;
+
+                       for_each_endpoint_of_node(dai_np_port, dai_np) {
+                               __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i);
+                               if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) {
+                                       rdai = rsnd_rdai_get(priv, dai_i);
+
+                                       rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
+                                       rsnd_parse_connect_graph(priv, &rdai->capture,  dai_np);
+                               }
+                               dai_i++;
+                       }
+               }
+       } else {
+               struct device_node *node;
+               struct device_node *dai_np;
+
+               for_each_child_of_node(np, node) {
+                       if (!of_node_name_eq(node, RSND_NODE_DAI))
+                               continue;
+
+                       for_each_child_of_node(node, dai_np) {
+                               __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i);
+                               if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) {
+                                       rdai = rsnd_rdai_get(priv, dai_i);
+
+                                       rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
+                                       rsnd_parse_connect_simple(priv, &rdai->capture,  dai_np);
+                               }
+                               dai_i++;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/*
+ *             pcm ops
+ */
+static int rsnd_hw_update(struct snd_pcm_substream *substream,
+                         struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (hw_params)
+               ret = rsnd_dai_call(hw_params, io, substream, hw_params);
+       else
+               ret = rsnd_dai_call(hw_free, io, substream);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return ret;
+}
+
+static int rsnd_hw_params(struct snd_soc_component *component,
+                         struct snd_pcm_substream *substream,
+                         struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+       struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
+
+       /*
+        * rsnd assumes that it might be used under DPCM if user want to use
+        * channel / rate convert. Then, rsnd should be FE.
+        * And then, this function will be called *after* BE settings.
+        * this means, each BE already has fixuped hw_params.
+        * see
+        *      dpcm_fe_dai_hw_params()
+        *      dpcm_be_dai_hw_params()
+        */
+       io->converted_rate = 0;
+       io->converted_chan = 0;
+       if (fe->dai_link->dynamic) {
+               struct rsnd_priv *priv = rsnd_io_to_priv(io);
+               struct device *dev = rsnd_priv_to_dev(priv);
+               struct snd_soc_dpcm *dpcm;
+               int stream = substream->stream;
+
+               for_each_dpcm_be(fe, stream, dpcm) {
+                       struct snd_soc_pcm_runtime *be = dpcm->be;
+                       struct snd_pcm_hw_params *be_params = &be->dpcm[stream].hw_params;
+
+                       if (params_channels(hw_params) != params_channels(be_params))
+                               io->converted_chan = params_channels(be_params);
+                       if (params_rate(hw_params) != params_rate(be_params))
+                               io->converted_rate = params_rate(be_params);
+               }
+               if (io->converted_chan)
+                       dev_dbg(dev, "convert channels = %d\n", io->converted_chan);
+               if (io->converted_rate) {
+                       /*
+                        * SRC supports convert rates from params_rate(hw_params)/k_down
+                        * to params_rate(hw_params)*k_up, where k_up is always 6, and
+                        * k_down depends on number of channels and SRC unit.
+                        * So all SRC units can upsample audio up to 6 times regardless
+                        * its number of channels. And all SRC units can downsample
+                        * 2 channel audio up to 6 times too.
+                        */
+                       int k_up = 6;
+                       int k_down = 6;
+                       int channel;
+                       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+
+                       dev_dbg(dev, "convert rate     = %d\n", io->converted_rate);
+
+                       channel = io->converted_chan ? io->converted_chan :
+                                 params_channels(hw_params);
+
+                       switch (rsnd_mod_id(src_mod)) {
+                       /*
+                        * SRC0 can downsample 4, 6 and 8 channel audio up to 4 times.
+                        * SRC1, SRC3 and SRC4 can downsample 4 channel audio
+                        * up to 4 times.
+                        * SRC1, SRC3 and SRC4 can downsample 6 and 8 channel audio
+                        * no more than twice.
+                        */
+                       case 1:
+                       case 3:
+                       case 4:
+                               if (channel > 4) {
+                                       k_down = 2;
+                                       break;
+                               }
+                               fallthrough;
+                       case 0:
+                               if (channel > 2)
+                                       k_down = 4;
+                               break;
+
+                       /* Other SRC units do not support more than 2 channels */
+                       default:
+                               if (channel > 2)
+                                       return -EINVAL;
+                       }
+
+                       if (params_rate(hw_params) > io->converted_rate * k_down) {
+                               hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
+                                       io->converted_rate * k_down;
+                               hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
+                                       io->converted_rate * k_down;
+                               hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
+                       } else if (params_rate(hw_params) * k_up < io->converted_rate) {
+                               hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
+                                       DIV_ROUND_UP(io->converted_rate, k_up);
+                               hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
+                                       DIV_ROUND_UP(io->converted_rate, k_up);
+                               hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
+                       }
+
+                       /*
+                        * TBD: Max SRC input and output rates also depend on number
+                        * of channels and SRC unit:
+                        * SRC1, SRC3 and SRC4 do not support more than 128kHz
+                        * for 6 channel and 96kHz for 8 channel audio.
+                        * Perhaps this function should return EINVAL if the input or
+                        * the output rate exceeds the limitation.
+                        */
+               }
+       }
+
+       return rsnd_hw_update(substream, hw_params);
+}
+
+static int rsnd_hw_free(struct snd_soc_component *component,
+                       struct snd_pcm_substream *substream)
+{
+       return rsnd_hw_update(substream, NULL);
+}
+
+static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component,
+                                     struct snd_pcm_substream *substream)
+{
+       struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+       snd_pcm_uframes_t pointer = 0;
+
+       rsnd_dai_call(pointer, io, &pointer);
+
+       return pointer;
+}
+
+/*
+ *             snd_kcontrol
+ */
+static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
+
+       if (cfg->texts) {
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+               uinfo->count = cfg->size;
+               uinfo->value.enumerated.items = cfg->max;
+               if (uinfo->value.enumerated.item >= cfg->max)
+                       uinfo->value.enumerated.item = cfg->max - 1;
+               strscpy(uinfo->value.enumerated.name,
+                       cfg->texts[uinfo->value.enumerated.item],
+                       sizeof(uinfo->value.enumerated.name));
+       } else {
+               uinfo->count = cfg->size;
+               uinfo->value.integer.min = 0;
+               uinfo->value.integer.max = cfg->max;
+               uinfo->type = (cfg->max == 1) ?
+                       SNDRV_CTL_ELEM_TYPE_BOOLEAN :
+                       SNDRV_CTL_ELEM_TYPE_INTEGER;
+       }
+
+       return 0;
+}
+
+static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
+                         struct snd_ctl_elem_value *uc)
+{
+       struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
+       int i;
+
+       for (i = 0; i < cfg->size; i++)
+               if (cfg->texts)
+                       uc->value.enumerated.item[i] = cfg->val[i];
+               else
+                       uc->value.integer.value[i] = cfg->val[i];
+
+       return 0;
+}
+
+static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
+                         struct snd_ctl_elem_value *uc)
+{
+       struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
+       int i, change = 0;
+
+       if (!cfg->accept(cfg->io))
+               return 0;
+
+       for (i = 0; i < cfg->size; i++) {
+               if (cfg->texts) {
+                       change |= (uc->value.enumerated.item[i] != cfg->val[i]);
+                       cfg->val[i] = uc->value.enumerated.item[i];
+               } else {
+                       change |= (uc->value.integer.value[i] != cfg->val[i]);
+                       cfg->val[i] = uc->value.integer.value[i];
+               }
+       }
+
+       if (change && cfg->update)
+               cfg->update(cfg->io, cfg->mod);
+
+       return change;
+}
+
+int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io)
+{
+       return 1;
+}
+
+int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       if (!runtime) {
+               dev_warn(dev, "Can't update kctrl when idle\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)
+{
+       cfg->cfg.val = cfg->val;
+
+       return &cfg->cfg;
+}
+
+struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg)
+{
+       cfg->cfg.val = &cfg->val;
+
+       return &cfg->cfg;
+}
+
+const char * const volume_ramp_rate[] = {
+       "128 dB/1 step",         /* 00000 */
+       "64 dB/1 step",          /* 00001 */
+       "32 dB/1 step",          /* 00010 */
+       "16 dB/1 step",          /* 00011 */
+       "8 dB/1 step",           /* 00100 */
+       "4 dB/1 step",           /* 00101 */
+       "2 dB/1 step",           /* 00110 */
+       "1 dB/1 step",           /* 00111 */
+       "0.5 dB/1 step",         /* 01000 */
+       "0.25 dB/1 step",        /* 01001 */
+       "0.125 dB/1 step",       /* 01010 = VOLUME_RAMP_MAX_MIX */
+       "0.125 dB/2 steps",      /* 01011 */
+       "0.125 dB/4 steps",      /* 01100 */
+       "0.125 dB/8 steps",      /* 01101 */
+       "0.125 dB/16 steps",     /* 01110 */
+       "0.125 dB/32 steps",     /* 01111 */
+       "0.125 dB/64 steps",     /* 10000 */
+       "0.125 dB/128 steps",    /* 10001 */
+       "0.125 dB/256 steps",    /* 10010 */
+       "0.125 dB/512 steps",    /* 10011 */
+       "0.125 dB/1024 steps",   /* 10100 */
+       "0.125 dB/2048 steps",   /* 10101 */
+       "0.125 dB/4096 steps",   /* 10110 */
+       "0.125 dB/8192 steps",   /* 10111 = VOLUME_RAMP_MAX_DVC */
+};
+
+int rsnd_kctrl_new(struct rsnd_mod *mod,
+                  struct rsnd_dai_stream *io,
+                  struct snd_soc_pcm_runtime *rtd,
+                  const unsigned char *name,
+                  int (*accept)(struct rsnd_dai_stream *io),
+                  void (*update)(struct rsnd_dai_stream *io,
+                                 struct rsnd_mod *mod),
+                  struct rsnd_kctrl_cfg *cfg,
+                  const char * const *texts,
+                  int size,
+                  u32 max)
+{
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_kcontrol *kctrl;
+       struct snd_kcontrol_new knew = {
+               .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name           = name,
+               .info           = rsnd_kctrl_info,
+               .index          = rtd->num,
+               .get            = rsnd_kctrl_get,
+               .put            = rsnd_kctrl_put,
+       };
+       int ret;
+
+       /*
+        * 1) Avoid duplicate register for DVC with MIX case
+        * 2) Allow duplicate register for MIX
+        * 3) re-register if card was rebinded
+        */
+       list_for_each_entry(kctrl, &card->controls, list) {
+               struct rsnd_kctrl_cfg *c = kctrl->private_data;
+
+               if (c == cfg)
+                       return 0;
+       }
+
+       if (size > RSND_MAX_CHANNELS)
+               return -EINVAL;
+
+       kctrl = snd_ctl_new1(&knew, cfg);
+       if (!kctrl)
+               return -ENOMEM;
+
+       ret = snd_ctl_add(card, kctrl);
+       if (ret < 0)
+               return ret;
+
+       cfg->texts      = texts;
+       cfg->max        = max;
+       cfg->size       = size;
+       cfg->accept     = accept;
+       cfg->update     = update;
+       cfg->card       = card;
+       cfg->kctrl      = kctrl;
+       cfg->io         = io;
+       cfg->mod        = mod;
+
+       return 0;
+}
+
+/*
+ *             snd_soc_component
+ */
+static const struct snd_soc_component_driver rsnd_soc_component = {
+       .name                   = "rsnd",
+       .probe                  = rsnd_debugfs_probe,
+       .hw_params              = rsnd_hw_params,
+       .hw_free                = rsnd_hw_free,
+       .pointer                = rsnd_pointer,
+       .legacy_dai_naming      = 1,
+};
+
+static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
+                                      struct rsnd_dai_stream *io)
+{
+       int ret;
+
+       ret = rsnd_dai_call(probe, io, priv);
+       if (ret == -EAGAIN) {
+               struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+               struct rsnd_mod *mod;
+               int i;
+
+               /*
+                * Fallback to PIO mode
+                */
+
+               /*
+                * call "remove" for SSI/SRC/DVC
+                * SSI will be switch to PIO mode if it was DMA mode
+                * see
+                *      rsnd_dma_init()
+                *      rsnd_ssi_fallback()
+                */
+               rsnd_dai_call(remove, io, priv);
+
+               /*
+                * remove all mod from io
+                * and, re connect ssi
+                */
+               for_each_rsnd_mod(i, mod, io)
+                       rsnd_dai_disconnect(mod, io, i);
+               rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
+
+               /*
+                * fallback
+                */
+               rsnd_dai_call(fallback, io, priv);
+
+               /*
+                * retry to "probe".
+                * DAI has SSI which is PIO mode only now.
+                */
+               ret = rsnd_dai_call(probe, io, priv);
+       }
+
+       return ret;
+}
+
+/*
+ *     rsnd probe
+ */
+static int rsnd_probe(struct platform_device *pdev)
+{
+       struct rsnd_priv *priv;
+       struct device *dev = &pdev->dev;
+       struct rsnd_dai *rdai;
+       int (*probe_func[])(struct rsnd_priv *priv) = {
+               rsnd_gen_probe,
+               rsnd_dma_probe,
+               rsnd_ssi_probe,
+               rsnd_ssiu_probe,
+               rsnd_src_probe,
+               rsnd_ctu_probe,
+               rsnd_mix_probe,
+               rsnd_dvc_probe,
+               rsnd_cmd_probe,
+               rsnd_adg_probe,
+               rsnd_dai_probe,
+       };
+       int ret, i;
+       int ci;
+
+       /*
+        *      init priv data
+        */
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENODEV;
+
+       priv->pdev      = pdev;
+       priv->flags     = (unsigned long)of_device_get_match_data(dev);
+       spin_lock_init(&priv->lock);
+
+       /*
+        *      init each module
+        */
+       for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
+               ret = probe_func[i](priv);
+               if (ret)
+                       return ret;
+       }
+
+       for_each_rsnd_dai(rdai, priv, i) {
+               ret = rsnd_rdai_continuance_probe(priv, &rdai->playback);
+               if (ret)
+                       goto exit_snd_probe;
+
+               ret = rsnd_rdai_continuance_probe(priv, &rdai->capture);
+               if (ret)
+                       goto exit_snd_probe;
+       }
+
+       dev_set_drvdata(dev, priv);
+
+       /*
+        *      asoc register
+        */
+       ci = 0;
+       for (i = 0; priv->component_dais[i] > 0; i++) {
+               int nr = priv->component_dais[i];
+
+               ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
+                                                     priv->daidrv + ci, nr);
+               if (ret < 0) {
+                       dev_err(dev, "cannot snd component register\n");
+                       goto exit_snd_probe;
+               }
+
+               ci += nr;
+       }
+
+       pm_runtime_enable(dev);
+
+       dev_info(dev, "probed\n");
+       return ret;
+
+exit_snd_probe:
+       for_each_rsnd_dai(rdai, priv, i) {
+               rsnd_dai_call(remove, &rdai->playback, priv);
+               rsnd_dai_call(remove, &rdai->capture, priv);
+       }
+
+       /*
+        * adg is very special mod which can't use rsnd_dai_call(remove),
+        * and it registers ADG clock on probe.
+        * It should be unregister if probe failed.
+        * Mainly it is assuming -EPROBE_DEFER case
+        */
+       rsnd_adg_remove(priv);
+
+       return ret;
+}
+
+static void rsnd_remove(struct platform_device *pdev)
+{
+       struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
+       struct rsnd_dai *rdai;
+       void (*remove_func[])(struct rsnd_priv *priv) = {
+               rsnd_ssi_remove,
+               rsnd_ssiu_remove,
+               rsnd_src_remove,
+               rsnd_ctu_remove,
+               rsnd_mix_remove,
+               rsnd_dvc_remove,
+               rsnd_cmd_remove,
+               rsnd_adg_remove,
+       };
+       int i;
+
+       pm_runtime_disable(&pdev->dev);
+
+       for_each_rsnd_dai(rdai, priv, i) {
+               int ret;
+
+               ret = rsnd_dai_call(remove, &rdai->playback, priv);
+               if (ret)
+                       dev_warn(&pdev->dev, "Failed to remove playback dai #%d\n", i);
+
+               ret = rsnd_dai_call(remove, &rdai->capture, priv);
+               if (ret)
+                       dev_warn(&pdev->dev, "Failed to remove capture dai #%d\n", i);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(remove_func); i++)
+               remove_func[i](priv);
+}
+
+static int __maybe_unused rsnd_suspend(struct device *dev)
+{
+       struct rsnd_priv *priv = dev_get_drvdata(dev);
+
+       rsnd_adg_clk_disable(priv);
+
+       return 0;
+}
+
+static int __maybe_unused rsnd_resume(struct device *dev)
+{
+       struct rsnd_priv *priv = dev_get_drvdata(dev);
+
+       rsnd_adg_clk_enable(priv);
+
+       return 0;
+}
+
+static const struct dev_pm_ops rsnd_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume)
+};
+
+static struct platform_driver rsnd_driver = {
+       .driver = {
+               .name   = "rcar_sound",
+               .pm     = &rsnd_pm_ops,
+               .of_match_table = rsnd_of_match,
+       },
+       .probe          = rsnd_probe,
+       .remove         = rsnd_remove,
+};
+module_platform_driver(rsnd_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Renesas R-Car audio driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_ALIAS("platform:rcar-pcm-audio");
diff --git a/sound/soc/renesas/rcar/ctu.c b/sound/soc/renesas/rcar/ctu.c
new file mode 100644 (file)
index 0000000..a26ec7b
--- /dev/null
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// ctu.c
+//
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+#include "rsnd.h"
+
+#define CTU_NAME_SIZE  16
+#define CTU_NAME "ctu"
+
+/*
+ * User needs to setup CTU by amixer, and its settings are
+ * based on below registers
+ *
+ * CTUn_CPMDR : amixser set "CTU Pass"
+ * CTUn_SV0xR : amixser set "CTU SV0"
+ * CTUn_SV1xR : amixser set "CTU SV1"
+ * CTUn_SV2xR : amixser set "CTU SV2"
+ * CTUn_SV3xR : amixser set "CTU SV3"
+ *
+ * [CTU Pass]
+ * 0000: default
+ * 0001: Connect input data of channel 0
+ * 0010: Connect input data of channel 1
+ * 0011: Connect input data of channel 2
+ * 0100: Connect input data of channel 3
+ * 0101: Connect input data of channel 4
+ * 0110: Connect input data of channel 5
+ * 0111: Connect input data of channel 6
+ * 1000: Connect input data of channel 7
+ * 1001: Connect calculated data by scale values of matrix row 0
+ * 1010: Connect calculated data by scale values of matrix row 1
+ * 1011: Connect calculated data by scale values of matrix row 2
+ * 1100: Connect calculated data by scale values of matrix row 3
+ *
+ * [CTU SVx]
+ * [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07]
+ * [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17]
+ * [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27]
+ * [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37]
+ * [Output4] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
+ * [Output5] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
+ * [Output6] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
+ * [Output7] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
+ *
+ * [SVxx]
+ * Plus                                        Minus
+ * value       time            dB      value           time            dB
+ * -----------------------------------------------------------------------
+ * H'7F_FFFF   2               6       H'80_0000       2               6
+ * ...
+ * H'40_0000   1               0       H'C0_0000       1               0
+ * ...
+ * H'00_0001   2.38 x 10^-7    -132
+ * H'00_0000   0               Mute    H'FF_FFFF       2.38 x 10^-7    -132
+ *
+ *
+ * Ex) Input ch -> Output ch
+ *     1ch     ->  0ch
+ *     0ch     ->  1ch
+ *
+ *     amixer set "CTU Reset" on
+ *     amixer set "CTU Pass" 9,10
+ *     amixer set "CTU SV0" 0,4194304
+ *     amixer set "CTU SV1" 4194304,0
+ * or
+ *     amixer set "CTU Reset" on
+ *     amixer set "CTU Pass" 2,1
+ */
+
+struct rsnd_ctu {
+       struct rsnd_mod mod;
+       struct rsnd_kctrl_cfg_m pass;
+       struct rsnd_kctrl_cfg_m sv[4];
+       struct rsnd_kctrl_cfg_s reset;
+       int channels;
+       u32 flags;
+};
+
+#define KCTRL_INITIALIZED      (1 << 0)
+
+#define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
+#define for_each_rsnd_ctu(pos, priv, i)                                        \
+       for ((i) = 0;                                                   \
+            ((i) < rsnd_ctu_nr(priv)) &&                               \
+                    ((pos) = (struct rsnd_ctu *)(priv)->ctu + i);      \
+            i++)
+
+#define rsnd_mod_to_ctu(_mod)  \
+       container_of((_mod), struct rsnd_ctu, mod)
+
+#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
+
+static void rsnd_ctu_activation(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, CTU_SWRSR, 0);
+       rsnd_mod_write(mod, CTU_SWRSR, 1);
+}
+
+static void rsnd_ctu_halt(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, CTU_CTUIR, 1);
+       rsnd_mod_write(mod, CTU_SWRSR, 0);
+}
+
+static int rsnd_ctu_probe_(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
+static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
+                              struct rsnd_mod *mod)
+{
+       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
+       u32 cpmdr = 0;
+       u32 scmdr = 0;
+       int i, j;
+
+       for (i = 0; i < RSND_MAX_CHANNELS; i++) {
+               u32 val = rsnd_kctrl_valm(ctu->pass, i);
+
+               cpmdr |= val << (28 - (i * 4));
+
+               if ((val > 0x8) && (scmdr < (val - 0x8)))
+                       scmdr = val - 0x8;
+       }
+
+       rsnd_mod_write(mod, CTU_CTUIR, 1);
+
+       rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io));
+
+       rsnd_mod_write(mod, CTU_CPMDR, cpmdr);
+
+       rsnd_mod_write(mod, CTU_SCMDR, scmdr);
+
+       for (i = 0; i < 4; i++) {
+
+               if (i >= scmdr)
+                       break;
+
+               for (j = 0; j < RSND_MAX_CHANNELS; j++)
+                       rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j));
+       }
+
+       rsnd_mod_write(mod, CTU_CTUIR, 0);
+}
+
+static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
+                                struct rsnd_mod *mod)
+{
+       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
+       int i;
+
+       if (!rsnd_kctrl_vals(ctu->reset))
+               return;
+
+       for (i = 0; i < RSND_MAX_CHANNELS; i++) {
+               rsnd_kctrl_valm(ctu->pass, i) = 0;
+               rsnd_kctrl_valm(ctu->sv[0],  i) = 0;
+               rsnd_kctrl_valm(ctu->sv[1],  i) = 0;
+               rsnd_kctrl_valm(ctu->sv[2],  i) = 0;
+               rsnd_kctrl_valm(ctu->sv[3],  i) = 0;
+       }
+       rsnd_kctrl_vals(ctu->reset) = 0;
+}
+
+static int rsnd_ctu_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       int ret;
+
+       ret = rsnd_mod_power_on(mod);
+       if (ret < 0)
+               return ret;
+
+       rsnd_ctu_activation(mod);
+
+       rsnd_ctu_value_init(io, mod);
+
+       return 0;
+}
+
+static int rsnd_ctu_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_ctu_halt(mod);
+
+       rsnd_mod_power_off(mod);
+
+       return 0;
+}
+
+static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct snd_soc_pcm_runtime *rtd)
+{
+       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
+       int ret;
+
+       if (rsnd_flags_has(ctu, KCTRL_INITIALIZED))
+               return 0;
+
+       /* CTU Pass */
+       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass",
+                              rsnd_kctrl_accept_anytime,
+                              NULL,
+                              &ctu->pass, RSND_MAX_CHANNELS,
+                              0xC);
+       if (ret < 0)
+               return ret;
+
+       /* ROW0 */
+       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
+                              rsnd_kctrl_accept_anytime,
+                              NULL,
+                              &ctu->sv[0], RSND_MAX_CHANNELS,
+                              0x00FFFFFF);
+       if (ret < 0)
+               return ret;
+
+       /* ROW1 */
+       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1",
+                              rsnd_kctrl_accept_anytime,
+                              NULL,
+                              &ctu->sv[1], RSND_MAX_CHANNELS,
+                              0x00FFFFFF);
+       if (ret < 0)
+               return ret;
+
+       /* ROW2 */
+       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2",
+                              rsnd_kctrl_accept_anytime,
+                              NULL,
+                              &ctu->sv[2], RSND_MAX_CHANNELS,
+                              0x00FFFFFF);
+       if (ret < 0)
+               return ret;
+
+       /* ROW3 */
+       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3",
+                              rsnd_kctrl_accept_anytime,
+                              NULL,
+                              &ctu->sv[3], RSND_MAX_CHANNELS,
+                              0x00FFFFFF);
+       if (ret < 0)
+               return ret;
+
+       /* Reset */
+       ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_ctu_value_reset,
+                              &ctu->reset, 1);
+
+       rsnd_flags_set(ctu, KCTRL_INITIALIZED);
+
+       return ret;
+}
+
+static int rsnd_ctu_id(struct rsnd_mod *mod)
+{
+       /*
+        * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0
+        * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1
+        */
+       return mod->id / 4;
+}
+
+static int rsnd_ctu_id_sub(struct rsnd_mod *mod)
+{
+       /*
+        * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3
+        * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3
+        */
+       return mod->id % 4;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_ctu_debug_info(struct seq_file *m,
+                               struct rsnd_dai_stream *io,
+                               struct rsnd_mod *mod)
+{
+       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
+                                 0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100);
+}
+#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
+static struct rsnd_mod_ops rsnd_ctu_ops = {
+       .name           = CTU_NAME,
+       .probe          = rsnd_ctu_probe_,
+       .init           = rsnd_ctu_init,
+       .quit           = rsnd_ctu_quit,
+       .pcm_new        = rsnd_ctu_pcm_new,
+       .get_status     = rsnd_mod_get_status,
+       .id             = rsnd_ctu_id,
+       .id_sub         = rsnd_ctu_id_sub,
+       .id_cmd         = rsnd_mod_id_raw,
+       DEBUG_INFO
+};
+
+struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
+               id = 0;
+
+       return rsnd_mod_get(rsnd_ctu_get(priv, id));
+}
+
+int rsnd_ctu_probe(struct rsnd_priv *priv)
+{
+       struct device_node *node;
+       struct device_node *np;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_ctu *ctu;
+       struct clk *clk;
+       char name[CTU_NAME_SIZE];
+       int i, nr, ret;
+
+       node = rsnd_ctu_of_node(priv);
+       if (!node)
+               return 0; /* not used is not error */
+
+       nr = of_get_child_count(node);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_ctu_probe_done;
+       }
+
+       ctu = devm_kcalloc(dev, nr, sizeof(*ctu), GFP_KERNEL);
+       if (!ctu) {
+               ret = -ENOMEM;
+               goto rsnd_ctu_probe_done;
+       }
+
+       priv->ctu_nr    = nr;
+       priv->ctu       = ctu;
+
+       i = 0;
+       ret = 0;
+       for_each_child_of_node(node, np) {
+               ctu = rsnd_ctu_get(priv, i);
+
+               /*
+                * CTU00, CTU01, CTU02, CTU03 => CTU0
+                * CTU10, CTU11, CTU12, CTU13 => CTU1
+                */
+               snprintf(name, CTU_NAME_SIZE, "%s.%d",
+                        CTU_NAME, i / 4);
+
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       of_node_put(np);
+                       goto rsnd_ctu_probe_done;
+               }
+
+               ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
+                                   clk, RSND_MOD_CTU, i);
+               if (ret) {
+                       of_node_put(np);
+                       goto rsnd_ctu_probe_done;
+               }
+
+               i++;
+       }
+
+
+rsnd_ctu_probe_done:
+       of_node_put(node);
+
+       return ret;
+}
+
+void rsnd_ctu_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_ctu *ctu;
+       int i;
+
+       for_each_rsnd_ctu(ctu, priv, i) {
+               rsnd_mod_quit(rsnd_mod_get(ctu));
+       }
+}
diff --git a/sound/soc/renesas/rcar/debugfs.c b/sound/soc/renesas/rcar/debugfs.c
new file mode 100644 (file)
index 0000000..26d3b31
--- /dev/null
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// // Renesas R-Car debugfs support
+//
+// Copyright (c) 2021 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+//     > mount -t debugfs none /sys/kernel/debug
+//     > cd /sys/kernel/debug/asoc/rcar-sound/ec500000.sound/rdai{N}/
+//     > cat playback/xxx
+//     > cat capture/xxx
+//
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include "rsnd.h"
+
+static int rsnd_debugfs_show(struct seq_file *m, void *v)
+{
+       struct rsnd_dai_stream *io = m->private;
+       struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       int i;
+
+       /* adg is out of mods */
+       rsnd_adg_clk_dbg_info(priv, m);
+
+       for_each_rsnd_mod(i, mod, io) {
+               u32 *status = mod->ops->get_status(mod, io, mod->type);
+
+               seq_printf(m, "name: %s\n", rsnd_mod_name(mod));
+               seq_printf(m, "status: %08x\n", *status);
+
+               if (mod->ops->debug_info)
+                       mod->ops->debug_info(m, io, mod);
+       }
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(rsnd_debugfs);
+
+void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr,
+                          void __iomem *base, int offset, int size)
+{
+       int i, j;
+
+       for (i = 0; i < size; i += 0x10) {
+               phys_addr_t addr = _addr + offset + i;
+
+               seq_printf(m, "%pa:", &addr);
+               for (j = 0; j < 0x10; j += 0x4)
+                       seq_printf(m, " %08x", __raw_readl(base + offset + i + j));
+               seq_puts(m, "\n");
+       }
+}
+
+void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod,
+                              int reg_id, int offset, int size)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+
+       rsnd_debugfs_reg_show(m,
+                             rsnd_gen_get_phy_addr(priv, reg_id),
+                             rsnd_gen_get_base_addr(priv, reg_id),
+                             offset, size);
+}
+
+int rsnd_debugfs_probe(struct snd_soc_component *component)
+{
+       struct rsnd_priv *priv = dev_get_drvdata(component->dev);
+       struct rsnd_dai *rdai;
+       struct dentry *dir;
+       char name[64];
+       int i;
+
+       /* Gen1 is not supported */
+       if (rsnd_is_gen1(priv))
+               return 0;
+
+       for_each_rsnd_dai(rdai, priv, i) {
+               /*
+                * created debugfs will be automatically
+                * removed, nothing to do for _remove.
+                * see
+                *      soc_cleanup_component_debugfs()
+                */
+               snprintf(name, sizeof(name), "rdai%d", i);
+               dir = debugfs_create_dir(name, component->debugfs_root);
+
+               debugfs_create_file("playback", 0444, dir, &rdai->playback, &rsnd_debugfs_fops);
+               debugfs_create_file("capture",  0444, dir, &rdai->capture,  &rsnd_debugfs_fops);
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_DEBUG_FS */
diff --git a/sound/soc/renesas/rcar/dma.c b/sound/soc/renesas/rcar/dma.c
new file mode 100644 (file)
index 0000000..2342bbb
--- /dev/null
@@ -0,0 +1,885 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car Audio DMAC support
+//
+// Copyright (C) 2015 Renesas Electronics Corp.
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+#include <linux/delay.h>
+#include <linux/of_dma.h>
+#include <sound/dmaengine_pcm.h>
+#include "rsnd.h"
+
+/*
+ * Audio DMAC peri peri register
+ */
+#define PDMASAR                0x00
+#define PDMADAR                0x04
+#define PDMACHCR       0x0c
+
+/* PDMACHCR */
+#define PDMACHCR_DE            (1 << 0)
+
+
+struct rsnd_dmaen {
+       struct dma_chan         *chan;
+};
+
+struct rsnd_dmapp {
+       int                     dmapp_id;
+       u32                     chcr;
+};
+
+struct rsnd_dma {
+       struct rsnd_mod         mod;
+       struct rsnd_mod         *mod_from;
+       struct rsnd_mod         *mod_to;
+       dma_addr_t              src_addr;
+       dma_addr_t              dst_addr;
+       union {
+               struct rsnd_dmaen en;
+               struct rsnd_dmapp pp;
+       } dma;
+};
+
+struct rsnd_dma_ctrl {
+       void __iomem *ppbase;
+       phys_addr_t ppres;
+       int dmaen_num;
+       int dmapp_num;
+};
+
+#define rsnd_priv_to_dmac(p)   ((struct rsnd_dma_ctrl *)(p)->dma)
+#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod)
+#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
+#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
+
+/* for DEBUG */
+static struct rsnd_mod_ops mem_ops = {
+       .name = "mem",
+};
+
+static struct rsnd_mod mem = {
+};
+
+/*
+ *             Audio DMAC
+ */
+static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
+                                                  struct rsnd_mod *mod_from,
+                                                  struct rsnd_mod *mod_to)
+{
+       if ((!mod_from && !mod_to) ||
+           (mod_from && mod_to))
+               return NULL;
+
+       if (mod_from)
+               return rsnd_mod_dma_req(io, mod_from);
+       else
+               return rsnd_mod_dma_req(io, mod_to);
+}
+
+static int rsnd_dmaen_stop(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_STOP);
+}
+
+static int rsnd_dmaen_cleanup(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
+                             struct rsnd_priv *priv)
+{
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+
+       /*
+        * DMAEngine release uses mutex lock.
+        * Thus, it shouldn't be called under spinlock.
+        * Let's call it under prepare
+        */
+       if (dmaen->chan)
+               snd_dmaengine_pcm_close_release_chan(io->substream);
+
+       dmaen->chan = NULL;
+
+       return 0;
+}
+
+static int rsnd_dmaen_prepare(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
+                             struct rsnd_priv *priv)
+{
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       /* maybe suspended */
+       if (dmaen->chan)
+               return 0;
+
+       /*
+        * DMAEngine request uses mutex lock.
+        * Thus, it shouldn't be called under spinlock.
+        * Let's call it under prepare
+        */
+       dmaen->chan = rsnd_dmaen_request_channel(io,
+                                                dma->mod_from,
+                                                dma->mod_to);
+       if (IS_ERR_OR_NULL(dmaen->chan)) {
+               dmaen->chan = NULL;
+               dev_err(dev, "can't get dma channel\n");
+               return -EIO;
+       }
+
+       return snd_dmaengine_pcm_open(io->substream, dmaen->chan);
+}
+
+static int rsnd_dmaen_start(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct rsnd_priv *priv)
+{
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct dma_slave_config cfg = {};
+       enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       int ret;
+
+       /*
+        * in case of monaural data writing or reading through Audio-DMAC
+        * data is always in Left Justified format, so both src and dst
+        * DMA Bus width need to be set equal to physical data width.
+        */
+       if (rsnd_runtime_channel_original(io) == 1) {
+               struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+               int bits = snd_pcm_format_physical_width(runtime->format);
+
+               switch (bits) {
+               case 8:
+                       buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+                       break;
+               case 16:
+                       buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+                       break;
+               case 32:
+                       buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+                       break;
+               default:
+                       dev_err(dev, "invalid format width %d\n", bits);
+                       return -EINVAL;
+               }
+       }
+
+       cfg.direction   = snd_pcm_substream_to_dma_direction(io->substream);
+       cfg.src_addr    = dma->src_addr;
+       cfg.dst_addr    = dma->dst_addr;
+       cfg.src_addr_width = buswidth;
+       cfg.dst_addr_width = buswidth;
+
+       dev_dbg(dev, "%s %pad -> %pad\n",
+               rsnd_mod_name(mod),
+               &cfg.src_addr, &cfg.dst_addr);
+
+       ret = dmaengine_slave_config(dmaen->chan, &cfg);
+       if (ret < 0)
+               return ret;
+
+       return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_START);
+}
+
+struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
+                                         struct rsnd_mod *mod, char *x)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct dma_chan *chan = NULL;
+       struct device_node *np;
+       int i = 0;
+
+       for_each_child_of_node(of_node, np) {
+               i = rsnd_node_fixed_index(dev, np, name, i);
+               if (i < 0) {
+                       chan = NULL;
+                       of_node_put(np);
+                       break;
+               }
+
+               if (i == rsnd_mod_id_raw(mod) && (!chan))
+                       chan = of_dma_request_slave_channel(np, x);
+               i++;
+       }
+
+       /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */
+       of_node_put(of_node);
+
+       return chan;
+}
+
+static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
+                          struct rsnd_dma *dma,
+                          struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+       struct dma_chan *chan;
+
+       /* try to get DMAEngine channel */
+       chan = rsnd_dmaen_request_channel(io, mod_from, mod_to);
+       if (IS_ERR_OR_NULL(chan)) {
+               /* Let's follow when -EPROBE_DEFER case */
+               if (PTR_ERR(chan) == -EPROBE_DEFER)
+                       return PTR_ERR(chan);
+
+               /*
+                * DMA failed. try to PIO mode
+                * see
+                *      rsnd_ssi_fallback()
+                *      rsnd_rdai_continuance_probe()
+                */
+               return -EAGAIN;
+       }
+
+       /*
+        * use it for IPMMU if needed
+        * see
+        *      rsnd_preallocate_pages()
+        */
+       io->dmac_dev = chan->device->dev;
+
+       dma_release_channel(chan);
+
+       dmac->dmaen_num++;
+
+       return 0;
+}
+
+static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
+                             snd_pcm_uframes_t *pointer)
+{
+       *pointer = snd_dmaengine_pcm_pointer(io->substream);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_dmaen_ops = {
+       .name           = "audmac",
+       .prepare        = rsnd_dmaen_prepare,
+       .cleanup        = rsnd_dmaen_cleanup,
+       .start          = rsnd_dmaen_start,
+       .stop           = rsnd_dmaen_stop,
+       .pointer        = rsnd_dmaen_pointer,
+       .get_status     = rsnd_mod_get_status,
+};
+
+/*
+ *             Audio DMAC peri peri
+ */
+static const u8 gen2_id_table_ssiu[] = {
+       /* SSI00 ~ SSI07 */
+       0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c,
+       /* SSI10 ~ SSI17 */
+       0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40,
+       /* SSI20 ~ SSI27 */
+       0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44,
+       /* SSI30 ~ SSI37 */
+       0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
+       /* SSI40 ~ SSI47 */
+       0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52,
+       /* SSI5 */
+       0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* SSI6 */
+       0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* SSI7 */
+       0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* SSI8 */
+       0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* SSI90 ~ SSI97 */
+       0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56,
+};
+static const u8 gen2_id_table_scu[] = {
+       0x2d, /* SCU_SRCI0 */
+       0x2e, /* SCU_SRCI1 */
+       0x2f, /* SCU_SRCI2 */
+       0x30, /* SCU_SRCI3 */
+       0x31, /* SCU_SRCI4 */
+       0x32, /* SCU_SRCI5 */
+       0x33, /* SCU_SRCI6 */
+       0x34, /* SCU_SRCI7 */
+       0x35, /* SCU_SRCI8 */
+       0x36, /* SCU_SRCI9 */
+};
+static const u8 gen2_id_table_cmd[] = {
+       0x37, /* SCU_CMD0 */
+       0x38, /* SCU_CMD1 */
+};
+
+static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
+                            struct rsnd_mod *mod)
+{
+       struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+       struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
+       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+       const u8 *entry = NULL;
+       int id = 255;
+       int size = 0;
+
+       if ((mod == ssi) ||
+           (mod == ssiu)) {
+               int busif = rsnd_mod_id_sub(ssiu);
+
+               entry = gen2_id_table_ssiu;
+               size = ARRAY_SIZE(gen2_id_table_ssiu);
+               id = (rsnd_mod_id(mod) * 8) + busif;
+       } else if (mod == src) {
+               entry = gen2_id_table_scu;
+               size = ARRAY_SIZE(gen2_id_table_scu);
+               id = rsnd_mod_id(mod);
+       } else if (mod == dvc) {
+               entry = gen2_id_table_cmd;
+               size = ARRAY_SIZE(gen2_id_table_cmd);
+               id = rsnd_mod_id(mod);
+       }
+
+       if ((!entry) || (size <= id)) {
+               struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
+
+               dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod));
+
+               /* use non-prohibited SRS number as error */
+               return 0x00; /* SSI00 */
+       }
+
+       return entry[id];
+}
+
+static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io,
+                              struct rsnd_mod *mod_from,
+                              struct rsnd_mod *mod_to)
+{
+       return  (rsnd_dmapp_get_id(io, mod_from) << 24) +
+               (rsnd_dmapp_get_id(io, mod_to) << 16);
+}
+
+#define rsnd_dmapp_addr(dmac, dma, reg) \
+       (dmac->ppbase + 0x20 + reg + \
+        (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id))
+static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
+{
+       struct rsnd_mod *mod = rsnd_mod_get(dma);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data);
+
+       iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg));
+}
+
+static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
+{
+       struct rsnd_mod *mod = rsnd_mod_get(dma);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+
+       return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
+}
+
+static void rsnd_dmapp_bset(struct rsnd_dma *dma, u32 data, u32 mask, u32 reg)
+{
+       struct rsnd_mod *mod = rsnd_mod_get(dma);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+       void __iomem *addr = rsnd_dmapp_addr(dmac, dma, reg);
+       u32 val = ioread32(addr);
+
+       val &= ~mask;
+       val |= (data & mask);
+
+       iowrite32(val, addr);
+}
+
+static int rsnd_dmapp_stop(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       int i;
+
+       rsnd_dmapp_bset(dma, 0,  PDMACHCR_DE, PDMACHCR);
+
+       for (i = 0; i < 1024; i++) {
+               if (0 == (rsnd_dmapp_read(dma, PDMACHCR) & PDMACHCR_DE))
+                       return 0;
+               udelay(1);
+       }
+
+       return -EIO;
+}
+
+static int rsnd_dmapp_start(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct rsnd_priv *priv)
+{
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
+
+       rsnd_dmapp_write(dma, dma->src_addr,    PDMASAR);
+       rsnd_dmapp_write(dma, dma->dst_addr,    PDMADAR);
+       rsnd_dmapp_write(dma, dmapp->chcr,      PDMACHCR);
+
+       return 0;
+}
+
+static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
+                            struct rsnd_dma *dma,
+                            struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
+{
+       struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dmapp->dmapp_id = dmac->dmapp_num;
+       dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE;
+
+       dmac->dmapp_num++;
+
+       dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n",
+               dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr);
+
+       return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_dmapp_debug_info(struct seq_file *m,
+                                 struct rsnd_dai_stream *io,
+                                 struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
+       struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
+
+       rsnd_debugfs_reg_show(m, dmac->ppres, dmac->ppbase,
+                             0x20 + 0x10 * dmapp->dmapp_id, 0x10);
+}
+#define DEBUG_INFO .debug_info = rsnd_dmapp_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
+static struct rsnd_mod_ops rsnd_dmapp_ops = {
+       .name           = "audmac-pp",
+       .start          = rsnd_dmapp_start,
+       .stop           = rsnd_dmapp_stop,
+       .quit           = rsnd_dmapp_stop,
+       .get_status     = rsnd_mod_get_status,
+       DEBUG_INFO
+};
+
+/*
+ *             Common DMAC Interface
+ */
+
+/*
+ *     DMA read/write register offset
+ *
+ *     RSND_xxx_I_N    for Audio DMAC input
+ *     RSND_xxx_O_N    for Audio DMAC output
+ *     RSND_xxx_I_P    for Audio DMAC peri peri input
+ *     RSND_xxx_O_P    for Audio DMAC peri peri output
+ *
+ *     ex) R-Car H2 case
+ *           mod        / DMAC in    / DMAC out   / DMAC PP in / DMAC pp out
+ *     SSI : 0xec541000 / 0xec241008 / 0xec24100c
+ *     SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000
+ *     SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000
+ *     CMD : 0xec500000 /            / 0xec008000                0xec308000
+ */
+#define RDMA_SSI_I_N(addr, i)  (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
+#define RDMA_SSI_O_N(addr, i)  (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
+
+#define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
+#define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j)
+
+#define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
+#define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j)
+
+#define RDMA_SRC_I_N(addr, i)  (addr ##_reg - 0x00500000 + (0x400 * i))
+#define RDMA_SRC_O_N(addr, i)  (addr ##_reg - 0x004fc000 + (0x400 * i))
+
+#define RDMA_SRC_I_P(addr, i)  (addr ##_reg - 0x00200000 + (0x400 * i))
+#define RDMA_SRC_O_P(addr, i)  (addr ##_reg - 0x001fc000 + (0x400 * i))
+
+#define RDMA_CMD_O_N(addr, i)  (addr ##_reg - 0x004f8000 + (0x400 * i))
+#define RDMA_CMD_O_P(addr, i)  (addr ##_reg - 0x001f8000 + (0x400 * i))
+
+static dma_addr_t
+rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
+                  struct rsnd_mod *mod,
+                  int is_play, int is_from)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI);
+       phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU);
+       int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
+                    !!(rsnd_io_to_mod_ssiu(io) == mod);
+       int use_src = !!rsnd_io_to_mod_src(io);
+       int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
+                     !!rsnd_io_to_mod_mix(io) ||
+                     !!rsnd_io_to_mod_ctu(io);
+       int id = rsnd_mod_id(mod);
+       int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io));
+       struct dma_addr {
+               dma_addr_t out_addr;
+               dma_addr_t in_addr;
+       } dma_addrs[3][2][3] = {
+               /* SRC */
+               /* Capture */
+               {{{ 0,                          0 },
+                 { RDMA_SRC_O_N(src, id),      RDMA_SRC_I_P(src, id) },
+                 { RDMA_CMD_O_N(src, id),      RDMA_SRC_I_P(src, id) } },
+                /* Playback */
+                {{ 0,                          0, },
+                 { RDMA_SRC_O_P(src, id),      RDMA_SRC_I_N(src, id) },
+                 { RDMA_CMD_O_P(src, id),      RDMA_SRC_I_N(src, id) } }
+               },
+               /* SSI */
+               /* Capture */
+               {{{ RDMA_SSI_O_N(ssi, id),              0 },
+                 { RDMA_SSIU_O_P(ssi, id, busif),      0 },
+                 { RDMA_SSIU_O_P(ssi, id, busif),      0 } },
+                /* Playback */
+                {{ 0,                  RDMA_SSI_I_N(ssi, id) },
+                 { 0,                  RDMA_SSIU_I_P(ssi, id, busif) },
+                 { 0,                  RDMA_SSIU_I_P(ssi, id, busif) } }
+               },
+               /* SSIU */
+               /* Capture */
+               {{{ RDMA_SSIU_O_N(ssi, id, busif),      0 },
+                 { RDMA_SSIU_O_P(ssi, id, busif),      0 },
+                 { RDMA_SSIU_O_P(ssi, id, busif),      0 } },
+                /* Playback */
+                {{ 0,                  RDMA_SSIU_I_N(ssi, id, busif) },
+                 { 0,                  RDMA_SSIU_I_P(ssi, id, busif) },
+                 { 0,                  RDMA_SSIU_I_P(ssi, id, busif) } } },
+       };
+
+       /*
+        * FIXME
+        *
+        * We can't support SSI9-4/5/6/7, because its address is
+        * out of calculation rule
+        */
+       if ((id == 9) && (busif >= 4))
+               dev_err(dev, "This driver doesn't support SSI%d-%d, so far",
+                       id, busif);
+
+       /* it shouldn't happen */
+       if (use_cmd && !use_src)
+               dev_err(dev, "DVC is selected without SRC\n");
+
+       /* use SSIU or SSI ? */
+       if (is_ssi && rsnd_ssi_use_busif(io))
+               is_ssi++;
+
+       return (is_from) ?
+               dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr :
+               dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr;
+}
+
+/*
+ *     Gen4 DMA read/write register offset
+ *
+ *     ex) R-Car V4H case
+ *               mod           / SYS-DMAC in   / SYS-DMAC out
+ *     SSI_SDMC: 0xec400000    / 0xec400000    / 0xec400000
+ */
+#define RDMA_SSI_SDMC(addr, i) (addr + (0x8000 * i))
+static dma_addr_t
+rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
+                  int is_play, int is_from)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_BASE_SDMC);
+       int id = rsnd_mod_id(mod);
+       int busif = rsnd_mod_id_sub(mod);
+
+       /*
+        * SSI0 only is supported
+        */
+       if (id != 0) {
+               struct device *dev = rsnd_priv_to_dev(priv);
+
+               dev_err(dev, "This driver doesn't support non SSI0");
+               return -EINVAL;
+       }
+
+       return RDMA_SSI_SDMC(addr, busif);
+}
+
+static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
+                               struct rsnd_mod *mod,
+                               int is_play, int is_from)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+
+       if (!mod)
+               return 0;
+
+       /*
+        * gen1 uses default DMA addr
+        */
+       if (rsnd_is_gen1(priv))
+               return 0;
+       else if (rsnd_is_gen4(priv))
+               return rsnd_gen4_dma_addr(io, mod, is_play, is_from);
+       else
+               return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
+}
+
+#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
+static void rsnd_dma_of_path(struct rsnd_mod *this,
+                            struct rsnd_dai_stream *io,
+                            int is_play,
+                            struct rsnd_mod **mod_from,
+                            struct rsnd_mod **mod_to)
+{
+       struct rsnd_mod *ssi;
+       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+       struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
+       struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
+       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+       struct rsnd_mod *mod[MOD_MAX];
+       struct rsnd_mod *mod_start, *mod_end;
+       struct rsnd_priv *priv = rsnd_mod_to_priv(this);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int nr, i, idx;
+
+       /*
+        * It should use "rcar_sound,ssiu" on DT.
+        * But, we need to keep compatibility for old version.
+        *
+        * If it has "rcar_sound.ssiu", it will be used.
+        * If not, "rcar_sound.ssi" will be used.
+        * see
+        *      rsnd_ssiu_dma_req()
+        *      rsnd_ssi_dma_req()
+        */
+       if (rsnd_ssiu_of_node(priv)) {
+               struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
+
+               /* use SSIU */
+               ssi = ssiu;
+               if (this == rsnd_io_to_mod_ssi(io))
+                       this = ssiu;
+       } else {
+               /* keep compatible, use SSI */
+               ssi = rsnd_io_to_mod_ssi(io);
+       }
+
+       if (!ssi)
+               return;
+
+       nr = 0;
+       for (i = 0; i < MOD_MAX; i++) {
+               mod[i] = NULL;
+               nr += !!rsnd_io_to_mod(io, i);
+       }
+
+       /*
+        * [S] -*-> [E]
+        * [S] -*-> SRC -o-> [E]
+        * [S] -*-> SRC -> DVC -o-> [E]
+        * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E]
+        *
+        * playback     [S] = mem
+        *              [E] = SSI
+        *
+        * capture      [S] = SSI
+        *              [E] = mem
+        *
+        * -*->         Audio DMAC
+        * -o->         Audio DMAC peri peri
+        */
+       mod_start       = (is_play) ? NULL : ssi;
+       mod_end         = (is_play) ? ssi  : NULL;
+
+       idx = 0;
+       mod[idx++] = mod_start;
+       for (i = 1; i < nr; i++) {
+               if (src) {
+                       mod[idx++] = src;
+                       src = NULL;
+               } else if (ctu) {
+                       mod[idx++] = ctu;
+                       ctu = NULL;
+               } else if (mix) {
+                       mod[idx++] = mix;
+                       mix = NULL;
+               } else if (dvc) {
+                       mod[idx++] = dvc;
+                       dvc = NULL;
+               }
+       }
+       mod[idx] = mod_end;
+
+       /*
+        *              | SSI | SRC |
+        * -------------+-----+-----+
+        *  is_play     |  o  |  *  |
+        * !is_play     |  *  |  o  |
+        */
+       if ((this == ssi) == (is_play)) {
+               *mod_from       = mod[idx - 1];
+               *mod_to         = mod[idx];
+       } else {
+               *mod_from       = mod[0];
+               *mod_to         = mod[1];
+       }
+
+       dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this));
+       for (i = 0; i <= idx; i++) {
+               dev_dbg(dev, "  %s%s\n",
+                       rsnd_mod_name(mod[i] ? mod[i] : &mem),
+                       (mod[i] == *mod_from) ? " from" :
+                       (mod[i] == *mod_to)   ? " to" : "");
+       }
+}
+
+static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
+                         struct rsnd_mod **dma_mod)
+{
+       struct rsnd_mod *mod_from = NULL;
+       struct rsnd_mod *mod_to = NULL;
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_dma *dma;
+       struct rsnd_mod_ops *ops;
+       enum rsnd_mod_type type;
+       int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma,
+                     struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
+       int is_play = rsnd_io_is_play(io);
+       int ret, dma_id;
+
+       /*
+        * DMA failed. try to PIO mode
+        * see
+        *      rsnd_ssi_fallback()
+        *      rsnd_rdai_continuance_probe()
+        */
+       if (!dmac)
+               return -EAGAIN;
+
+       rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
+
+       /* for Gen2 or later */
+       if (mod_from && mod_to) {
+               ops     = &rsnd_dmapp_ops;
+               attach  = rsnd_dmapp_attach;
+               dma_id  = dmac->dmapp_num;
+               type    = RSND_MOD_AUDMAPP;
+       } else {
+               ops     = &rsnd_dmaen_ops;
+               attach  = rsnd_dmaen_attach;
+               dma_id  = dmac->dmaen_num;
+               type    = RSND_MOD_AUDMA;
+       }
+
+       /* for Gen1, overwrite */
+       if (rsnd_is_gen1(priv)) {
+               ops     = &rsnd_dmaen_ops;
+               attach  = rsnd_dmaen_attach;
+               dma_id  = dmac->dmaen_num;
+               type    = RSND_MOD_AUDMA;
+       }
+
+       dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+       if (!dma)
+               return -ENOMEM;
+
+       *dma_mod = rsnd_mod_get(dma);
+
+       ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
+                           type, dma_id);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(dev, "%s %s -> %s\n",
+               rsnd_mod_name(*dma_mod),
+               rsnd_mod_name(mod_from ? mod_from : &mem),
+               rsnd_mod_name(mod_to   ? mod_to   : &mem));
+
+       ret = attach(io, dma, mod_from, mod_to);
+       if (ret < 0)
+               return ret;
+
+       dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
+       dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
+       dma->mod_from = mod_from;
+       dma->mod_to   = mod_to;
+
+       return 0;
+}
+
+int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
+                   struct rsnd_mod **dma_mod)
+{
+       if (!(*dma_mod)) {
+               int ret = rsnd_dma_alloc(io, mod, dma_mod);
+
+               if (ret < 0)
+                       return ret;
+       }
+
+       return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type);
+}
+
+int rsnd_dma_probe(struct rsnd_priv *priv)
+{
+       struct platform_device *pdev = rsnd_priv_to_pdev(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_dma_ctrl *dmac;
+       struct resource *res;
+
+       /*
+        * for Gen1
+        */
+       if (rsnd_is_gen1(priv))
+               return 0;
+
+       /*
+        * for Gen2 or later
+        */
+       dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL);
+       if (!dmac) {
+               dev_err(dev, "dma allocate failed\n");
+               return 0; /* it will be PIO mode */
+       }
+
+       /* for Gen4 doesn't have DMA-pp */
+       if (rsnd_is_gen4(priv))
+               goto audmapp_end;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp");
+       if (!res) {
+               dev_err(dev, "lack of audmapp in DT\n");
+               return 0; /* it will be PIO mode */
+       }
+
+       dmac->dmapp_num = 0;
+       dmac->ppres  = res->start;
+       dmac->ppbase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(dmac->ppbase))
+               return PTR_ERR(dmac->ppbase);
+audmapp_end:
+       priv->dma = dmac;
+
+       /* dummy mem mod for debug */
+       return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0);
+}
diff --git a/sound/soc/renesas/rcar/dvc.c b/sound/soc/renesas/rcar/dvc.c
new file mode 100644 (file)
index 0000000..da91dd3
--- /dev/null
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car DVC support
+//
+// Copyright (C) 2014 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+/*
+ * Playback Volume
+ *     amixer set "DVC Out" 100%
+ *
+ * Capture Volume
+ *     amixer set "DVC In" 100%
+ *
+ * Playback Mute
+ *     amixer set "DVC Out Mute" on
+ *
+ * Capture Mute
+ *     amixer set "DVC In Mute" on
+ *
+ * Volume Ramp
+ *     amixer set "DVC Out Ramp Up Rate"   "0.125 dB/64 steps"
+ *     amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
+ *     amixer set "DVC Out Ramp" on
+ *     aplay xxx.wav &
+ *     amixer set "DVC Out"  80%  // Volume Down
+ *     amixer set "DVC Out" 100%  // Volume Up
+ */
+
+#include "rsnd.h"
+
+#define RSND_DVC_NAME_SIZE     16
+
+#define DVC_NAME "dvc"
+
+struct rsnd_dvc {
+       struct rsnd_mod mod;
+       struct rsnd_kctrl_cfg_m volume;
+       struct rsnd_kctrl_cfg_m mute;
+       struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
+       struct rsnd_kctrl_cfg_s rup;    /* Ramp Rate Up */
+       struct rsnd_kctrl_cfg_s rdown;  /* Ramp Rate Down */
+};
+
+#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
+#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
+
+#define rsnd_mod_to_dvc(_mod)  \
+       container_of((_mod), struct rsnd_dvc, mod)
+
+#define for_each_rsnd_dvc(pos, priv, i)                                \
+       for ((i) = 0;                                           \
+            ((i) < rsnd_dvc_nr(priv)) &&                       \
+            ((pos) = (struct rsnd_dvc *)(priv)->dvc + i);      \
+            i++)
+
+static void rsnd_dvc_activation(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, DVC_SWRSR, 0);
+       rsnd_mod_write(mod, DVC_SWRSR, 1);
+}
+
+static void rsnd_dvc_halt(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, DVC_DVUIR, 1);
+       rsnd_mod_write(mod, DVC_SWRSR, 0);
+}
+
+#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \
+                                rsnd_kctrl_vals(dvc->rdown))
+#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13))
+
+static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
+                                             struct rsnd_mod *mod)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       u32 val[RSND_MAX_CHANNELS];
+       int i;
+
+       /* Enable Ramp */
+       if (rsnd_kctrl_vals(dvc->ren))
+               for (i = 0; i < RSND_MAX_CHANNELS; i++)
+                       val[i] = rsnd_kctrl_max(dvc->volume);
+       else
+               for (i = 0; i < RSND_MAX_CHANNELS; i++)
+                       val[i] = rsnd_kctrl_valm(dvc->volume, i);
+
+       /* Enable Digital Volume */
+       for (i = 0; i < RSND_MAX_CHANNELS; i++)
+               rsnd_mod_write(mod, DVC_VOLxR(i), val[i]);
+}
+
+static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
+                                struct rsnd_mod *mod)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       u32 adinr = 0;
+       u32 dvucr = 0;
+       u32 vrctr = 0;
+       u32 vrpdr = 0;
+       u32 vrdbr = 0;
+
+       adinr = rsnd_get_adinr_bit(mod, io) |
+               rsnd_runtime_channel_after_ctu(io);
+
+       /* Enable Digital Volume, Zero Cross Mute Mode */
+       dvucr |= 0x101;
+
+       /* Enable Ramp */
+       if (rsnd_kctrl_vals(dvc->ren)) {
+               dvucr |= 0x10;
+
+               /*
+                * FIXME !!
+                * use scale-downed Digital Volume
+                * as Volume Ramp
+                * 7F FFFF -> 3FF
+                */
+               vrctr = 0xff;
+               vrpdr = rsnd_dvc_get_vrpdr(dvc);
+               vrdbr = rsnd_dvc_get_vrdbr(dvc);
+       }
+
+       /* Initialize operation */
+       rsnd_mod_write(mod, DVC_DVUIR, 1);
+
+       /* General Information */
+       rsnd_mod_write(mod, DVC_ADINR, adinr);
+       rsnd_mod_write(mod, DVC_DVUCR, dvucr);
+
+       /* Volume Ramp Parameter */
+       rsnd_mod_write(mod, DVC_VRCTR, vrctr);
+       rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+       rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+
+       /* Digital Volume Function Parameter */
+       rsnd_dvc_volume_parameter(io, mod);
+
+       /* cancel operation */
+       rsnd_mod_write(mod, DVC_DVUIR, 0);
+}
+
+static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
+                                  struct rsnd_mod *mod)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       u32 zcmcr = 0;
+       u32 vrpdr = 0;
+       u32 vrdbr = 0;
+       int i;
+
+       for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++)
+               zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i;
+
+       if (rsnd_kctrl_vals(dvc->ren)) {
+               vrpdr = rsnd_dvc_get_vrpdr(dvc);
+               vrdbr = rsnd_dvc_get_vrdbr(dvc);
+       }
+
+       /* Disable DVC Register access */
+       rsnd_mod_write(mod, DVC_DVUER, 0);
+
+       /* Zero Cross Mute Function */
+       rsnd_mod_write(mod, DVC_ZCMCR, zcmcr);
+
+       /* Volume Ramp Function */
+       rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+       rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+       /* add DVC_VRWTR here */
+
+       /* Digital Volume Function Parameter */
+       rsnd_dvc_volume_parameter(io, mod);
+
+       /* Enable DVC Register access */
+       rsnd_mod_write(mod, DVC_DVUER, 1);
+}
+
+static int rsnd_dvc_probe_(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
+static int rsnd_dvc_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       int ret;
+
+       ret = rsnd_mod_power_on(mod);
+       if (ret < 0)
+               return ret;
+
+       rsnd_dvc_activation(mod);
+
+       rsnd_dvc_volume_init(io, mod);
+
+       rsnd_dvc_volume_update(io, mod);
+
+       return 0;
+}
+
+static int rsnd_dvc_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_dvc_halt(mod);
+
+       rsnd_mod_power_off(mod);
+
+       return 0;
+}
+
+static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct snd_soc_pcm_runtime *rtd)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       int is_play = rsnd_io_is_play(io);
+       int channels = rsnd_rdai_channels_get(rdai);
+       int ret;
+
+       /* Volume */
+       ret = rsnd_kctrl_new_m(mod, io, rtd,
+                       is_play ?
+                       "DVC Out Playback Volume" : "DVC In Capture Volume",
+                       rsnd_kctrl_accept_anytime,
+                       rsnd_dvc_volume_update,
+                       &dvc->volume, channels,
+                       0x00800000 - 1);
+       if (ret < 0)
+               return ret;
+
+       /* Mute */
+       ret = rsnd_kctrl_new_m(mod, io, rtd,
+                       is_play ?
+                       "DVC Out Mute Switch" : "DVC In Mute Switch",
+                       rsnd_kctrl_accept_anytime,
+                       rsnd_dvc_volume_update,
+                       &dvc->mute, channels,
+                       1);
+       if (ret < 0)
+               return ret;
+
+       /* Ramp */
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
+                       is_play ?
+                       "DVC Out Ramp Switch" : "DVC In Ramp Switch",
+                       rsnd_kctrl_accept_anytime,
+                       rsnd_dvc_volume_update,
+                       &dvc->ren, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_kctrl_new_e(mod, io, rtd,
+                       is_play ?
+                       "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
+                       rsnd_kctrl_accept_anytime,
+                       rsnd_dvc_volume_update,
+                       &dvc->rup,
+                       volume_ramp_rate,
+                       VOLUME_RAMP_MAX_DVC);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_kctrl_new_e(mod, io, rtd,
+                       is_play ?
+                       "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
+                       rsnd_kctrl_accept_anytime,
+                       rsnd_dvc_volume_update,
+                       &dvc->rdown,
+                       volume_ramp_rate,
+                       VOLUME_RAMP_MAX_DVC);
+
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
+                                        struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+
+       return rsnd_dma_request_channel(rsnd_dvc_of_node(priv),
+                                       DVC_NAME, mod, "tx");
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_dvc_debug_info(struct seq_file *m,
+                               struct rsnd_dai_stream *io,
+                               struct rsnd_mod *mod)
+{
+       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
+                                 0xe00 + rsnd_mod_id(mod) * 0x100, 0x60);
+}
+#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
+static struct rsnd_mod_ops rsnd_dvc_ops = {
+       .name           = DVC_NAME,
+       .dma_req        = rsnd_dvc_dma_req,
+       .probe          = rsnd_dvc_probe_,
+       .init           = rsnd_dvc_init,
+       .quit           = rsnd_dvc_quit,
+       .pcm_new        = rsnd_dvc_pcm_new,
+       .get_status     = rsnd_mod_get_status,
+       DEBUG_INFO
+};
+
+struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
+               id = 0;
+
+       return rsnd_mod_get(rsnd_dvc_get(priv, id));
+}
+
+int rsnd_dvc_probe(struct rsnd_priv *priv)
+{
+       struct device_node *node;
+       struct device_node *np;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_dvc *dvc;
+       struct clk *clk;
+       char name[RSND_DVC_NAME_SIZE];
+       int i, nr, ret;
+
+       node = rsnd_dvc_of_node(priv);
+       if (!node)
+               return 0; /* not used is not error */
+
+       nr = of_get_child_count(node);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_dvc_probe_done;
+       }
+
+       dvc     = devm_kcalloc(dev, nr, sizeof(*dvc), GFP_KERNEL);
+       if (!dvc) {
+               ret = -ENOMEM;
+               goto rsnd_dvc_probe_done;
+       }
+
+       priv->dvc_nr    = nr;
+       priv->dvc       = dvc;
+
+       i = 0;
+       ret = 0;
+       for_each_child_of_node(node, np) {
+               dvc = rsnd_dvc_get(priv, i);
+
+               snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
+                        DVC_NAME, i);
+
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       of_node_put(np);
+                       goto rsnd_dvc_probe_done;
+               }
+
+               ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
+                                   clk, RSND_MOD_DVC, i);
+               if (ret) {
+                       of_node_put(np);
+                       goto rsnd_dvc_probe_done;
+               }
+
+               i++;
+       }
+
+rsnd_dvc_probe_done:
+       of_node_put(node);
+
+       return ret;
+}
+
+void rsnd_dvc_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_dvc *dvc;
+       int i;
+
+       for_each_rsnd_dvc(dvc, priv, i) {
+               rsnd_mod_quit(rsnd_mod_get(dvc));
+       }
+}
diff --git a/sound/soc/renesas/rcar/gen.c b/sound/soc/renesas/rcar/gen.c
new file mode 100644 (file)
index 0000000..d1f20cd
--- /dev/null
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car Gen1 SRU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+/*
+ * #define DEBUG
+ *
+ * you can also add below in
+ * ${LINUX}/drivers/base/regmap/regmap.c
+ * for regmap debug
+ *
+ * #define LOG_DEVICE "xxxx.rcar_sound"
+ */
+
+#include "rsnd.h"
+
+struct rsnd_gen {
+       struct rsnd_gen_ops *ops;
+
+       /* RSND_BASE_MAX base */
+       void __iomem *base[RSND_BASE_MAX];
+       phys_addr_t res[RSND_BASE_MAX];
+       struct regmap *regmap[RSND_BASE_MAX];
+
+       /* RSND_REG_MAX base */
+       struct regmap_field *regs[REG_MAX];
+       const char *reg_name[REG_MAX];
+};
+
+#define rsnd_priv_to_gen(p)    ((struct rsnd_gen *)(p)->gen)
+#define rsnd_reg_name(gen, id) ((gen)->reg_name[id])
+
+struct rsnd_regmap_field_conf {
+       int idx;
+       unsigned int reg_offset;
+       unsigned int id_offset;
+       const char *reg_name;
+};
+
+#define RSND_REG_SET(id, offset, _id_offset, n)        \
+{                                              \
+       .idx = id,                              \
+       .reg_offset = offset,                   \
+       .id_offset = _id_offset,                \
+       .reg_name = n,                          \
+}
+/* single address mapping */
+#define RSND_GEN_S_REG(id, offset)     \
+       RSND_REG_SET(id, offset, 0, #id)
+
+/* multi address mapping */
+#define RSND_GEN_M_REG(id, offset, _id_offset) \
+       RSND_REG_SET(id, offset, _id_offset, #id)
+
+/*
+ *             basic function
+ */
+static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
+                                 struct rsnd_gen *gen, enum rsnd_reg reg)
+{
+       if (!gen->regs[reg]) {
+               struct device *dev = rsnd_priv_to_dev(priv);
+
+               dev_err(dev, "unsupported register access %x\n", reg);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int rsnd_mod_id_cmd(struct rsnd_mod *mod)
+{
+       if (mod->ops->id_cmd)
+               return mod->ops->id_cmd(mod);
+
+       return rsnd_mod_id(mod);
+}
+
+u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+       u32 val;
+
+       if (!rsnd_is_accessible_reg(priv, gen, reg))
+               return 0;
+
+       regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val);
+
+       dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n",
+               rsnd_mod_name(mod),
+               rsnd_reg_name(gen, reg), reg, val);
+
+       return val;
+}
+
+void rsnd_mod_write(struct rsnd_mod *mod,
+                   enum rsnd_reg reg, u32 data)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+       if (!rsnd_is_accessible_reg(priv, gen, reg))
+               return;
+
+       regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data);
+
+       dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n",
+               rsnd_mod_name(mod),
+               rsnd_reg_name(gen, reg), reg, data);
+}
+
+void rsnd_mod_bset(struct rsnd_mod *mod,
+                  enum rsnd_reg reg, u32 mask, u32 data)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+       if (!rsnd_is_accessible_reg(priv, gen, reg))
+               return;
+
+       regmap_fields_force_update_bits(gen->regs[reg],
+                                       rsnd_mod_id_cmd(mod), mask, data);
+
+       dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n",
+               rsnd_mod_name(mod),
+               rsnd_reg_name(gen, reg), reg, data, mask);
+
+}
+
+phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
+{
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+       return  gen->res[reg_id];
+}
+
+#ifdef CONFIG_DEBUG_FS
+void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id)
+{
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+       return  gen->base[reg_id];
+}
+#endif
+
+#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf)                \
+       _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf))
+static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
+                                int id_size,
+                                int reg_id,
+                                const char *name,
+                                const struct rsnd_regmap_field_conf *conf,
+                                int conf_size)
+{
+       struct platform_device *pdev = rsnd_priv_to_pdev(priv);
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct resource *res;
+       struct regmap_config regc;
+       struct regmap_field *regs;
+       struct regmap *regmap;
+       struct reg_field regf;
+       void __iomem *base;
+       int i;
+
+       memset(&regc, 0, sizeof(regc));
+       regc.reg_bits = 32;
+       regc.val_bits = 32;
+       regc.reg_stride = 4;
+       regc.name = name;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       if (!res)
+               return -ENODEV;
+
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       regmap = devm_regmap_init_mmio(dev, base, &regc);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       /* RSND_BASE_MAX base */
+       gen->base[reg_id] = base;
+       gen->regmap[reg_id] = regmap;
+       gen->res[reg_id] = res->start;
+
+       for (i = 0; i < conf_size; i++) {
+
+               regf.reg        = conf[i].reg_offset;
+               regf.id_offset  = conf[i].id_offset;
+               regf.lsb        = 0;
+               regf.msb        = 31;
+               regf.id_size    = id_size;
+
+               regs = devm_regmap_field_alloc(dev, regmap, regf);
+               if (IS_ERR(regs))
+                       return PTR_ERR(regs);
+
+               /* RSND_REG_MAX base */
+               gen->regs[conf[i].idx] = regs;
+               gen->reg_name[conf[i].idx] = conf[i].reg_name;
+       }
+
+       return 0;
+}
+
+/*
+ * (A) : Gen4 is 0xa0c, but it is not used.
+ *     see
+ *             rsnd_ssiu_init()
+ */
+static const struct rsnd_regmap_field_conf conf_common_ssiu[] = {
+       RSND_GEN_S_REG(SSI_MODE0,               0x800),
+       RSND_GEN_S_REG(SSI_MODE1,               0x804),
+       RSND_GEN_S_REG(SSI_MODE2,               0x808), // (A)
+       RSND_GEN_S_REG(SSI_CONTROL,             0x810),
+       RSND_GEN_S_REG(SSI_SYS_STATUS0,         0x840),
+       RSND_GEN_S_REG(SSI_SYS_STATUS1,         0x844),
+       RSND_GEN_S_REG(SSI_SYS_STATUS2,         0x848),
+       RSND_GEN_S_REG(SSI_SYS_STATUS3,         0x84c),
+       RSND_GEN_S_REG(SSI_SYS_STATUS4,         0x880),
+       RSND_GEN_S_REG(SSI_SYS_STATUS5,         0x884),
+       RSND_GEN_S_REG(SSI_SYS_STATUS6,         0x888),
+       RSND_GEN_S_REG(SSI_SYS_STATUS7,         0x88c),
+       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0,     0x850),
+       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1,     0x854),
+       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2,     0x858),
+       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3,     0x85c),
+       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4,     0x890),
+       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5,     0x894),
+       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6,     0x898),
+       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7,     0x89c),
+       RSND_GEN_S_REG(HDMI0_SEL,               0x9e0),
+       RSND_GEN_S_REG(HDMI1_SEL,               0x9e4),
+       RSND_GEN_M_REG(SSI_BUSIF0_MODE,         0x0,    0x80),
+       RSND_GEN_M_REG(SSI_BUSIF0_ADINR,        0x4,    0x80),
+       RSND_GEN_M_REG(SSI_BUSIF0_DALIGN,       0x8,    0x80),
+       RSND_GEN_M_REG(SSI_BUSIF1_MODE,         0x20,   0x80),
+       RSND_GEN_M_REG(SSI_BUSIF1_ADINR,        0x24,   0x80),
+       RSND_GEN_M_REG(SSI_BUSIF1_DALIGN,       0x28,   0x80),
+       RSND_GEN_M_REG(SSI_BUSIF2_MODE,         0x40,   0x80),
+       RSND_GEN_M_REG(SSI_BUSIF2_ADINR,        0x44,   0x80),
+       RSND_GEN_M_REG(SSI_BUSIF2_DALIGN,       0x48,   0x80),
+       RSND_GEN_M_REG(SSI_BUSIF3_MODE,         0x60,   0x80),
+       RSND_GEN_M_REG(SSI_BUSIF3_ADINR,        0x64,   0x80),
+       RSND_GEN_M_REG(SSI_BUSIF3_DALIGN,       0x68,   0x80),
+       RSND_GEN_M_REG(SSI_BUSIF4_MODE,         0x500,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF4_ADINR,        0x504,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF4_DALIGN,       0x508,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF5_MODE,         0x520,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF5_ADINR,        0x524,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF5_DALIGN,       0x528,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF6_MODE,         0x540,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF6_ADINR,        0x544,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF6_DALIGN,       0x548,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF7_MODE,         0x560,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF7_ADINR,        0x564,  0x80),
+       RSND_GEN_M_REG(SSI_BUSIF7_DALIGN,       0x568,  0x80),
+       RSND_GEN_M_REG(SSI_MODE,                0xc,    0x80),
+       RSND_GEN_M_REG(SSI_CTRL,                0x10,   0x80),
+       RSND_GEN_M_REG(SSI_INT_ENABLE,          0x18,   0x80),
+       RSND_GEN_S_REG(SSI9_BUSIF0_MODE,        0x48c),
+       RSND_GEN_S_REG(SSI9_BUSIF0_ADINR,       0x484),
+       RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN,      0x488),
+       RSND_GEN_S_REG(SSI9_BUSIF1_MODE,        0x4a0),
+       RSND_GEN_S_REG(SSI9_BUSIF1_ADINR,       0x4a4),
+       RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN,      0x4a8),
+       RSND_GEN_S_REG(SSI9_BUSIF2_MODE,        0x4c0),
+       RSND_GEN_S_REG(SSI9_BUSIF2_ADINR,       0x4c4),
+       RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN,      0x4c8),
+       RSND_GEN_S_REG(SSI9_BUSIF3_MODE,        0x4e0),
+       RSND_GEN_S_REG(SSI9_BUSIF3_ADINR,       0x4e4),
+       RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN,      0x4e8),
+       RSND_GEN_S_REG(SSI9_BUSIF4_MODE,        0xd80),
+       RSND_GEN_S_REG(SSI9_BUSIF4_ADINR,       0xd84),
+       RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN,      0xd88),
+       RSND_GEN_S_REG(SSI9_BUSIF5_MODE,        0xda0),
+       RSND_GEN_S_REG(SSI9_BUSIF5_ADINR,       0xda4),
+       RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN,      0xda8),
+       RSND_GEN_S_REG(SSI9_BUSIF6_MODE,        0xdc0),
+       RSND_GEN_S_REG(SSI9_BUSIF6_ADINR,       0xdc4),
+       RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN,      0xdc8),
+       RSND_GEN_S_REG(SSI9_BUSIF7_MODE,        0xde0),
+       RSND_GEN_S_REG(SSI9_BUSIF7_ADINR,       0xde4),
+       RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN,      0xde8),
+};
+
+static const struct rsnd_regmap_field_conf conf_common_scu[] = {
+       RSND_GEN_M_REG(SRC_I_BUSIF_MODE,        0x0,    0x20),
+       RSND_GEN_M_REG(SRC_O_BUSIF_MODE,        0x4,    0x20),
+       RSND_GEN_M_REG(SRC_BUSIF_DALIGN,        0x8,    0x20),
+       RSND_GEN_M_REG(SRC_ROUTE_MODE0,         0xc,    0x20),
+       RSND_GEN_M_REG(SRC_CTRL,                0x10,   0x20),
+       RSND_GEN_M_REG(SRC_INT_ENABLE0,         0x18,   0x20),
+       RSND_GEN_M_REG(CMD_BUSIF_MODE,          0x184,  0x20),
+       RSND_GEN_M_REG(CMD_BUSIF_DALIGN,        0x188,  0x20),
+       RSND_GEN_M_REG(CMD_ROUTE_SLCT,          0x18c,  0x20),
+       RSND_GEN_M_REG(CMD_CTRL,                0x190,  0x20),
+       RSND_GEN_S_REG(SCU_SYS_STATUS0,         0x1c8),
+       RSND_GEN_S_REG(SCU_SYS_INT_EN0,         0x1cc),
+       RSND_GEN_S_REG(SCU_SYS_STATUS1,         0x1d0),
+       RSND_GEN_S_REG(SCU_SYS_INT_EN1,         0x1d4),
+       RSND_GEN_M_REG(SRC_SWRSR,               0x200,  0x40),
+       RSND_GEN_M_REG(SRC_SRCIR,               0x204,  0x40),
+       RSND_GEN_M_REG(SRC_ADINR,               0x214,  0x40),
+       RSND_GEN_M_REG(SRC_IFSCR,               0x21c,  0x40),
+       RSND_GEN_M_REG(SRC_IFSVR,               0x220,  0x40),
+       RSND_GEN_M_REG(SRC_SRCCR,               0x224,  0x40),
+       RSND_GEN_M_REG(SRC_BSDSR,               0x22c,  0x40),
+       RSND_GEN_M_REG(SRC_BSISR,               0x238,  0x40),
+       RSND_GEN_M_REG(CTU_SWRSR,               0x500,  0x100),
+       RSND_GEN_M_REG(CTU_CTUIR,               0x504,  0x100),
+       RSND_GEN_M_REG(CTU_ADINR,               0x508,  0x100),
+       RSND_GEN_M_REG(CTU_CPMDR,               0x510,  0x100),
+       RSND_GEN_M_REG(CTU_SCMDR,               0x514,  0x100),
+       RSND_GEN_M_REG(CTU_SV00R,               0x518,  0x100),
+       RSND_GEN_M_REG(CTU_SV01R,               0x51c,  0x100),
+       RSND_GEN_M_REG(CTU_SV02R,               0x520,  0x100),
+       RSND_GEN_M_REG(CTU_SV03R,               0x524,  0x100),
+       RSND_GEN_M_REG(CTU_SV04R,               0x528,  0x100),
+       RSND_GEN_M_REG(CTU_SV05R,               0x52c,  0x100),
+       RSND_GEN_M_REG(CTU_SV06R,               0x530,  0x100),
+       RSND_GEN_M_REG(CTU_SV07R,               0x534,  0x100),
+       RSND_GEN_M_REG(CTU_SV10R,               0x538,  0x100),
+       RSND_GEN_M_REG(CTU_SV11R,               0x53c,  0x100),
+       RSND_GEN_M_REG(CTU_SV12R,               0x540,  0x100),
+       RSND_GEN_M_REG(CTU_SV13R,               0x544,  0x100),
+       RSND_GEN_M_REG(CTU_SV14R,               0x548,  0x100),
+       RSND_GEN_M_REG(CTU_SV15R,               0x54c,  0x100),
+       RSND_GEN_M_REG(CTU_SV16R,               0x550,  0x100),
+       RSND_GEN_M_REG(CTU_SV17R,               0x554,  0x100),
+       RSND_GEN_M_REG(CTU_SV20R,               0x558,  0x100),
+       RSND_GEN_M_REG(CTU_SV21R,               0x55c,  0x100),
+       RSND_GEN_M_REG(CTU_SV22R,               0x560,  0x100),
+       RSND_GEN_M_REG(CTU_SV23R,               0x564,  0x100),
+       RSND_GEN_M_REG(CTU_SV24R,               0x568,  0x100),
+       RSND_GEN_M_REG(CTU_SV25R,               0x56c,  0x100),
+       RSND_GEN_M_REG(CTU_SV26R,               0x570,  0x100),
+       RSND_GEN_M_REG(CTU_SV27R,               0x574,  0x100),
+       RSND_GEN_M_REG(CTU_SV30R,               0x578,  0x100),
+       RSND_GEN_M_REG(CTU_SV31R,               0x57c,  0x100),
+       RSND_GEN_M_REG(CTU_SV32R,               0x580,  0x100),
+       RSND_GEN_M_REG(CTU_SV33R,               0x584,  0x100),
+       RSND_GEN_M_REG(CTU_SV34R,               0x588,  0x100),
+       RSND_GEN_M_REG(CTU_SV35R,               0x58c,  0x100),
+       RSND_GEN_M_REG(CTU_SV36R,               0x590,  0x100),
+       RSND_GEN_M_REG(CTU_SV37R,               0x594,  0x100),
+       RSND_GEN_M_REG(MIX_SWRSR,               0xd00,  0x40),
+       RSND_GEN_M_REG(MIX_MIXIR,               0xd04,  0x40),
+       RSND_GEN_M_REG(MIX_ADINR,               0xd08,  0x40),
+       RSND_GEN_M_REG(MIX_MIXMR,               0xd10,  0x40),
+       RSND_GEN_M_REG(MIX_MVPDR,               0xd14,  0x40),
+       RSND_GEN_M_REG(MIX_MDBAR,               0xd18,  0x40),
+       RSND_GEN_M_REG(MIX_MDBBR,               0xd1c,  0x40),
+       RSND_GEN_M_REG(MIX_MDBCR,               0xd20,  0x40),
+       RSND_GEN_M_REG(MIX_MDBDR,               0xd24,  0x40),
+       RSND_GEN_M_REG(MIX_MDBER,               0xd28,  0x40),
+       RSND_GEN_M_REG(DVC_SWRSR,               0xe00,  0x100),
+       RSND_GEN_M_REG(DVC_DVUIR,               0xe04,  0x100),
+       RSND_GEN_M_REG(DVC_ADINR,               0xe08,  0x100),
+       RSND_GEN_M_REG(DVC_DVUCR,               0xe10,  0x100),
+       RSND_GEN_M_REG(DVC_ZCMCR,               0xe14,  0x100),
+       RSND_GEN_M_REG(DVC_VRCTR,               0xe18,  0x100),
+       RSND_GEN_M_REG(DVC_VRPDR,               0xe1c,  0x100),
+       RSND_GEN_M_REG(DVC_VRDBR,               0xe20,  0x100),
+       RSND_GEN_M_REG(DVC_VOL0R,               0xe28,  0x100),
+       RSND_GEN_M_REG(DVC_VOL1R,               0xe2c,  0x100),
+       RSND_GEN_M_REG(DVC_VOL2R,               0xe30,  0x100),
+       RSND_GEN_M_REG(DVC_VOL3R,               0xe34,  0x100),
+       RSND_GEN_M_REG(DVC_VOL4R,               0xe38,  0x100),
+       RSND_GEN_M_REG(DVC_VOL5R,               0xe3c,  0x100),
+       RSND_GEN_M_REG(DVC_VOL6R,               0xe40,  0x100),
+       RSND_GEN_M_REG(DVC_VOL7R,               0xe44,  0x100),
+       RSND_GEN_M_REG(DVC_DVUER,               0xe48,  0x100),
+};
+
+static const struct rsnd_regmap_field_conf conf_common_adg[] = {
+       RSND_GEN_S_REG(BRRA,                    0x00),
+       RSND_GEN_S_REG(BRRB,                    0x04),
+       RSND_GEN_S_REG(BRGCKR,                  0x08),
+       RSND_GEN_S_REG(AUDIO_CLK_SEL0,          0x0c),
+       RSND_GEN_S_REG(AUDIO_CLK_SEL1,          0x10),
+       RSND_GEN_S_REG(AUDIO_CLK_SEL2,          0x14),
+       RSND_GEN_S_REG(DIV_EN,                  0x30),
+       RSND_GEN_S_REG(SRCIN_TIMSEL0,           0x34),
+       RSND_GEN_S_REG(SRCIN_TIMSEL1,           0x38),
+       RSND_GEN_S_REG(SRCIN_TIMSEL2,           0x3c),
+       RSND_GEN_S_REG(SRCIN_TIMSEL3,           0x40),
+       RSND_GEN_S_REG(SRCIN_TIMSEL4,           0x44),
+       RSND_GEN_S_REG(SRCOUT_TIMSEL0,          0x48),
+       RSND_GEN_S_REG(SRCOUT_TIMSEL1,          0x4c),
+       RSND_GEN_S_REG(SRCOUT_TIMSEL2,          0x50),
+       RSND_GEN_S_REG(SRCOUT_TIMSEL3,          0x54),
+       RSND_GEN_S_REG(SRCOUT_TIMSEL4,          0x58),
+       RSND_GEN_S_REG(CMDOUT_TIMSEL,           0x5c),
+};
+
+static const struct rsnd_regmap_field_conf conf_common_ssi[] = {
+       RSND_GEN_M_REG(SSICR,                   0x00,   0x40),
+       RSND_GEN_M_REG(SSISR,                   0x04,   0x40),
+       RSND_GEN_M_REG(SSITDR,                  0x08,   0x40),
+       RSND_GEN_M_REG(SSIRDR,                  0x0c,   0x40),
+       RSND_GEN_M_REG(SSIWSR,                  0x20,   0x40),
+};
+
+/*
+ *             Gen4
+ */
+static int rsnd_gen4_probe(struct rsnd_priv *priv)
+{
+       struct rsnd_regmap_field_conf conf_null[] = { };
+
+       /*
+        * ssiu: SSIU0
+        * ssi : SSI0
+        */
+       int ret_ssiu = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSIU, "ssiu", conf_common_ssiu);
+       int ret_ssi  = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSI,  "ssi",  conf_common_ssi);
+       int ret_adg  = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG,  "adg",  conf_common_adg);
+       int ret_sdmc = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SDMC, "sdmc", conf_null);
+
+       return ret_adg | ret_ssiu | ret_ssi | ret_sdmc;
+}
+
+/*
+ *             Gen2
+ */
+static int rsnd_gen2_probe(struct rsnd_priv *priv)
+{
+       /*
+        * ssi : SSI0  - SSI9
+        * ssiu: SSIU0 - SSIU9
+        * scu : SRC0  - SRC9 etc
+        */
+       int ret_ssi  = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSI,  "ssi",  conf_common_ssi);
+       int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSIU, "ssiu", conf_common_ssiu);
+       int ret_scu  = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SCU,  "scu",  conf_common_scu);
+       int ret_adg  = rsnd_gen_regmap_init(priv,  1, RSND_BASE_ADG,  "adg",  conf_common_adg);
+
+       return ret_ssi | ret_ssiu | ret_scu | ret_adg;
+}
+
+/*
+ *             Gen1
+ */
+
+static int rsnd_gen1_probe(struct rsnd_priv *priv)
+{
+       /*
+        * ssi : SSI0 - SSI8
+        */
+       int ret_ssi  = rsnd_gen_regmap_init(priv, 9, RSND_BASE_SSI, "ssi", conf_common_ssi);
+       int ret_adg  = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg);
+
+       return ret_adg | ret_ssi;
+}
+
+/*
+ *             Gen
+ */
+int rsnd_gen_probe(struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen;
+       int ret;
+
+       gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
+       if (!gen)
+               return -ENOMEM;
+
+       priv->gen = gen;
+
+       ret = -ENODEV;
+       if (rsnd_is_gen1(priv))
+               ret = rsnd_gen1_probe(priv);
+       else if (rsnd_is_gen2(priv) ||
+                rsnd_is_gen3(priv))
+               ret = rsnd_gen2_probe(priv);
+       else if (rsnd_is_gen4(priv))
+               ret = rsnd_gen4_probe(priv);
+
+       if (ret < 0)
+               dev_err(dev, "unknown generation R-Car sound device\n");
+
+       return ret;
+}
diff --git a/sound/soc/renesas/rcar/mix.c b/sound/soc/renesas/rcar/mix.c
new file mode 100644 (file)
index 0000000..024d91c
--- /dev/null
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mix.c
+//
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+/*
+ *                 CTUn        MIXn
+ *                 +------+    +------+
+ * [SRC3 / SRC6] -> |CTU n0| ->        [MIX n0| ->
+ * [SRC4 / SRC9] -> |CTU n1| ->        [MIX n1| ->
+ * [SRC0 / SRC1] -> |CTU n2| ->        [MIX n2| ->
+ * [SRC2 / SRC5] -> |CTU n3| ->        [MIX n3| ->
+ *                 +------+    +------+
+ *
+ * ex)
+ *     DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>;
+ *     DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
+ *
+ * MIX Volume
+ *     amixer set "MIX",0  100%  // DAI0 Volume
+ *     amixer set "MIX",1  100%  // DAI1 Volume
+ *
+ * Volume Ramp
+ *     amixer set "MIX Ramp Up Rate"   "0.125 dB/1 step"
+ *     amixer set "MIX Ramp Down Rate" "4 dB/1 step"
+ *     amixer set "MIX Ramp" on
+ *     aplay xxx.wav &
+ *     amixer set "MIX",0  80%  // DAI0 Volume Down
+ *     amixer set "MIX",1 100%  // DAI1 Volume Up
+ */
+
+#include "rsnd.h"
+
+#define MIX_NAME_SIZE  16
+#define MIX_NAME "mix"
+
+struct rsnd_mix {
+       struct rsnd_mod mod;
+       struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */
+       struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */
+       struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */
+       struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */
+       struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
+       struct rsnd_kctrl_cfg_s rup;    /* Ramp Rate Up */
+       struct rsnd_kctrl_cfg_s rdw;    /* Ramp Rate Down */
+       u32 flags;
+};
+
+#define ONCE_KCTRL_INITIALIZED         (1 << 0)
+#define HAS_VOLA                       (1 << 1)
+#define HAS_VOLB                       (1 << 2)
+#define HAS_VOLC                       (1 << 3)
+#define HAS_VOLD                       (1 << 4)
+
+#define VOL_MAX                                0x3ff
+
+#define rsnd_mod_to_mix(_mod)  \
+       container_of((_mod), struct rsnd_mix, mod)
+
+#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
+#define rsnd_mix_nr(priv) ((priv)->mix_nr)
+#define for_each_rsnd_mix(pos, priv, i)                                        \
+       for ((i) = 0;                                                   \
+            ((i) < rsnd_mix_nr(priv)) &&                               \
+                    ((pos) = (struct rsnd_mix *)(priv)->mix + i);      \
+            i++)
+
+static void rsnd_mix_activation(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, MIX_SWRSR, 0);
+       rsnd_mod_write(mod, MIX_SWRSR, 1);
+}
+
+static void rsnd_mix_halt(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, MIX_MIXIR, 1);
+       rsnd_mod_write(mod, MIX_SWRSR, 0);
+}
+
+#define rsnd_mix_get_vol(mix, X) \
+       rsnd_flags_has(mix, HAS_VOL##X) ? \
+               (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
+static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
+                                     struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
+       u32 volA = rsnd_mix_get_vol(mix, A);
+       u32 volB = rsnd_mix_get_vol(mix, B);
+       u32 volC = rsnd_mix_get_vol(mix, C);
+       u32 volD = rsnd_mix_get_vol(mix, D);
+
+       dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n",
+               volA, volB, volC, volD);
+
+       rsnd_mod_write(mod, MIX_MDBAR, volA);
+       rsnd_mod_write(mod, MIX_MDBBR, volB);
+       rsnd_mod_write(mod, MIX_MDBCR, volC);
+       rsnd_mod_write(mod, MIX_MDBDR, volD);
+}
+
+static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
+                                struct rsnd_mod *mod)
+{
+       struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
+
+       rsnd_mod_write(mod, MIX_MIXIR, 1);
+
+       /* General Information */
+       rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
+
+       /* volume step */
+       rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren));
+       rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 |
+                                      rsnd_kctrl_vals(mix->rdw));
+
+       /* common volume parameter */
+       rsnd_mix_volume_parameter(io, mod);
+
+       rsnd_mod_write(mod, MIX_MIXIR, 0);
+}
+
+static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
+                                 struct rsnd_mod *mod)
+{
+       /* Disable MIX dB setting */
+       rsnd_mod_write(mod, MIX_MDBER, 0);
+
+       /* common volume parameter */
+       rsnd_mix_volume_parameter(io, mod);
+
+       /* Enable MIX dB setting */
+       rsnd_mod_write(mod, MIX_MDBER, 1);
+}
+
+static int rsnd_mix_probe_(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
+static int rsnd_mix_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       int ret;
+
+       ret = rsnd_mod_power_on(mod);
+       if (ret < 0)
+               return ret;
+
+       rsnd_mix_activation(mod);
+
+       rsnd_mix_volume_init(io, mod);
+
+       rsnd_mix_volume_update(io, mod);
+
+       return 0;
+}
+
+static int rsnd_mix_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_mix_halt(mod);
+
+       rsnd_mod_power_off(mod);
+
+       return 0;
+}
+
+static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct snd_soc_pcm_runtime *rtd)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
+       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+       struct rsnd_kctrl_cfg_s *volume;
+       int ret;
+
+       switch (rsnd_mod_id(src_mod)) {
+       case 3:
+       case 6: /* MDBAR */
+               volume = &mix->volumeA;
+               rsnd_flags_set(mix, HAS_VOLA);
+               break;
+       case 4:
+       case 9: /* MDBBR */
+               volume = &mix->volumeB;
+               rsnd_flags_set(mix, HAS_VOLB);
+               break;
+       case 0:
+       case 1: /* MDBCR */
+               volume = &mix->volumeC;
+               rsnd_flags_set(mix, HAS_VOLC);
+               break;
+       case 2:
+       case 5: /* MDBDR */
+               volume = &mix->volumeD;
+               rsnd_flags_set(mix, HAS_VOLD);
+               break;
+       default:
+               dev_err(dev, "unknown SRC is connected\n");
+               return -EINVAL;
+       }
+
+       /* Volume */
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
+                              "MIX Playback Volume",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_mix_volume_update,
+                              volume, VOL_MAX);
+       if (ret < 0)
+               return ret;
+       rsnd_kctrl_vals(*volume) = VOL_MAX;
+
+       if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
+               return ret;
+
+       /* Ramp */
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
+                              "MIX Ramp Switch",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_mix_volume_update,
+                              &mix->ren, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_kctrl_new_e(mod, io, rtd,
+                              "MIX Ramp Up Rate",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_mix_volume_update,
+                              &mix->rup,
+                              volume_ramp_rate,
+                              VOLUME_RAMP_MAX_MIX);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_kctrl_new_e(mod, io, rtd,
+                              "MIX Ramp Down Rate",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_mix_volume_update,
+                              &mix->rdw,
+                              volume_ramp_rate,
+                              VOLUME_RAMP_MAX_MIX);
+
+       rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED);
+
+       return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_mix_debug_info(struct seq_file *m,
+                               struct rsnd_dai_stream *io,
+                               struct rsnd_mod *mod)
+{
+       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
+                                 0xd00 + rsnd_mod_id(mod) * 0x40, 0x30);
+}
+#define DEBUG_INFO .debug_info = rsnd_mix_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
+static struct rsnd_mod_ops rsnd_mix_ops = {
+       .name           = MIX_NAME,
+       .probe          = rsnd_mix_probe_,
+       .init           = rsnd_mix_init,
+       .quit           = rsnd_mix_quit,
+       .pcm_new        = rsnd_mix_pcm_new,
+       .get_status     = rsnd_mod_get_status,
+       DEBUG_INFO
+};
+
+struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
+               id = 0;
+
+       return rsnd_mod_get(rsnd_mix_get(priv, id));
+}
+
+int rsnd_mix_probe(struct rsnd_priv *priv)
+{
+       struct device_node *node;
+       struct device_node *np;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mix *mix;
+       struct clk *clk;
+       char name[MIX_NAME_SIZE];
+       int i, nr, ret;
+
+       node = rsnd_mix_of_node(priv);
+       if (!node)
+               return 0; /* not used is not error */
+
+       nr = of_get_child_count(node);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_mix_probe_done;
+       }
+
+       mix     = devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL);
+       if (!mix) {
+               ret = -ENOMEM;
+               goto rsnd_mix_probe_done;
+       }
+
+       priv->mix_nr    = nr;
+       priv->mix       = mix;
+
+       i = 0;
+       ret = 0;
+       for_each_child_of_node(node, np) {
+               mix = rsnd_mix_get(priv, i);
+
+               snprintf(name, MIX_NAME_SIZE, "%s.%d",
+                        MIX_NAME, i);
+
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       of_node_put(np);
+                       goto rsnd_mix_probe_done;
+               }
+
+               ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
+                                   clk, RSND_MOD_MIX, i);
+               if (ret) {
+                       of_node_put(np);
+                       goto rsnd_mix_probe_done;
+               }
+
+               i++;
+       }
+
+rsnd_mix_probe_done:
+       of_node_put(node);
+
+       return ret;
+}
+
+void rsnd_mix_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_mix *mix;
+       int i;
+
+       for_each_rsnd_mix(mix, priv, i) {
+               rsnd_mod_quit(rsnd_mod_get(mix));
+       }
+}
diff --git a/sound/soc/renesas/rcar/rsnd.h b/sound/soc/renesas/rcar/rsnd.h
new file mode 100644 (file)
index 0000000..3c164d8
--- /dev/null
@@ -0,0 +1,896 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+#ifndef RSND_H
+#define RSND_H
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/sh_dma.h>
+#include <linux/workqueue.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#define RSND_BASE_ADG  0
+#define RSND_BASE_SSI  1
+#define RSND_BASE_SSIU 2
+#define RSND_BASE_SCU  3       // for Gen2/Gen3
+#define RSND_BASE_SDMC 3       // for Gen4     reuse
+#define RSND_BASE_MAX  4
+
+/*
+ *     pseudo register
+ *
+ * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different.
+ * This driver uses pseudo register in order to hide it.
+ * see gen1/gen2 for detail
+ */
+enum rsnd_reg {
+       /* SCU (MIX/CTU/DVC) */
+       SRC_I_BUSIF_MODE,
+       SRC_O_BUSIF_MODE,
+       SRC_ROUTE_MODE0,
+       SRC_SWRSR,
+       SRC_SRCIR,
+       SRC_ADINR,
+       SRC_IFSCR,
+       SRC_IFSVR,
+       SRC_SRCCR,
+       SRC_CTRL,
+       SRC_BSDSR,
+       SRC_BSISR,
+       SRC_INT_ENABLE0,
+       SRC_BUSIF_DALIGN,
+       SRCIN_TIMSEL0,
+       SRCIN_TIMSEL1,
+       SRCIN_TIMSEL2,
+       SRCIN_TIMSEL3,
+       SRCIN_TIMSEL4,
+       SRCOUT_TIMSEL0,
+       SRCOUT_TIMSEL1,
+       SRCOUT_TIMSEL2,
+       SRCOUT_TIMSEL3,
+       SRCOUT_TIMSEL4,
+       SCU_SYS_STATUS0,
+       SCU_SYS_STATUS1,
+       SCU_SYS_INT_EN0,
+       SCU_SYS_INT_EN1,
+       CMD_CTRL,
+       CMD_BUSIF_MODE,
+       CMD_BUSIF_DALIGN,
+       CMD_ROUTE_SLCT,
+       CMDOUT_TIMSEL,
+       CTU_SWRSR,
+       CTU_CTUIR,
+       CTU_ADINR,
+       CTU_CPMDR,
+       CTU_SCMDR,
+       CTU_SV00R,
+       CTU_SV01R,
+       CTU_SV02R,
+       CTU_SV03R,
+       CTU_SV04R,
+       CTU_SV05R,
+       CTU_SV06R,
+       CTU_SV07R,
+       CTU_SV10R,
+       CTU_SV11R,
+       CTU_SV12R,
+       CTU_SV13R,
+       CTU_SV14R,
+       CTU_SV15R,
+       CTU_SV16R,
+       CTU_SV17R,
+       CTU_SV20R,
+       CTU_SV21R,
+       CTU_SV22R,
+       CTU_SV23R,
+       CTU_SV24R,
+       CTU_SV25R,
+       CTU_SV26R,
+       CTU_SV27R,
+       CTU_SV30R,
+       CTU_SV31R,
+       CTU_SV32R,
+       CTU_SV33R,
+       CTU_SV34R,
+       CTU_SV35R,
+       CTU_SV36R,
+       CTU_SV37R,
+       MIX_SWRSR,
+       MIX_MIXIR,
+       MIX_ADINR,
+       MIX_MIXMR,
+       MIX_MVPDR,
+       MIX_MDBAR,
+       MIX_MDBBR,
+       MIX_MDBCR,
+       MIX_MDBDR,
+       MIX_MDBER,
+       DVC_SWRSR,
+       DVC_DVUIR,
+       DVC_ADINR,
+       DVC_DVUCR,
+       DVC_ZCMCR,
+       DVC_VOL0R,
+       DVC_VOL1R,
+       DVC_VOL2R,
+       DVC_VOL3R,
+       DVC_VOL4R,
+       DVC_VOL5R,
+       DVC_VOL6R,
+       DVC_VOL7R,
+       DVC_DVUER,
+       DVC_VRCTR,
+       DVC_VRPDR,
+       DVC_VRDBR,
+
+       /* ADG */
+       BRRA,
+       BRRB,
+       BRGCKR,
+       DIV_EN,
+       AUDIO_CLK_SEL0,
+       AUDIO_CLK_SEL1,
+       AUDIO_CLK_SEL2,
+
+       /* SSIU */
+       SSI_MODE,
+       SSI_MODE0,
+       SSI_MODE1,
+       SSI_MODE2,
+       SSI_CONTROL,
+       SSI_CTRL,
+       SSI_BUSIF0_MODE,
+       SSI_BUSIF1_MODE,
+       SSI_BUSIF2_MODE,
+       SSI_BUSIF3_MODE,
+       SSI_BUSIF4_MODE,
+       SSI_BUSIF5_MODE,
+       SSI_BUSIF6_MODE,
+       SSI_BUSIF7_MODE,
+       SSI_BUSIF0_ADINR,
+       SSI_BUSIF1_ADINR,
+       SSI_BUSIF2_ADINR,
+       SSI_BUSIF3_ADINR,
+       SSI_BUSIF4_ADINR,
+       SSI_BUSIF5_ADINR,
+       SSI_BUSIF6_ADINR,
+       SSI_BUSIF7_ADINR,
+       SSI_BUSIF0_DALIGN,
+       SSI_BUSIF1_DALIGN,
+       SSI_BUSIF2_DALIGN,
+       SSI_BUSIF3_DALIGN,
+       SSI_BUSIF4_DALIGN,
+       SSI_BUSIF5_DALIGN,
+       SSI_BUSIF6_DALIGN,
+       SSI_BUSIF7_DALIGN,
+       SSI_INT_ENABLE,
+       SSI_SYS_STATUS0,
+       SSI_SYS_STATUS1,
+       SSI_SYS_STATUS2,
+       SSI_SYS_STATUS3,
+       SSI_SYS_STATUS4,
+       SSI_SYS_STATUS5,
+       SSI_SYS_STATUS6,
+       SSI_SYS_STATUS7,
+       SSI_SYS_INT_ENABLE0,
+       SSI_SYS_INT_ENABLE1,
+       SSI_SYS_INT_ENABLE2,
+       SSI_SYS_INT_ENABLE3,
+       SSI_SYS_INT_ENABLE4,
+       SSI_SYS_INT_ENABLE5,
+       SSI_SYS_INT_ENABLE6,
+       SSI_SYS_INT_ENABLE7,
+       HDMI0_SEL,
+       HDMI1_SEL,
+       SSI9_BUSIF0_MODE,
+       SSI9_BUSIF1_MODE,
+       SSI9_BUSIF2_MODE,
+       SSI9_BUSIF3_MODE,
+       SSI9_BUSIF4_MODE,
+       SSI9_BUSIF5_MODE,
+       SSI9_BUSIF6_MODE,
+       SSI9_BUSIF7_MODE,
+       SSI9_BUSIF0_ADINR,
+       SSI9_BUSIF1_ADINR,
+       SSI9_BUSIF2_ADINR,
+       SSI9_BUSIF3_ADINR,
+       SSI9_BUSIF4_ADINR,
+       SSI9_BUSIF5_ADINR,
+       SSI9_BUSIF6_ADINR,
+       SSI9_BUSIF7_ADINR,
+       SSI9_BUSIF0_DALIGN,
+       SSI9_BUSIF1_DALIGN,
+       SSI9_BUSIF2_DALIGN,
+       SSI9_BUSIF3_DALIGN,
+       SSI9_BUSIF4_DALIGN,
+       SSI9_BUSIF5_DALIGN,
+       SSI9_BUSIF6_DALIGN,
+       SSI9_BUSIF7_DALIGN,
+
+       /* SSI */
+       SSICR,
+       SSISR,
+       SSITDR,
+       SSIRDR,
+       SSIWSR,
+
+       REG_MAX,
+};
+#define SRCIN_TIMSEL(i)                (SRCIN_TIMSEL0 + (i))
+#define SRCOUT_TIMSEL(i)       (SRCOUT_TIMSEL0 + (i))
+#define CTU_SVxxR(i, j)                (CTU_SV00R + (i * 8) + (j))
+#define DVC_VOLxR(i)           (DVC_VOL0R + (i))
+#define AUDIO_CLK_SEL(i)       (AUDIO_CLK_SEL0 + (i))
+#define SSI_BUSIF_MODE(i)      (SSI_BUSIF0_MODE + (i))
+#define SSI_BUSIF_ADINR(i)     (SSI_BUSIF0_ADINR + (i))
+#define SSI_BUSIF_DALIGN(i)    (SSI_BUSIF0_DALIGN + (i))
+#define SSI9_BUSIF_MODE(i)     (SSI9_BUSIF0_MODE + (i))
+#define SSI9_BUSIF_ADINR(i)    (SSI9_BUSIF0_ADINR + (i))
+#define SSI9_BUSIF_DALIGN(i)   (SSI9_BUSIF0_DALIGN + (i))
+#define SSI_SYS_STATUS(i)      (SSI_SYS_STATUS0 + (i))
+#define SSI_SYS_INT_ENABLE(i) (SSI_SYS_INT_ENABLE0 + (i))
+
+
+struct rsnd_priv;
+struct rsnd_mod;
+struct rsnd_dai;
+struct rsnd_dai_stream;
+
+/*
+ *     R-Car basic functions
+ */
+u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg);
+void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data);
+void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data);
+u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+
+/*
+ *     R-Car DMA
+ */
+int rsnd_dma_attach(struct rsnd_dai_stream *io,
+                   struct rsnd_mod *mod, struct rsnd_mod **dma_mod);
+int rsnd_dma_probe(struct rsnd_priv *priv);
+struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
+                                         struct rsnd_mod *mod, char *x);
+
+/*
+ *     R-Car sound mod
+ */
+enum rsnd_mod_type {
+       RSND_MOD_AUDMAPP,
+       RSND_MOD_AUDMA,
+       RSND_MOD_DVC,
+       RSND_MOD_MIX,
+       RSND_MOD_CTU,
+       RSND_MOD_CMD,
+       RSND_MOD_SRC,
+       RSND_MOD_SSIM3,         /* SSI multi 3 */
+       RSND_MOD_SSIM2,         /* SSI multi 2 */
+       RSND_MOD_SSIM1,         /* SSI multi 1 */
+       RSND_MOD_SSIP,          /* SSI parent */
+       RSND_MOD_SSI,
+       RSND_MOD_SSIU,
+       RSND_MOD_MAX,
+};
+
+struct rsnd_mod_ops {
+       char *name;
+       struct dma_chan* (*dma_req)(struct rsnd_dai_stream *io,
+                                   struct rsnd_mod *mod);
+       int (*probe)(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
+                    struct rsnd_priv *priv);
+       int (*remove)(struct rsnd_mod *mod,
+                     struct rsnd_dai_stream *io,
+                     struct rsnd_priv *priv);
+       int (*init)(struct rsnd_mod *mod,
+                   struct rsnd_dai_stream *io,
+                   struct rsnd_priv *priv);
+       int (*quit)(struct rsnd_mod *mod,
+                   struct rsnd_dai_stream *io,
+                   struct rsnd_priv *priv);
+       int (*start)(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
+                    struct rsnd_priv *priv);
+       int (*stop)(struct rsnd_mod *mod,
+                   struct rsnd_dai_stream *io,
+                   struct rsnd_priv *priv);
+       int (*irq)(struct rsnd_mod *mod,
+                  struct rsnd_dai_stream *io,
+                  struct rsnd_priv *priv, int enable);
+       int (*pcm_new)(struct rsnd_mod *mod,
+                      struct rsnd_dai_stream *io,
+                      struct snd_soc_pcm_runtime *rtd);
+       int (*hw_params)(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params);
+       int (*pointer)(struct rsnd_mod *mod,
+                      struct rsnd_dai_stream *io,
+                      snd_pcm_uframes_t *pointer);
+       int (*fallback)(struct rsnd_mod *mod,
+                       struct rsnd_dai_stream *io,
+                       struct rsnd_priv *priv);
+       int (*prepare)(struct rsnd_mod *mod,
+                      struct rsnd_dai_stream *io,
+                      struct rsnd_priv *priv);
+       int (*cleanup)(struct rsnd_mod *mod,
+                      struct rsnd_dai_stream *io,
+                      struct rsnd_priv *priv);
+       int (*hw_free)(struct rsnd_mod *mod,
+                      struct rsnd_dai_stream *io,
+                      struct snd_pcm_substream *substream);
+       u32 *(*get_status)(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          enum rsnd_mod_type type);
+       int (*id)(struct rsnd_mod *mod);
+       int (*id_sub)(struct rsnd_mod *mod);
+       int (*id_cmd)(struct rsnd_mod *mod);
+
+#ifdef CONFIG_DEBUG_FS
+       void (*debug_info)(struct seq_file *m,
+                          struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+#endif
+};
+
+struct rsnd_dai_stream;
+struct rsnd_mod {
+       int id;
+       enum rsnd_mod_type type;
+       struct rsnd_mod_ops *ops;
+       struct rsnd_priv *priv;
+       struct clk *clk;
+       u32 status;
+};
+/*
+ * status
+ *
+ * 0xH000DCB0
+ *
+ * B   0: init         1: quit
+ * C   0: start        1: stop
+ * D   0: hw_params    1: hw_free
+ *
+ * H is always called (see __rsnd_mod_call)
+ */
+#define __rsnd_mod_shift_init          4
+#define __rsnd_mod_shift_quit          4
+#define __rsnd_mod_shift_start         8
+#define __rsnd_mod_shift_stop          8
+#define __rsnd_mod_shift_hw_params     12
+#define __rsnd_mod_shift_hw_free       12
+#define __rsnd_mod_shift_probe         28 /* always called */
+#define __rsnd_mod_shift_remove                28 /* always called */
+#define __rsnd_mod_shift_irq           28 /* always called */
+#define __rsnd_mod_shift_pcm_new       28 /* always called */
+#define __rsnd_mod_shift_fallback      28 /* always called */
+#define __rsnd_mod_shift_pointer       28 /* always called */
+#define __rsnd_mod_shift_prepare       28 /* always called */
+#define __rsnd_mod_shift_cleanup       28 /* always called */
+
+#define __rsnd_mod_add_probe           0
+#define __rsnd_mod_add_remove          0
+#define __rsnd_mod_add_prepare         0
+#define __rsnd_mod_add_cleanup         0
+#define __rsnd_mod_add_init             1 /* needs protect */
+#define __rsnd_mod_add_quit            -1 /* needs protect */
+#define __rsnd_mod_add_start            1 /* needs protect */
+#define __rsnd_mod_add_stop            -1 /* needs protect */
+#define __rsnd_mod_add_hw_params        1 /* needs protect */
+#define __rsnd_mod_add_hw_free         -1 /* needs protect */
+#define __rsnd_mod_add_irq             0
+#define __rsnd_mod_add_pcm_new         0
+#define __rsnd_mod_add_fallback                0
+#define __rsnd_mod_add_pointer         0
+
+#define __rsnd_mod_call_probe          0
+#define __rsnd_mod_call_remove         0
+#define __rsnd_mod_call_prepare                0
+#define __rsnd_mod_call_cleanup                0
+#define __rsnd_mod_call_init           0 /* needs protect */
+#define __rsnd_mod_call_quit           1 /* needs protect */
+#define __rsnd_mod_call_start          0 /* needs protect */
+#define __rsnd_mod_call_stop           1 /* needs protect */
+#define __rsnd_mod_call_hw_params      0 /* needs protect */
+#define __rsnd_mod_call_hw_free                1 /* needs protect */
+#define __rsnd_mod_call_irq            0
+#define __rsnd_mod_call_pcm_new                0
+#define __rsnd_mod_call_fallback       0
+#define __rsnd_mod_call_pointer                0
+
+#define rsnd_mod_to_priv(mod)  ((mod)->priv)
+#define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
+#define rsnd_mod_power_off(mod)        clk_disable((mod)->clk)
+#define rsnd_mod_get(ip)       (&(ip)->mod)
+
+int rsnd_mod_init(struct rsnd_priv *priv,
+                 struct rsnd_mod *mod,
+                 struct rsnd_mod_ops *ops,
+                 struct clk *clk,
+                 enum rsnd_mod_type type,
+                 int id);
+void rsnd_mod_quit(struct rsnd_mod *mod);
+struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
+                                 struct rsnd_mod *mod);
+void rsnd_mod_interrupt(struct rsnd_mod *mod,
+                       void (*callback)(struct rsnd_mod *mod,
+                                        struct rsnd_dai_stream *io));
+u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        enum rsnd_mod_type type);
+int rsnd_mod_id(struct rsnd_mod *mod);
+int rsnd_mod_id_raw(struct rsnd_mod *mod);
+int rsnd_mod_id_sub(struct rsnd_mod *mod);
+char *rsnd_mod_name(struct rsnd_mod *mod);
+struct rsnd_mod *rsnd_mod_next(int *iterator,
+                              struct rsnd_dai_stream *io,
+                              enum rsnd_mod_type *array,
+                              int array_size);
+#define for_each_rsnd_mod(iterator, pos, io)                           \
+       for (iterator = 0;                                              \
+            (pos = rsnd_mod_next(&iterator, io, NULL, 0)); iterator++)
+#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size)       \
+       for (iterator = 0;                                              \
+            (pos = rsnd_mod_next(&iterator, io, array, size)); iterator++)
+#define for_each_rsnd_mod_array(iterator, pos, io, array)              \
+       for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array))
+
+void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
+               struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
+               struct device_node *node,
+               struct device_node *playback,
+               struct device_node *capture);
+int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name);
+int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx);
+
+int rsnd_channel_normalization(int chan);
+#define rsnd_runtime_channel_original(io) \
+       rsnd_runtime_channel_original_with_params(io, NULL)
+int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
+                               struct snd_pcm_hw_params *params);
+#define rsnd_runtime_channel_after_ctu(io)                     \
+       rsnd_runtime_channel_after_ctu_with_params(io, NULL)
+int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
+                               struct snd_pcm_hw_params *params);
+#define rsnd_runtime_channel_for_ssi(io) \
+       rsnd_runtime_channel_for_ssi_with_params(io, NULL)
+int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
+                                struct snd_pcm_hw_params *params);
+int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io);
+int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io);
+
+/*
+ * DT
+ */
+#define rsnd_parse_of_node(priv, node)                                 \
+       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node)
+#define RSND_NODE_DAI  "rcar_sound,dai"
+#define RSND_NODE_SSI  "rcar_sound,ssi"
+#define RSND_NODE_SSIU "rcar_sound,ssiu"
+#define RSND_NODE_SRC  "rcar_sound,src"
+#define RSND_NODE_CTU  "rcar_sound,ctu"
+#define RSND_NODE_MIX  "rcar_sound,mix"
+#define RSND_NODE_DVC  "rcar_sound,dvc"
+
+/*
+ *     R-Car sound DAI
+ */
+#define RSND_DAI_NAME_SIZE     16
+struct rsnd_dai_stream {
+       char name[RSND_DAI_NAME_SIZE];
+       struct snd_pcm_substream *substream;
+       struct rsnd_mod *mod[RSND_MOD_MAX];
+       struct rsnd_mod *dma;
+       struct rsnd_dai *rdai;
+       struct device *dmac_dev; /* for IPMMU */
+       u32 converted_rate;      /* converted sampling rate */
+       int converted_chan;      /* converted channels */
+       u32 parent_ssi_status;
+       u32 flags;
+};
+
+/* flags */
+#define RSND_STREAM_HDMI0      (1 << 0) /* for HDMI0 */
+#define RSND_STREAM_HDMI1      (1 << 1) /* for HDMI1 */
+#define RSND_STREAM_TDM_SPLIT  (1 << 2) /* for TDM split mode */
+#define RSND_HW_RULE_ERR       (1 << 3) /* hw_rule error */
+
+#define rsnd_io_to_mod(io, i)  ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
+#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
+#define rsnd_io_to_mod_ssiu(io)        rsnd_io_to_mod((io), RSND_MOD_SSIU)
+#define rsnd_io_to_mod_ssip(io)        rsnd_io_to_mod((io), RSND_MOD_SSIP)
+#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
+#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
+#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX)
+#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC)
+#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD)
+#define rsnd_io_to_rdai(io)    ((io)->rdai)
+#define rsnd_io_to_priv(io)    (rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
+#define rsnd_io_is_play(io)    (&rsnd_io_to_rdai(io)->playback == io)
+#define rsnd_io_to_runtime(io) ((io)->substream ? \
+                               (io)->substream->runtime : NULL)
+#define rsnd_io_converted_rate(io)     ((io)->converted_rate)
+#define rsnd_io_converted_chan(io)     ((io)->converted_chan)
+int rsnd_io_is_working(struct rsnd_dai_stream *io);
+
+struct rsnd_dai {
+       char name[RSND_DAI_NAME_SIZE];
+       struct rsnd_dai_stream playback;
+       struct rsnd_dai_stream capture;
+       struct rsnd_priv *priv;
+       struct snd_pcm_hw_constraint_list constraint;
+       struct of_phandle_args dai_args;
+
+       int max_channels;       /* 2ch - 16ch */
+       int ssi_lane;           /* 1lane - 4lane */
+       int chan_width;         /* 16/24/32 bit width */
+
+       unsigned int clk_master:1;
+       unsigned int bit_clk_inv:1;
+       unsigned int frm_clk_inv:1;
+       unsigned int sys_delay:1;
+       unsigned int data_alignment:1;
+};
+
+#define rsnd_rdai_nr(priv) ((priv)->rdai_nr)
+#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
+#define rsnd_rdai_to_priv(rdai) ((rdai)->priv)
+#define for_each_rsnd_dai(rdai, priv, i)               \
+       for (i = 0;                                     \
+            (i < rsnd_rdai_nr(priv)) &&                \
+            ((rdai) = rsnd_rdai_get(priv, i));         \
+            i++)
+
+struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id);
+
+#define rsnd_rdai_channels_set(rdai, max_channels) \
+       rsnd_rdai_channels_ctrl(rdai, max_channels)
+#define rsnd_rdai_channels_get(rdai) \
+       rsnd_rdai_channels_ctrl(rdai, 0)
+int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai,
+                           int max_channels);
+
+#define rsnd_rdai_ssi_lane_set(rdai, ssi_lane) \
+       rsnd_rdai_ssi_lane_ctrl(rdai, ssi_lane)
+#define rsnd_rdai_ssi_lane_get(rdai) \
+       rsnd_rdai_ssi_lane_ctrl(rdai, 0)
+int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
+                           int ssi_lane);
+
+#define rsnd_rdai_width_set(rdai, width) \
+       rsnd_rdai_width_ctrl(rdai, width)
+#define rsnd_rdai_width_get(rdai) \
+       rsnd_rdai_width_ctrl(rdai, 0)
+int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width);
+int rsnd_dai_connect(struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io,
+                    enum rsnd_mod_type type);
+
+/*
+ *     R-Car Gen1/Gen2
+ */
+int rsnd_gen_probe(struct rsnd_priv *priv);
+void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
+                              struct rsnd_mod *mod,
+                              enum rsnd_reg reg);
+phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
+#ifdef CONFIG_DEBUG_FS
+void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id);
+#endif
+
+/*
+ *     R-Car ADG
+ */
+int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate);
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod);
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate);
+int rsnd_adg_probe(struct rsnd_priv *priv);
+void rsnd_adg_remove(struct rsnd_priv *priv);
+int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
+                                 struct rsnd_dai_stream *io,
+                                 unsigned int in_rate,
+                                 unsigned int out_rate);
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
+                                struct rsnd_dai_stream *io);
+#define rsnd_adg_clk_enable(priv)      rsnd_adg_clk_control(priv, 1)
+#define rsnd_adg_clk_disable(priv)     rsnd_adg_clk_control(priv, 0)
+void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);
+void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m);
+
+/*
+ *     R-Car sound priv
+ */
+struct rsnd_priv {
+
+       struct platform_device *pdev;
+       spinlock_t lock;
+       unsigned long flags;
+#define RSND_GEN_MASK  (0xF << 0)
+#define RSND_GEN1      (1 << 0)
+#define RSND_GEN2      (2 << 0)
+#define RSND_GEN3      (3 << 0)
+#define RSND_GEN4      (4 << 0)
+#define RSND_SOC_MASK  (0xFF << 4)
+#define RSND_SOC_E     (1 << 4) /* E1/E2/E3 */
+
+       /*
+        * below value will be filled on rsnd_gen_probe()
+        */
+       void *gen;
+
+       /*
+        * below value will be filled on rsnd_adg_probe()
+        */
+       void *adg;
+
+       /*
+        * below value will be filled on rsnd_dma_probe()
+        */
+       void *dma;
+
+       /*
+        * below value will be filled on rsnd_ssi_probe()
+        */
+       void *ssi;
+       int ssi_nr;
+
+       /*
+        * below value will be filled on rsnd_ssiu_probe()
+        */
+       void *ssiu;
+       int ssiu_nr;
+
+       /*
+        * below value will be filled on rsnd_src_probe()
+        */
+       void *src;
+       int src_nr;
+
+       /*
+        * below value will be filled on rsnd_ctu_probe()
+        */
+       void *ctu;
+       int ctu_nr;
+
+       /*
+        * below value will be filled on rsnd_mix_probe()
+        */
+       void *mix;
+       int mix_nr;
+
+       /*
+        * below value will be filled on rsnd_dvc_probe()
+        */
+       void *dvc;
+       int dvc_nr;
+
+       /*
+        * below value will be filled on rsnd_cmd_probe()
+        */
+       void *cmd;
+       int cmd_nr;
+
+       /*
+        * below value will be filled on rsnd_dai_probe()
+        */
+       struct snd_soc_dai_driver *daidrv;
+       struct rsnd_dai *rdai;
+       int rdai_nr;
+
+#define RSND_MAX_COMPONENT 3
+       int component_dais[RSND_MAX_COMPONENT];
+};
+
+#define rsnd_priv_to_pdev(priv)        ((priv)->pdev)
+#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
+
+#define rsnd_is_gen1(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
+#define rsnd_is_gen2(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
+#define rsnd_is_gen3(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3)
+#define rsnd_is_gen4(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN4)
+#define rsnd_is_gen3_e3(priv)  (((priv)->flags & \
+                                       (RSND_GEN_MASK | RSND_SOC_MASK)) == \
+                                       (RSND_GEN3 | RSND_SOC_E))
+
+#define rsnd_flags_has(p, f) ((p)->flags & (f))
+#define rsnd_flags_set(p, f) ((p)->flags |= (f))
+#define rsnd_flags_del(p, f) ((p)->flags &= ~(f))
+
+/*
+ *     rsnd_kctrl
+ */
+struct rsnd_kctrl_cfg {
+       unsigned int max;
+       unsigned int size;
+       u32 *val;
+       const char * const *texts;
+       int (*accept)(struct rsnd_dai_stream *io);
+       void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+       struct rsnd_dai_stream *io;
+       struct snd_card *card;
+       struct snd_kcontrol *kctrl;
+       struct rsnd_mod *mod;
+};
+
+#define RSND_MAX_CHANNELS      8
+struct rsnd_kctrl_cfg_m {
+       struct rsnd_kctrl_cfg cfg;
+       u32 val[RSND_MAX_CHANNELS];
+};
+
+struct rsnd_kctrl_cfg_s {
+       struct rsnd_kctrl_cfg cfg;
+       u32 val;
+};
+#define rsnd_kctrl_size(x)     ((x).cfg.size)
+#define rsnd_kctrl_max(x)      ((x).cfg.max)
+#define rsnd_kctrl_valm(x, i)  ((x).val[i])    /* = (x).cfg.val[i] */
+#define rsnd_kctrl_vals(x)     ((x).val)       /* = (x).cfg.val[0] */
+
+int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io);
+int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io);
+struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg);
+struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg);
+int rsnd_kctrl_new(struct rsnd_mod *mod,
+                  struct rsnd_dai_stream *io,
+                  struct snd_soc_pcm_runtime *rtd,
+                  const unsigned char *name,
+                  int (*accept)(struct rsnd_dai_stream *io),
+                  void (*update)(struct rsnd_dai_stream *io,
+                                 struct rsnd_mod *mod),
+                  struct rsnd_kctrl_cfg *cfg,
+                  const char * const *texts,
+                  int size,
+                  u32 max);
+
+#define rsnd_kctrl_new_m(mod, io, rtd, name, accept, update, cfg, size, max) \
+       rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_m(cfg), \
+                      NULL, size, max)
+
+#define rsnd_kctrl_new_s(mod, io, rtd, name, accept, update, cfg, max) \
+       rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
+                      NULL, 1, max)
+
+#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts, size) \
+       rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
+                      texts, 1, size)
+
+extern const char * const volume_ramp_rate[];
+#define VOLUME_RAMP_MAX_DVC    (0x17 + 1)
+#define VOLUME_RAMP_MAX_MIX    (0x0a + 1)
+
+/*
+ *     R-Car SSI
+ */
+int rsnd_ssi_probe(struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
+int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
+u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io);
+int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
+
+#define rsnd_ssi_is_pin_sharing(io)    \
+       __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
+int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
+
+#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI)
+void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
+                           struct device_node *playback,
+                           struct device_node *capture);
+unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
+                      int param1, int param2, int *idx);
+
+/*
+ *     R-Car SSIU
+ */
+int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
+                    struct rsnd_mod *mod);
+int rsnd_ssiu_probe(struct rsnd_priv *priv);
+void rsnd_ssiu_remove(struct rsnd_priv *priv);
+void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
+                            struct device_node *playback,
+                            struct device_node *capture);
+#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU)
+bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod);
+
+/*
+ *     R-Car SRC
+ */
+int rsnd_src_probe(struct rsnd_priv *priv);
+void rsnd_src_remove(struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
+
+#define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1)
+#define rsnd_src_get_out_rate(priv, io) rsnd_src_get_rate(priv, io, 0)
+unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
+                              struct rsnd_dai_stream *io,
+                              int is_in);
+
+#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC)
+#define rsnd_parse_connect_src(rdai, playback, capture)                        \
+       rsnd_parse_connect_common(rdai, "src", rsnd_src_mod_get,        \
+                                 rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
+                                                  playback, capture)
+
+/*
+ *     R-Car CTU
+ */
+int rsnd_ctu_probe(struct rsnd_priv *priv);
+void rsnd_ctu_remove(struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
+#define rsnd_parse_connect_ctu(rdai, playback, capture)                        \
+       rsnd_parse_connect_common(rdai, "ctu", rsnd_ctu_mod_get,        \
+                                 rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
+                                                  playback, capture)
+
+/*
+ *     R-Car MIX
+ */
+int rsnd_mix_probe(struct rsnd_priv *priv);
+void rsnd_mix_remove(struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
+#define rsnd_parse_connect_mix(rdai, playback, capture)                        \
+       rsnd_parse_connect_common(rdai, "mix", rsnd_mix_mod_get,        \
+                                 rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
+                                                  playback, capture)
+
+/*
+ *     R-Car DVC
+ */
+int rsnd_dvc_probe(struct rsnd_priv *priv);
+void rsnd_dvc_remove(struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
+#define rsnd_parse_connect_dvc(rdai, playback, capture)                        \
+       rsnd_parse_connect_common(rdai, "dvc", rsnd_dvc_mod_get,        \
+                                 rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
+                                                  playback, capture)
+
+/*
+ *     R-Car CMD
+ */
+int rsnd_cmd_probe(struct rsnd_priv *priv);
+void rsnd_cmd_remove(struct rsnd_priv *priv);
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
+
+void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
+
+/*
+ * If you don't need interrupt status debug message,
+ * define RSND_DEBUG_NO_IRQ_STATUS as 1 on top of src.c/ssi.c
+ *
+ * #define RSND_DEBUG_NO_IRQ_STATUS 1
+ */
+#define rsnd_print_irq_status(dev, param...) do {      \
+       if (!IS_BUILTIN(RSND_DEBUG_NO_IRQ_STATUS))      \
+               dev_info(dev, param);                   \
+} while (0)
+
+#ifdef CONFIG_DEBUG_FS
+int rsnd_debugfs_probe(struct snd_soc_component *component);
+void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr,
+                          void __iomem *base, int offset, int size);
+void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod,
+                              int reg_id, int offset, int size);
+
+#else
+#define rsnd_debugfs_probe  NULL
+#endif
+
+#endif /* RSND_H */
diff --git a/sound/soc/renesas/rcar/src.c b/sound/soc/renesas/rcar/src.c
new file mode 100644 (file)
index 0000000..e7f86db
--- /dev/null
@@ -0,0 +1,732 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SRC support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+/*
+ * You can use Synchronous Sampling Rate Convert (if no DVC)
+ *
+ *     amixer set "SRC Out Rate" on
+ *     aplay xxx.wav &
+ *     amixer set "SRC Out Rate" 96000 // convert rate to 96000Hz
+ *     amixer set "SRC Out Rate" 22050 // convert rate to 22050Hz
+ */
+
+/*
+ * you can enable below define if you don't need
+ * SSI interrupt status debug message when debugging
+ * see rsnd_print_irq_status()
+ *
+ * #define RSND_DEBUG_NO_IRQ_STATUS 1
+ */
+
+#include <linux/of_irq.h>
+#include "rsnd.h"
+
+#define SRC_NAME "src"
+
+/* SCU_SYSTEM_STATUS0/1 */
+#define OUF_SRC(id)    ((1 << (id + 16)) | (1 << id))
+
+struct rsnd_src {
+       struct rsnd_mod mod;
+       struct rsnd_mod *dma;
+       struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */
+       struct rsnd_kctrl_cfg_s sync; /* sync convert */
+       int irq;
+};
+
+#define RSND_SRC_NAME_SIZE 16
+
+#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)
+#define rsnd_src_nr(priv) ((priv)->src_nr)
+#define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val)
+
+#define rsnd_mod_to_src(_mod)                          \
+       container_of((_mod), struct rsnd_src, mod)
+
+#define for_each_rsnd_src(pos, priv, i)                                \
+       for ((i) = 0;                                           \
+            ((i) < rsnd_src_nr(priv)) &&                       \
+            ((pos) = (struct rsnd_src *)(priv)->src + i);      \
+            i++)
+
+
+/*
+ *             image of SRC (Sampling Rate Converter)
+ *
+ * 96kHz   <-> +-----+ 48kHz   +-----+  48kHz  +-------+
+ * 48kHz   <-> | SRC | <------>        | SSI | <-----> | codec |
+ * 44.1kHz <-> +-----+         +-----+         +-------+
+ * ...
+ *
+ */
+
+static void rsnd_src_activation(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, SRC_SWRSR, 0);
+       rsnd_mod_write(mod, SRC_SWRSR, 1);
+}
+
+static void rsnd_src_halt(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, SRC_SRCIR, 1);
+       rsnd_mod_write(mod, SRC_SWRSR, 0);
+}
+
+static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
+                                        struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       int is_play = rsnd_io_is_play(io);
+
+       return rsnd_dma_request_channel(rsnd_src_of_node(priv),
+                                       SRC_NAME, mod,
+                                       is_play ? "rx" : "tx");
+}
+
+static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
+                                struct rsnd_mod *mod)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 convert_rate;
+
+       if (!runtime)
+               return 0;
+
+       if (!rsnd_src_sync_is_enabled(mod))
+               return rsnd_io_converted_rate(io);
+
+       convert_rate = src->sync.val;
+
+       if (!convert_rate)
+               convert_rate = rsnd_io_converted_rate(io);
+
+       if (!convert_rate)
+               convert_rate = runtime->rate;
+
+       return convert_rate;
+}
+
+unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
+                              struct rsnd_dai_stream *io,
+                              int is_in)
+{
+       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       unsigned int rate = 0;
+       int is_play = rsnd_io_is_play(io);
+
+       /*
+        * Playback
+        * runtime_rate -> [SRC] -> convert_rate
+        *
+        * Capture
+        * convert_rate -> [SRC] -> runtime_rate
+        */
+
+       if (is_play == is_in)
+               return runtime->rate;
+
+       /*
+        * return convert rate if SRC is used,
+        * otherwise, return runtime->rate as usual
+        */
+       if (src_mod)
+               rate = rsnd_src_convert_rate(io, src_mod);
+
+       if (!rate)
+               rate = runtime->rate;
+
+       return rate;
+}
+
+static const u32 bsdsr_table_pattern1[] = {
+       0x01800000, /* 6 - 1/6 */
+       0x01000000, /* 6 - 1/4 */
+       0x00c00000, /* 6 - 1/3 */
+       0x00800000, /* 6 - 1/2 */
+       0x00600000, /* 6 - 2/3 */
+       0x00400000, /* 6 - 1   */
+};
+
+static const u32 bsdsr_table_pattern2[] = {
+       0x02400000, /* 6 - 1/6 */
+       0x01800000, /* 6 - 1/4 */
+       0x01200000, /* 6 - 1/3 */
+       0x00c00000, /* 6 - 1/2 */
+       0x00900000, /* 6 - 2/3 */
+       0x00600000, /* 6 - 1   */
+};
+
+static const u32 bsisr_table[] = {
+       0x00100060, /* 6 - 1/6 */
+       0x00100040, /* 6 - 1/4 */
+       0x00100030, /* 6 - 1/3 */
+       0x00100020, /* 6 - 1/2 */
+       0x00100020, /* 6 - 2/3 */
+       0x00100020, /* 6 - 1   */
+};
+
+static const u32 chan288888[] = {
+       0x00000006, /* 1 to 2 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+};
+
+static const u32 chan244888[] = {
+       0x00000006, /* 1 to 2 */
+       0x0000001e, /* 1 to 4 */
+       0x0000001e, /* 1 to 4 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+       0x000001fe, /* 1 to 8 */
+};
+
+static const u32 chan222222[] = {
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+       0x00000006, /* 1 to 2 */
+};
+
+static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
+                                     struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       int is_play = rsnd_io_is_play(io);
+       int use_src = 0;
+       u32 fin, fout;
+       u32 ifscr, fsrate, adinr;
+       u32 cr, route;
+       u32 i_busif, o_busif, tmp;
+       const u32 *bsdsr_table;
+       const u32 *chptn;
+       uint ratio;
+       int chan;
+       int idx;
+
+       if (!runtime)
+               return;
+
+       fin  = rsnd_src_get_in_rate(priv, io);
+       fout = rsnd_src_get_out_rate(priv, io);
+
+       chan = rsnd_runtime_channel_original(io);
+
+       /* 6 - 1/6 are very enough ratio for SRC_BSDSR */
+       if (fin == fout)
+               ratio = 0;
+       else if (fin > fout)
+               ratio = 100 * fin / fout;
+       else
+               ratio = 100 * fout / fin;
+
+       if (ratio > 600) {
+               dev_err(dev, "FSO/FSI ratio error\n");
+               return;
+       }
+
+       use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod);
+
+       /*
+        * SRC_ADINR
+        */
+       adinr = rsnd_get_adinr_bit(mod, io) | chan;
+
+       /*
+        * SRC_IFSCR / SRC_IFSVR
+        */
+       ifscr = 0;
+       fsrate = 0;
+       if (use_src) {
+               u64 n;
+
+               ifscr = 1;
+               n = (u64)0x0400000 * fin;
+               do_div(n, fout);
+               fsrate = n;
+       }
+
+       /*
+        * SRC_SRCCR / SRC_ROUTE_MODE0
+        */
+       cr      = 0x00011110;
+       route   = 0x0;
+       if (use_src) {
+               route   = 0x1;
+
+               if (rsnd_src_sync_is_enabled(mod)) {
+                       cr |= 0x1;
+                       route |= rsnd_io_is_play(io) ?
+                               (0x1 << 24) : (0x1 << 25);
+               }
+       }
+
+       /*
+        * SRC_BSDSR / SRC_BSISR
+        *
+        * see
+        *      Combination of Register Setting Related to
+        *      FSO/FSI Ratio and Channel, Latency
+        */
+       switch (rsnd_mod_id(mod)) {
+       case 0:
+               chptn           = chan288888;
+               bsdsr_table     = bsdsr_table_pattern1;
+               break;
+       case 1:
+       case 3:
+       case 4:
+               chptn           = chan244888;
+               bsdsr_table     = bsdsr_table_pattern1;
+               break;
+       case 2:
+       case 9:
+               chptn           = chan222222;
+               bsdsr_table     = bsdsr_table_pattern1;
+               break;
+       case 5:
+       case 6:
+       case 7:
+       case 8:
+               chptn           = chan222222;
+               bsdsr_table     = bsdsr_table_pattern2;
+               break;
+       default:
+               goto convert_rate_err;
+       }
+
+       /*
+        * E3 need to overwrite
+        */
+       if (rsnd_is_gen3_e3(priv))
+               switch (rsnd_mod_id(mod)) {
+               case 0:
+               case 4:
+                       chptn   = chan222222;
+               }
+
+       for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++)
+               if (chptn[idx] & (1 << chan))
+                       break;
+
+       if (chan > 8 ||
+           idx >= ARRAY_SIZE(chan222222))
+               goto convert_rate_err;
+
+       /* BUSIF_MODE */
+       tmp = rsnd_get_busif_shift(io, mod);
+       i_busif = ( is_play ? tmp : 0) | 1;
+       o_busif = (!is_play ? tmp : 0) | 1;
+
+       rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
+
+       rsnd_mod_write(mod, SRC_SRCIR, 1);      /* initialize */
+       rsnd_mod_write(mod, SRC_ADINR, adinr);
+       rsnd_mod_write(mod, SRC_IFSCR, ifscr);
+       rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+       rsnd_mod_write(mod, SRC_SRCCR, cr);
+       rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]);
+       rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]);
+       rsnd_mod_write(mod, SRC_SRCIR, 0);      /* cancel initialize */
+
+       rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif);
+       rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif);
+
+       rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
+
+       rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
+
+       return;
+
+convert_rate_err:
+       dev_err(dev, "unknown BSDSR/BSDIR settings\n");
+}
+
+static int rsnd_src_irq(struct rsnd_mod *mod,
+                       struct rsnd_dai_stream *io,
+                       struct rsnd_priv *priv,
+                       int enable)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 sys_int_val, int_val, sys_int_mask;
+       int irq = src->irq;
+       int id = rsnd_mod_id(mod);
+
+       sys_int_val =
+       sys_int_mask = OUF_SRC(id);
+       int_val = 0x3300;
+
+       /*
+        * IRQ is not supported on non-DT
+        * see
+        *      rsnd_src_probe_()
+        */
+       if ((irq <= 0) || !enable) {
+               sys_int_val = 0;
+               int_val = 0;
+       }
+
+       /*
+        * WORKAROUND
+        *
+        * ignore over flow error when rsnd_src_sync_is_enabled()
+        */
+       if (rsnd_src_sync_is_enabled(mod))
+               sys_int_val = sys_int_val & 0xffff;
+
+       rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
+       rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
+       rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
+
+       return 0;
+}
+
+static void rsnd_src_status_clear(struct rsnd_mod *mod)
+{
+       u32 val = OUF_SRC(rsnd_mod_id(mod));
+
+       rsnd_mod_write(mod, SCU_SYS_STATUS0, val);
+       rsnd_mod_write(mod, SCU_SYS_STATUS1, val);
+}
+
+static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 val0, val1;
+       u32 status0, status1;
+       bool ret = false;
+
+       val0 = val1 = OUF_SRC(rsnd_mod_id(mod));
+
+       /*
+        * WORKAROUND
+        *
+        * ignore over flow error when rsnd_src_sync_is_enabled()
+        */
+       if (rsnd_src_sync_is_enabled(mod))
+               val0 = val0 & 0xffff;
+
+       status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0);
+       status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1);
+       if ((status0 & val0) || (status1 & val1)) {
+               rsnd_print_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n",
+                                     rsnd_mod_name(mod), status0, status1);
+
+               ret = true;
+       }
+
+       return ret;
+}
+
+static int rsnd_src_start(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
+                         struct rsnd_priv *priv)
+{
+       u32 val;
+
+       /*
+        * WORKAROUND
+        *
+        * Enable SRC output if you want to use sync convert together with DVC
+        */
+       val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ?
+               0x01 : 0x11;
+
+       rsnd_mod_write(mod, SRC_CTRL, val);
+
+       return 0;
+}
+
+static int rsnd_src_stop(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_mod_write(mod, SRC_CTRL, 0);
+
+       return 0;
+}
+
+static int rsnd_src_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       int ret;
+
+       /* reset sync convert_rate */
+       src->sync.val = 0;
+
+       ret = rsnd_mod_power_on(mod);
+       if (ret < 0)
+               return ret;
+
+       rsnd_src_activation(mod);
+
+       rsnd_src_set_convert_rate(io, mod);
+
+       rsnd_src_status_clear(mod);
+
+       return 0;
+}
+
+static int rsnd_src_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+       rsnd_src_halt(mod);
+
+       rsnd_mod_power_off(mod);
+
+       /* reset sync convert_rate */
+       src->sync.val = 0;
+
+       return 0;
+}
+
+static void __rsnd_src_interrupt(struct rsnd_mod *mod,
+                                struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       bool stop = false;
+
+       spin_lock(&priv->lock);
+
+       /* ignore all cases if not working */
+       if (!rsnd_io_is_working(io))
+               goto rsnd_src_interrupt_out;
+
+       if (rsnd_src_error_occurred(mod))
+               stop = true;
+
+       rsnd_src_status_clear(mod);
+rsnd_src_interrupt_out:
+
+       spin_unlock(&priv->lock);
+
+       if (stop)
+               snd_pcm_stop_xrun(io->substream);
+}
+
+static irqreturn_t rsnd_src_interrupt(int irq, void *data)
+{
+       struct rsnd_mod *mod = data;
+
+       rsnd_mod_interrupt(mod, __rsnd_src_interrupt);
+
+       return IRQ_HANDLED;
+}
+
+static int rsnd_src_probe_(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int irq = src->irq;
+       int ret;
+
+       if (irq > 0) {
+               /*
+                * IRQ is not supported on non-DT
+                * see
+                *      rsnd_src_irq()
+                */
+               ret = devm_request_irq(dev, irq,
+                                      rsnd_src_interrupt,
+                                      IRQF_SHARED,
+                                      dev_name(dev), mod);
+               if (ret)
+                       return ret;
+       }
+
+       ret = rsnd_dma_attach(io, mod, &src->dma);
+
+       return ret;
+}
+
+static int rsnd_src_pcm_new(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct snd_soc_pcm_runtime *rtd)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       int ret;
+
+       /*
+        * enable SRC sync convert if possible
+        */
+
+       /*
+        * It can't use SRC Synchronous convert
+        * when Capture if it uses CMD
+        */
+       if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io))
+               return 0;
+
+       /*
+        * enable sync convert
+        */
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
+                              rsnd_io_is_play(io) ?
+                              "SRC Out Rate Switch" :
+                              "SRC In Rate Switch",
+                              rsnd_kctrl_accept_anytime,
+                              rsnd_src_set_convert_rate,
+                              &src->sen, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_kctrl_new_s(mod, io, rtd,
+                              rsnd_io_is_play(io) ?
+                              "SRC Out Rate" :
+                              "SRC In Rate",
+                              rsnd_kctrl_accept_runtime,
+                              rsnd_src_set_convert_rate,
+                              &src->sync, 192000);
+
+       return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_src_debug_info(struct seq_file *m,
+                               struct rsnd_dai_stream *io,
+                               struct rsnd_mod *mod)
+{
+       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
+                                 rsnd_mod_id(mod) * 0x20, 0x20);
+       seq_puts(m, "\n");
+       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
+                                 0x1c0, 0x20);
+       seq_puts(m, "\n");
+       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
+                                 0x200 + rsnd_mod_id(mod) * 0x40, 0x40);
+}
+#define DEBUG_INFO .debug_info = rsnd_src_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
+static struct rsnd_mod_ops rsnd_src_ops = {
+       .name           = SRC_NAME,
+       .dma_req        = rsnd_src_dma_req,
+       .probe          = rsnd_src_probe_,
+       .init           = rsnd_src_init,
+       .quit           = rsnd_src_quit,
+       .start          = rsnd_src_start,
+       .stop           = rsnd_src_stop,
+       .irq            = rsnd_src_irq,
+       .pcm_new        = rsnd_src_pcm_new,
+       .get_status     = rsnd_mod_get_status,
+       DEBUG_INFO
+};
+
+struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
+               id = 0;
+
+       return rsnd_mod_get(rsnd_src_get(priv, id));
+}
+
+int rsnd_src_probe(struct rsnd_priv *priv)
+{
+       struct device_node *node;
+       struct device_node *np;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_src *src;
+       struct clk *clk;
+       char name[RSND_SRC_NAME_SIZE];
+       int i, nr, ret;
+
+       node = rsnd_src_of_node(priv);
+       if (!node)
+               return 0; /* not used is not error */
+
+       nr = rsnd_node_count(priv, node, SRC_NAME);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_src_probe_done;
+       }
+
+       src     = devm_kcalloc(dev, nr, sizeof(*src), GFP_KERNEL);
+       if (!src) {
+               ret = -ENOMEM;
+               goto rsnd_src_probe_done;
+       }
+
+       priv->src_nr    = nr;
+       priv->src       = src;
+
+       i = 0;
+       for_each_child_of_node(node, np) {
+               if (!of_device_is_available(np))
+                       goto skip;
+
+               i = rsnd_node_fixed_index(dev, np, SRC_NAME, i);
+               if (i < 0) {
+                       ret = -EINVAL;
+                       of_node_put(np);
+                       goto rsnd_src_probe_done;
+               }
+
+               src = rsnd_src_get(priv, i);
+
+               snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
+                        SRC_NAME, i);
+
+               src->irq = irq_of_parse_and_map(np, 0);
+               if (!src->irq) {
+                       ret = -EINVAL;
+                       of_node_put(np);
+                       goto rsnd_src_probe_done;
+               }
+
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       of_node_put(np);
+                       goto rsnd_src_probe_done;
+               }
+
+               ret = rsnd_mod_init(priv, rsnd_mod_get(src),
+                                   &rsnd_src_ops, clk, RSND_MOD_SRC, i);
+               if (ret) {
+                       of_node_put(np);
+                       goto rsnd_src_probe_done;
+               }
+
+skip:
+               i++;
+       }
+
+       ret = 0;
+
+rsnd_src_probe_done:
+       of_node_put(node);
+
+       return ret;
+}
+
+void rsnd_src_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_src *src;
+       int i;
+
+       for_each_rsnd_src(src, priv, i) {
+               rsnd_mod_quit(rsnd_mod_get(src));
+       }
+}
diff --git a/sound/soc/renesas/rcar/ssi.c b/sound/soc/renesas/rcar/ssi.c
new file mode 100644 (file)
index 0000000..b3d4e8a
--- /dev/null
@@ -0,0 +1,1260 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SSIU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on fsi.c
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
+
+/*
+ * you can enable below define if you don't need
+ * SSI interrupt status debug message when debugging
+ * see rsnd_print_irq_status()
+ *
+ * #define RSND_DEBUG_NO_IRQ_STATUS 1
+ */
+
+#include <sound/simple_card_utils.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/delay.h>
+#include "rsnd.h"
+#define RSND_SSI_NAME_SIZE 16
+
+/*
+ * SSICR
+ */
+#define        FORCE           (1u << 31)      /* Fixed */
+#define        DMEN            (1u << 28)      /* DMA Enable */
+#define        UIEN            (1u << 27)      /* Underflow Interrupt Enable */
+#define        OIEN            (1u << 26)      /* Overflow Interrupt Enable */
+#define        IIEN            (1u << 25)      /* Idle Mode Interrupt Enable */
+#define        DIEN            (1u << 24)      /* Data Interrupt Enable */
+#define        CHNL_4          (1u << 22)      /* Channels */
+#define        CHNL_6          (2u << 22)      /* Channels */
+#define        CHNL_8          (3u << 22)      /* Channels */
+#define DWL_MASK       (7u << 19)      /* Data Word Length mask */
+#define        DWL_8           (0u << 19)      /* Data Word Length */
+#define        DWL_16          (1u << 19)      /* Data Word Length */
+#define        DWL_18          (2u << 19)      /* Data Word Length */
+#define        DWL_20          (3u << 19)      /* Data Word Length */
+#define        DWL_22          (4u << 19)      /* Data Word Length */
+#define        DWL_24          (5u << 19)      /* Data Word Length */
+#define        DWL_32          (6u << 19)      /* Data Word Length */
+
+/*
+ * System word length
+ */
+#define        SWL_16          (1 << 16)       /* R/W System Word Length */
+#define        SWL_24          (2 << 16)       /* R/W System Word Length */
+#define        SWL_32          (3 << 16)       /* R/W System Word Length */
+
+#define        SCKD            (1 << 15)       /* Serial Bit Clock Direction */
+#define        SWSD            (1 << 14)       /* Serial WS Direction */
+#define        SCKP            (1 << 13)       /* Serial Bit Clock Polarity */
+#define        SWSP            (1 << 12)       /* Serial WS Polarity */
+#define        SDTA            (1 << 10)       /* Serial Data Alignment */
+#define        PDTA            (1 <<  9)       /* Parallel Data Alignment */
+#define        DEL             (1 <<  8)       /* Serial Data Delay */
+#define        CKDV(v)         (v <<  4)       /* Serial Clock Division Ratio */
+#define        TRMD            (1 <<  1)       /* Transmit/Receive Mode Select */
+#define        EN              (1 <<  0)       /* SSI Module Enable */
+
+/*
+ * SSISR
+ */
+#define        UIRQ            (1 << 27)       /* Underflow Error Interrupt Status */
+#define        OIRQ            (1 << 26)       /* Overflow Error Interrupt Status */
+#define        IIRQ            (1 << 25)       /* Idle Mode Interrupt Status */
+#define        DIRQ            (1 << 24)       /* Data Interrupt Status Flag */
+
+/*
+ * SSIWSR
+ */
+#define CONT           (1 << 8)        /* WS Continue Function */
+#define WS_MODE                (1 << 0)        /* WS Mode */
+
+#define SSI_NAME "ssi"
+
+struct rsnd_ssi {
+       struct rsnd_mod mod;
+
+       u32 flags;
+       u32 cr_own;
+       u32 cr_clk;
+       u32 cr_mode;
+       u32 cr_en;
+       u32 wsr;
+       int chan;
+       int rate;
+       int irq;
+       unsigned int usrcnt;
+
+       /* for PIO */
+       int byte_pos;
+       int byte_per_period;
+       int next_period_byte;
+};
+
+/* flags */
+#define RSND_SSI_CLK_PIN_SHARE         (1 << 0)
+#define RSND_SSI_NO_BUSIF              (1 << 1) /* SSI+DMA without BUSIF */
+#define RSND_SSI_PROBED                        (1 << 2)
+
+#define for_each_rsnd_ssi(pos, priv, i)                                        \
+       for (i = 0;                                                     \
+            (i < rsnd_ssi_nr(priv)) &&                                 \
+               ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i));         \
+            i++)
+
+#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
+#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
+#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
+#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
+#define rsnd_ssi_is_multi_secondary(mod, io)                           \
+       (rsnd_ssi_multi_secondaries(io) & (1 << rsnd_mod_id(mod)))
+#define rsnd_ssi_is_run_mods(mod, io) \
+       (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
+#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
+
+int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       int use_busif = 0;
+
+       if (!rsnd_ssi_is_dma_mode(mod))
+               return 0;
+
+       if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF)))
+               use_busif = 1;
+       if (rsnd_io_to_mod_src(io))
+               use_busif = 1;
+
+       return use_busif;
+}
+
+static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, SSISR, 0);
+}
+
+static u32 rsnd_ssi_status_get(struct rsnd_mod *mod)
+{
+       return rsnd_mod_read(mod, SSISR);
+}
+
+static void rsnd_ssi_status_check(struct rsnd_mod *mod,
+                                 u32 bit)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 status;
+       int i;
+
+       for (i = 0; i < 1024; i++) {
+               status = rsnd_ssi_status_get(mod);
+               if (status & bit)
+                       return;
+
+               udelay(5);
+       }
+
+       dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod));
+}
+
+static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io)
+{
+       static const enum rsnd_mod_type types[] = {
+               RSND_MOD_SSIM1,
+               RSND_MOD_SSIM2,
+               RSND_MOD_SSIM3,
+       };
+       int i, mask;
+
+       mask = 0;
+       for (i = 0; i < ARRAY_SIZE(types); i++) {
+               struct rsnd_mod *mod = rsnd_io_to_mod(io, types[i]);
+
+               if (!mod)
+                       continue;
+
+               mask |= 1 << rsnd_mod_id(mod);
+       }
+
+       return mask;
+}
+
+static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+       struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
+       u32 mods;
+
+       mods = rsnd_ssi_multi_secondaries_runtime(io) |
+               1 << rsnd_mod_id(ssi_mod);
+
+       if (ssi_parent_mod)
+               mods |= 1 << rsnd_mod_id(ssi_parent_mod);
+
+       return mods;
+}
+
+u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io)
+{
+       if (rsnd_runtime_is_multi_ssi(io))
+               return rsnd_ssi_multi_secondaries(io);
+
+       return 0;
+}
+
+static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai)
+{
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int width = rsnd_rdai_width_get(rdai);
+
+       switch (width) {
+       case 32: return SWL_32;
+       case 24: return SWL_24;
+       case 16: return SWL_16;
+       }
+
+       dev_err(dev, "unsupported slot width value: %d\n", width);
+       return 0;
+}
+
+unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
+                      int param1, int param2, int *idx)
+{
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       static const int ssi_clk_mul_table[] = {
+               1, 2, 4, 8, 16, 6, 12,
+       };
+       int j, ret;
+       unsigned int main_rate;
+       int width = rsnd_rdai_width_get(rdai);
+
+       for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
+
+               /*
+                * It will set SSIWSR.CONT here, but SSICR.CKDV = 000
+                * with it is not allowed. (SSIWSR.WS_MODE with
+                * SSICR.CKDV = 000 is not allowed either).
+                * Skip it. See SSICR.CKDV
+                */
+               if (j == 0)
+                       continue;
+
+               main_rate = width * param1 * param2 * ssi_clk_mul_table[j];
+
+               ret = rsnd_adg_clk_query(priv, main_rate);
+               if (ret < 0)
+                       continue;
+
+               if (idx)
+                       *idx = j;
+
+               return main_rate;
+       }
+
+       return 0;
+}
+
+static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
+                                    struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       int chan = rsnd_runtime_channel_for_ssi(io);
+       int idx, ret;
+       unsigned int main_rate;
+       unsigned int rate = rsnd_io_is_play(io) ?
+               rsnd_src_get_out_rate(priv, io) :
+               rsnd_src_get_in_rate(priv, io);
+
+       if (!rsnd_rdai_is_clk_master(rdai))
+               return 0;
+
+       if (!rsnd_ssi_can_output_clk(mod))
+               return 0;
+
+       if (rsnd_ssi_is_multi_secondary(mod, io))
+               return 0;
+
+       if (rsnd_runtime_is_tdm_split(io))
+               chan = rsnd_io_converted_chan(io);
+
+       chan = rsnd_channel_normalization(chan);
+
+       if (ssi->usrcnt > 0) {
+               if (ssi->rate != rate) {
+                       dev_err(dev, "SSI parent/child should use same rate\n");
+                       return -EINVAL;
+               }
+
+               if (ssi->chan != chan) {
+                       dev_err(dev, "SSI parent/child should use same chan\n");
+                       return -EINVAL;
+               }
+
+               return 0;
+       }
+
+       ret = -EIO;
+       main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
+       if (!main_rate)
+               goto rate_err;
+
+       ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
+       if (ret < 0)
+               goto rate_err;
+
+       /*
+        * SSI clock will be output contiguously
+        * by below settings.
+        * This means, rsnd_ssi_master_clk_start()
+        * and rsnd_ssi_register_setup() are necessary
+        * for SSI parent
+        *
+        * SSICR  : FORCE, SCKD, SWSD
+        * SSIWSR : CONT
+        */
+       ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) |
+                       SCKD | SWSD | CKDV(idx);
+       ssi->wsr = CONT;
+       ssi->rate = rate;
+       ssi->chan = chan;
+
+       dev_dbg(dev, "%s outputs %d chan %u Hz\n",
+               rsnd_mod_name(mod), chan, rate);
+
+       return 0;
+
+rate_err:
+       dev_err(dev, "unsupported clock rate\n");
+       return ret;
+}
+
+static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
+                                    struct rsnd_dai_stream *io)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       if (!rsnd_rdai_is_clk_master(rdai))
+               return;
+
+       if (!rsnd_ssi_can_output_clk(mod))
+               return;
+
+       if (ssi->usrcnt > 1)
+               return;
+
+       ssi->cr_clk     = 0;
+       ssi->rate       = 0;
+       ssi->chan       = 0;
+
+       rsnd_adg_ssi_clk_stop(mod);
+}
+
+static void rsnd_ssi_config_init(struct rsnd_mod *mod,
+                               struct rsnd_dai_stream *io)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       u32 cr_own      = ssi->cr_own;
+       u32 cr_mode     = ssi->cr_mode;
+       u32 wsr         = ssi->wsr;
+       int width;
+       int is_tdm, is_tdm_split;
+
+       is_tdm          = rsnd_runtime_is_tdm(io);
+       is_tdm_split    = rsnd_runtime_is_tdm_split(io);
+
+       if (is_tdm)
+               dev_dbg(dev, "TDM mode\n");
+       if (is_tdm_split)
+               dev_dbg(dev, "TDM Split mode\n");
+
+       cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
+
+       if (rdai->bit_clk_inv)
+               cr_own |= SCKP;
+       if (rdai->frm_clk_inv && !is_tdm)
+               cr_own |= SWSP;
+       if (rdai->data_alignment)
+               cr_own |= SDTA;
+       if (rdai->sys_delay)
+               cr_own |= DEL;
+
+       /*
+        * TDM Mode
+        * see
+        *      rsnd_ssiu_init_gen2()
+        */
+       if (is_tdm || is_tdm_split) {
+               wsr     |= WS_MODE;
+               cr_own  |= CHNL_8;
+       }
+
+       /*
+        * We shouldn't exchange SWSP after running.
+        * This means, parent needs to care it.
+        */
+       if (rsnd_ssi_is_parent(mod, io))
+               goto init_end;
+
+       if (rsnd_io_is_play(io))
+               cr_own |= TRMD;
+
+       cr_own &= ~DWL_MASK;
+       width = snd_pcm_format_width(runtime->format);
+       if (is_tdm_split) {
+               /*
+                * The SWL and DWL bits in SSICR should be fixed at 32-bit
+                * setting when TDM split mode.
+                * see datasheet
+                *      Operation :: TDM Format Split Function (TDM Split Mode)
+                */
+               width = 32;
+       }
+
+       switch (width) {
+       case 8:
+               cr_own |= DWL_8;
+               break;
+       case 16:
+               cr_own |= DWL_16;
+               break;
+       case 24:
+               cr_own |= DWL_24;
+               break;
+       case 32:
+               cr_own |= DWL_32;
+               break;
+       }
+
+       if (rsnd_ssi_is_dma_mode(mod)) {
+               cr_mode = UIEN | OIEN | /* over/under run */
+                         DMEN;         /* DMA : enable DMA */
+       } else {
+               cr_mode = DIEN;         /* PIO : enable Data interrupt */
+       }
+
+init_end:
+       ssi->cr_own     = cr_own;
+       ssi->cr_mode    = cr_mode;
+       ssi->wsr        = wsr;
+}
+
+static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       rsnd_mod_write(mod, SSIWSR,     ssi->wsr);
+       rsnd_mod_write(mod, SSICR,      ssi->cr_own     |
+                                       ssi->cr_clk     |
+                                       ssi->cr_mode    |
+                                       ssi->cr_en);
+}
+
+/*
+ *     SSI mod common functions
+ */
+static int rsnd_ssi_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       int ret;
+
+       if (!rsnd_ssi_is_run_mods(mod, io))
+               return 0;
+
+       ret = rsnd_ssi_master_clk_start(mod, io);
+       if (ret < 0)
+               return ret;
+
+       ssi->usrcnt++;
+
+       ret = rsnd_mod_power_on(mod);
+       if (ret < 0)
+               return ret;
+
+       rsnd_ssi_config_init(mod, io);
+
+       rsnd_ssi_register_setup(mod);
+
+       /* clear error status */
+       rsnd_ssi_status_clear(mod);
+
+       return 0;
+}
+
+static int rsnd_ssi_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       if (!rsnd_ssi_is_run_mods(mod, io))
+               return 0;
+
+       if (!ssi->usrcnt) {
+               dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod));
+               return -EIO;
+       }
+
+       rsnd_ssi_master_clk_stop(mod, io);
+
+       rsnd_mod_power_off(mod);
+
+       ssi->usrcnt--;
+
+       if (!ssi->usrcnt) {
+               ssi->cr_own     = 0;
+               ssi->cr_mode    = 0;
+               ssi->wsr        = 0;
+       }
+
+       return 0;
+}
+
+static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
+                             struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       unsigned int fmt_width = snd_pcm_format_width(params_format(params));
+
+       if (fmt_width > rdai->chan_width) {
+               struct rsnd_priv *priv = rsnd_io_to_priv(io);
+               struct device *dev = rsnd_priv_to_dev(priv);
+
+               dev_err(dev, "invalid combination of slot-width and format-data-width\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rsnd_ssi_start(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
+                         struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       if (!rsnd_ssi_is_run_mods(mod, io))
+               return 0;
+
+       /*
+        * EN will be set via SSIU :: SSI_CONTROL
+        * if Multi channel mode
+        */
+       if (rsnd_ssi_multi_secondaries_runtime(io))
+               return 0;
+
+       /*
+        * EN is for data output.
+        * SSI parent EN is not needed.
+        */
+       if (rsnd_ssi_is_parent(mod, io))
+               return 0;
+
+       ssi->cr_en = EN;
+
+       rsnd_mod_write(mod, SSICR,      ssi->cr_own     |
+                                       ssi->cr_clk     |
+                                       ssi->cr_mode    |
+                                       ssi->cr_en);
+
+       return 0;
+}
+
+static int rsnd_ssi_stop(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       u32 cr;
+
+       if (!rsnd_ssi_is_run_mods(mod, io))
+               return 0;
+
+       if (rsnd_ssi_is_parent(mod, io))
+               return 0;
+
+       cr  =   ssi->cr_own     |
+               ssi->cr_clk;
+
+       /*
+        * disable all IRQ,
+        * Playback: Wait all data was sent
+        * Capture:  It might not receave data. Do nothing
+        */
+       if (rsnd_io_is_play(io)) {
+               rsnd_mod_write(mod, SSICR, cr | ssi->cr_en);
+               rsnd_ssi_status_check(mod, DIRQ);
+       }
+
+       /* In multi-SSI mode, stop is performed by setting ssi0129 in
+        * SSI_CONTROL to 0 (in rsnd_ssio_stop_gen2). Do nothing here.
+        */
+       if (rsnd_ssi_multi_secondaries_runtime(io))
+               return 0;
+
+       /*
+        * disable SSI,
+        * and, wait idle state
+        */
+       rsnd_mod_write(mod, SSICR, cr); /* disabled all */
+       rsnd_ssi_status_check(mod, IIRQ);
+
+       ssi->cr_en = 0;
+
+       return 0;
+}
+
+static int rsnd_ssi_irq(struct rsnd_mod *mod,
+                       struct rsnd_dai_stream *io,
+                       struct rsnd_priv *priv,
+                       int enable)
+{
+       u32 val = 0;
+       int is_tdm, is_tdm_split;
+       int id = rsnd_mod_id(mod);
+
+       is_tdm          = rsnd_runtime_is_tdm(io);
+       is_tdm_split    = rsnd_runtime_is_tdm_split(io);
+
+       if (rsnd_is_gen1(priv))
+               return 0;
+
+       if (rsnd_ssi_is_parent(mod, io))
+               return 0;
+
+       if (!rsnd_ssi_is_run_mods(mod, io))
+               return 0;
+
+       if (enable)
+               val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000;
+
+       if (is_tdm || is_tdm_split) {
+               switch (id) {
+               case 0:
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+               case 9:
+                       val |= 0x0000ff00;
+                       break;
+               }
+       }
+
+       rsnd_mod_write(mod, SSI_INT_ENABLE, val);
+
+       return 0;
+}
+
+static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
+                                  struct rsnd_dai_stream *io);
+static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
+                                struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int is_dma = rsnd_ssi_is_dma_mode(mod);
+       u32 status;
+       bool elapsed = false;
+       bool stop = false;
+
+       spin_lock(&priv->lock);
+
+       /* ignore all cases if not working */
+       if (!rsnd_io_is_working(io))
+               goto rsnd_ssi_interrupt_out;
+
+       status = rsnd_ssi_status_get(mod);
+
+       /* PIO only */
+       if (!is_dma && (status & DIRQ))
+               elapsed = rsnd_ssi_pio_interrupt(mod, io);
+
+       /* DMA only */
+       if (is_dma && (status & (UIRQ | OIRQ))) {
+               rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
+                                     rsnd_mod_name(mod), status);
+
+               stop = true;
+       }
+
+       stop |= rsnd_ssiu_busif_err_status_clear(mod);
+
+       rsnd_ssi_status_clear(mod);
+rsnd_ssi_interrupt_out:
+       spin_unlock(&priv->lock);
+
+       if (elapsed)
+               snd_pcm_period_elapsed(io->substream);
+
+       if (stop)
+               snd_pcm_stop_xrun(io->substream);
+
+}
+
+static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
+{
+       struct rsnd_mod *mod = data;
+
+       rsnd_mod_interrupt(mod, __rsnd_ssi_interrupt);
+
+       return IRQ_HANDLED;
+}
+
+static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod,
+                               struct rsnd_dai_stream *io,
+                               enum rsnd_mod_type type)
+{
+       /*
+        * SSIP (= SSI parent) needs to be special, otherwise,
+        * 2nd SSI might doesn't start. see also rsnd_mod_call()
+        *
+        * We can't include parent SSI status on SSI, because we don't know
+        * how many SSI requests parent SSI. Thus, it is localed on "io" now.
+        * ex) trouble case
+        *      Playback: SSI0
+        *      Capture : SSI1 (needs SSI0)
+        *
+        * 1) start Capture  -> SSI0/SSI1 are started.
+        * 2) start Playback -> SSI0 doesn't work, because it is already
+        *                      marked as "started" on 1)
+        *
+        * OTOH, using each mod's status is good for MUX case.
+        * It doesn't need to start in 2nd start
+        * ex)
+        *      IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
+        *                          |
+        *      IO-1: SRC1 -> CTU2 -+
+        *
+        * 1) start IO-0 ->     start SSI0
+        * 2) start IO-1 ->     SSI0 doesn't need to start, because it is
+        *                      already started on 1)
+        */
+       if (type == RSND_MOD_SSIP)
+               return &io->parent_ssi_status;
+
+       return rsnd_mod_get_status(mod, io, type);
+}
+
+/*
+ *             SSI PIO
+ */
+static void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
+                                  struct rsnd_dai_stream *io)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+
+       if (!__rsnd_ssi_is_pin_sharing(mod))
+               return;
+
+       if (!rsnd_rdai_is_clk_master(rdai))
+               return;
+
+       if (rsnd_ssi_is_multi_secondary(mod, io))
+               return;
+
+       switch (rsnd_mod_id(mod)) {
+       case 1:
+       case 2:
+       case 9:
+               rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP);
+               break;
+       case 4:
+               rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP);
+               break;
+       case 8:
+               rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP);
+               break;
+       }
+}
+
+static int rsnd_ssi_pcm_new(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct snd_soc_pcm_runtime *rtd)
+{
+       /*
+        * rsnd_rdai_is_clk_master() will be enabled after set_fmt,
+        * and, pcm_new will be called after it.
+        * This function reuse pcm_new at this point.
+        */
+       rsnd_ssi_parent_attach(mod, io);
+
+       return 0;
+}
+
+static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
+                                struct rsnd_dai_stream *io,
+                                struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       int ret = 0;
+
+       /*
+        * SSIP/SSIU/IRQ are not needed on
+        * SSI Multi secondaries
+        */
+       if (rsnd_ssi_is_multi_secondary(mod, io))
+               return 0;
+
+       /*
+        * It can't judge ssi parent at this point
+        * see rsnd_ssi_pcm_new()
+        */
+
+       /*
+        * SSI might be called again as PIO fallback
+        * It is easy to manual handling for IRQ request/free
+        *
+        * OTOH, this function might be called many times if platform is
+        * using MIX. It needs xxx_attach() many times on xxx_probe().
+        * Because of it, we can't control .probe/.remove calling count by
+        * mod->status.
+        * But it don't need to call request_irq() many times.
+        * Let's control it by RSND_SSI_PROBED flag.
+        */
+       if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
+               ret = request_irq(ssi->irq,
+                                 rsnd_ssi_interrupt,
+                                 IRQF_SHARED,
+                                 dev_name(dev), mod);
+
+               rsnd_flags_set(ssi, RSND_SSI_PROBED);
+       }
+
+       return ret;
+}
+
+static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
+                                 struct rsnd_dai_stream *io,
+                                 struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io);
+
+       /* Do nothing if non SSI (= SSI parent, multi SSI) mod */
+       if (pure_ssi_mod != mod)
+               return 0;
+
+       /* PIO will request IRQ again */
+       if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
+               free_irq(ssi->irq, mod);
+
+               rsnd_flags_del(ssi, RSND_SSI_PROBED);
+       }
+
+       return 0;
+}
+
+/*
+ *     SSI PIO functions
+ */
+static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
+                                  struct rsnd_dai_stream *io)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos);
+       int shift = 0;
+       int byte_pos;
+       bool elapsed = false;
+
+       if (snd_pcm_format_width(runtime->format) == 24)
+               shift = 8;
+
+       /*
+        * 8/16/32 data can be assesse to TDR/RDR register
+        * directly as 32bit data
+        * see rsnd_ssi_init()
+        */
+       if (rsnd_io_is_play(io))
+               rsnd_mod_write(mod, SSITDR, (*buf) << shift);
+       else
+               *buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
+
+       byte_pos = ssi->byte_pos + sizeof(*buf);
+
+       if (byte_pos >= ssi->next_period_byte) {
+               int period_pos = byte_pos / ssi->byte_per_period;
+
+               if (period_pos >= runtime->periods) {
+                       byte_pos = 0;
+                       period_pos = 0;
+               }
+
+               ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period;
+
+               elapsed = true;
+       }
+
+       WRITE_ONCE(ssi->byte_pos, byte_pos);
+
+       return elapsed;
+}
+
+static int rsnd_ssi_pio_init(struct rsnd_mod *mod,
+                            struct rsnd_dai_stream *io,
+                            struct rsnd_priv *priv)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       if (!rsnd_ssi_is_parent(mod, io)) {
+               ssi->byte_pos           = 0;
+               ssi->byte_per_period    = runtime->period_size *
+                                         runtime->channels *
+                                         samples_to_bytes(runtime, 1);
+               ssi->next_period_byte   = ssi->byte_per_period;
+       }
+
+       return rsnd_ssi_init(mod, io, priv);
+}
+
+static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           snd_pcm_uframes_t *pointer)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+
+       *pointer = bytes_to_frames(runtime, READ_ONCE(ssi->byte_pos));
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
+       .name           = SSI_NAME,
+       .probe          = rsnd_ssi_common_probe,
+       .remove         = rsnd_ssi_common_remove,
+       .init           = rsnd_ssi_pio_init,
+       .quit           = rsnd_ssi_quit,
+       .start          = rsnd_ssi_start,
+       .stop           = rsnd_ssi_stop,
+       .irq            = rsnd_ssi_irq,
+       .pointer        = rsnd_ssi_pio_pointer,
+       .pcm_new        = rsnd_ssi_pcm_new,
+       .hw_params      = rsnd_ssi_hw_params,
+       .get_status     = rsnd_ssi_get_status,
+};
+
+static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
+                             struct rsnd_dai_stream *io,
+                             struct rsnd_priv *priv)
+{
+       int ret;
+
+       /*
+        * SSIP/SSIU/IRQ/DMA are not needed on
+        * SSI Multi secondaries
+        */
+       if (rsnd_ssi_is_multi_secondary(mod, io))
+               return 0;
+
+       ret = rsnd_ssi_common_probe(mod, io, priv);
+       if (ret)
+               return ret;
+
+       /* SSI probe might be called many times in MUX multi path */
+       ret = rsnd_dma_attach(io, mod, &io->dma);
+
+       return ret;
+}
+
+static int rsnd_ssi_fallback(struct rsnd_mod *mod,
+                            struct rsnd_dai_stream *io,
+                            struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       /*
+        * fallback to PIO
+        *
+        * SSI .probe might be called again.
+        * see
+        *      rsnd_rdai_continuance_probe()
+        */
+       mod->ops = &rsnd_ssi_pio_ops;
+
+       dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod));
+
+       return 0;
+}
+
+static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
+                                        struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       int is_play = rsnd_io_is_play(io);
+       char *name;
+
+       /*
+        * It should use "rcar_sound,ssiu" on DT.
+        * But, we need to keep compatibility for old version.
+        *
+        * If it has "rcar_sound.ssiu", it will be used.
+        * If not, "rcar_sound.ssi" will be used.
+        * see
+        *      rsnd_ssiu_dma_req()
+        *      rsnd_dma_of_path()
+        */
+
+       if (rsnd_ssi_use_busif(io))
+               name = is_play ? "rxu" : "txu";
+       else
+               name = is_play ? "rx" : "tx";
+
+       return rsnd_dma_request_channel(rsnd_ssi_of_node(priv),
+                                       SSI_NAME, mod, name);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_ssi_debug_info(struct seq_file *m,
+                               struct rsnd_dai_stream *io,
+                               struct rsnd_mod *mod)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       seq_printf(m, "clock:           %s\n",          rsnd_rdai_is_clk_master(rdai) ?
+                                                               "provider" : "consumer");
+       seq_printf(m, "bit_clk_inv:     %d\n",          rdai->bit_clk_inv);
+       seq_printf(m, "frm_clk_inv:     %d\n",          rdai->frm_clk_inv);
+       seq_printf(m, "pin share:       %d\n",          __rsnd_ssi_is_pin_sharing(mod));
+       seq_printf(m, "can out clk:     %d\n",          rsnd_ssi_can_output_clk(mod));
+       seq_printf(m, "multi secondary: %d\n",          rsnd_ssi_is_multi_secondary(mod, io));
+       seq_printf(m, "tdm:             %d, %d\n",      rsnd_runtime_is_tdm(io),
+                                                       rsnd_runtime_is_tdm_split(io));
+       seq_printf(m, "chan:            %d\n",          ssi->chan);
+       seq_printf(m, "user:            %d\n",          ssi->usrcnt);
+
+       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSI,
+                                 rsnd_mod_id(mod) * 0x40, 0x40);
+}
+#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
+static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
+       .name           = SSI_NAME,
+       .dma_req        = rsnd_ssi_dma_req,
+       .probe          = rsnd_ssi_dma_probe,
+       .remove         = rsnd_ssi_common_remove,
+       .init           = rsnd_ssi_init,
+       .quit           = rsnd_ssi_quit,
+       .start          = rsnd_ssi_start,
+       .stop           = rsnd_ssi_stop,
+       .irq            = rsnd_ssi_irq,
+       .pcm_new        = rsnd_ssi_pcm_new,
+       .fallback       = rsnd_ssi_fallback,
+       .hw_params      = rsnd_ssi_hw_params,
+       .get_status     = rsnd_ssi_get_status,
+       DEBUG_INFO
+};
+
+int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
+{
+       return mod->ops == &rsnd_ssi_dma_ops;
+}
+
+/*
+ *             ssi mod function
+ */
+static void rsnd_ssi_connect(struct rsnd_mod *mod,
+                            struct rsnd_dai_stream *io)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       static const enum rsnd_mod_type types[] = {
+               RSND_MOD_SSI,
+               RSND_MOD_SSIM1,
+               RSND_MOD_SSIM2,
+               RSND_MOD_SSIM3,
+       };
+       enum rsnd_mod_type type;
+       int i;
+
+       /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */
+       for (i = 0; i < ARRAY_SIZE(types); i++) {
+               type = types[i];
+               if (!rsnd_io_to_mod(io, type)) {
+                       rsnd_dai_connect(mod, io, type);
+                       rsnd_rdai_channels_set(rdai, (i + 1) * 2);
+                       rsnd_rdai_ssi_lane_set(rdai, (i + 1));
+                       return;
+               }
+       }
+}
+
+void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
+                           struct device_node *playback,
+                           struct device_node *capture)
+{
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *node;
+       struct device_node *np;
+       int i;
+
+       node = rsnd_ssi_of_node(priv);
+       if (!node)
+               return;
+
+       i = 0;
+       for_each_child_of_node(node, np) {
+               struct rsnd_mod *mod;
+
+               i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
+               if (i < 0) {
+                       of_node_put(np);
+                       break;
+               }
+
+               mod = rsnd_ssi_mod_get(priv, i);
+
+               if (np == playback)
+                       rsnd_ssi_connect(mod, &rdai->playback);
+               if (np == capture)
+                       rsnd_ssi_connect(mod, &rdai->capture);
+               i++;
+       }
+
+       of_node_put(node);
+}
+
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
+               id = 0;
+
+       return rsnd_mod_get(rsnd_ssi_get(priv, id));
+}
+
+int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
+{
+       if (!mod)
+               return 0;
+
+       return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE));
+}
+
+int rsnd_ssi_probe(struct rsnd_priv *priv)
+{
+       struct device_node *node;
+       struct device_node *np;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mod_ops *ops;
+       struct clk *clk;
+       struct rsnd_ssi *ssi;
+       char name[RSND_SSI_NAME_SIZE];
+       int i, nr, ret;
+
+       node = rsnd_ssi_of_node(priv);
+       if (!node)
+               return -EINVAL;
+
+       nr = rsnd_node_count(priv, node, SSI_NAME);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_ssi_probe_done;
+       }
+
+       ssi     = devm_kcalloc(dev, nr, sizeof(*ssi), GFP_KERNEL);
+       if (!ssi) {
+               ret = -ENOMEM;
+               goto rsnd_ssi_probe_done;
+       }
+
+       priv->ssi       = ssi;
+       priv->ssi_nr    = nr;
+
+       i = 0;
+       for_each_child_of_node(node, np) {
+               if (!of_device_is_available(np))
+                       goto skip;
+
+               i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
+               if (i < 0) {
+                       ret = -EINVAL;
+                       of_node_put(np);
+                       goto rsnd_ssi_probe_done;
+               }
+
+               ssi = rsnd_ssi_get(priv, i);
+
+               snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
+                        SSI_NAME, i);
+
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       of_node_put(np);
+                       goto rsnd_ssi_probe_done;
+               }
+
+               if (of_property_read_bool(np, "shared-pin"))
+                       rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
+
+               if (of_property_read_bool(np, "no-busif"))
+                       rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF);
+
+               ssi->irq = irq_of_parse_and_map(np, 0);
+               if (!ssi->irq) {
+                       ret = -EINVAL;
+                       of_node_put(np);
+                       goto rsnd_ssi_probe_done;
+               }
+
+               if (of_property_read_bool(np, "pio-transfer"))
+                       ops = &rsnd_ssi_pio_ops;
+               else
+                       ops = &rsnd_ssi_dma_ops;
+
+               ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
+                                   RSND_MOD_SSI, i);
+               if (ret) {
+                       of_node_put(np);
+                       goto rsnd_ssi_probe_done;
+               }
+skip:
+               i++;
+       }
+
+       ret = 0;
+
+rsnd_ssi_probe_done:
+       of_node_put(node);
+
+       return ret;
+}
+
+void rsnd_ssi_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi;
+       int i;
+
+       for_each_rsnd_ssi(ssi, priv, i) {
+               rsnd_mod_quit(rsnd_mod_get(ssi));
+       }
+}
diff --git a/sound/soc/renesas/rcar/ssiu.c b/sound/soc/renesas/rcar/ssiu.c
new file mode 100644 (file)
index 0000000..665e8b2
--- /dev/null
@@ -0,0 +1,609 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SSIU support
+//
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+#include "rsnd.h"
+
+#define SSIU_NAME "ssiu"
+
+struct rsnd_ssiu {
+       struct rsnd_mod mod;
+       u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
+       unsigned int usrcnt;
+       int id;
+       int id_sub;
+};
+
+/* SSI_MODE */
+#define TDM_EXT                (1 << 0)
+#define TDM_SPLIT      (1 << 8)
+
+#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
+#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
+#define for_each_rsnd_ssiu(pos, priv, i)                               \
+       for (i = 0;                                                     \
+            (i < rsnd_ssiu_nr(priv)) &&                                \
+                    ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));  \
+            i++)
+
+/*
+ *     SSI     Gen2            Gen3            Gen4
+ *     0       BUSIF0-3        BUSIF0-7        BUSIF0-7
+ *     1       BUSIF0-3        BUSIF0-7
+ *     2       BUSIF0-3        BUSIF0-7
+ *     3       BUSIF0          BUSIF0-7
+ *     4       BUSIF0          BUSIF0-7
+ *     5       BUSIF0          BUSIF0
+ *     6       BUSIF0          BUSIF0
+ *     7       BUSIF0          BUSIF0
+ *     8       BUSIF0          BUSIF0
+ *     9       BUSIF0-3        BUSIF0-7
+ *     total   22              52              8
+ */
+static const int gen2_id[] = { 0, 4,  8, 12, 13, 14, 15, 16, 17, 18 };
+static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
+static const int gen4_id[] = { 0 };
+
+/* enable busif buffer over/under run interrupt. */
+#define rsnd_ssiu_busif_err_irq_enable(mod)  rsnd_ssiu_busif_err_irq_ctrl(mod, 1)
+#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0)
+static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
+{
+       int id = rsnd_mod_id(mod);
+       int shift, offset;
+       int i;
+
+       switch (id) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+               shift  = id;
+               offset = 0;
+               break;
+       case 9:
+               shift  = 1;
+               offset = 1;
+               break;
+       default:
+               return;
+       }
+
+       for (i = 0; i < 4; i++) {
+               enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset);
+               u32 val = 0xf << (shift * 4);
+               u32 sys_int_enable = rsnd_mod_read(mod, reg);
+
+               if (enable)
+                       sys_int_enable |= val;
+               else
+                       sys_int_enable &= ~val;
+               rsnd_mod_write(mod, reg, sys_int_enable);
+       }
+}
+
+bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
+{
+       bool error = false;
+       int id = rsnd_mod_id(mod);
+       int shift, offset;
+       int i;
+
+       switch (id) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+               shift  = id;
+               offset = 0;
+               break;
+       case 9:
+               shift  = 1;
+               offset = 1;
+               break;
+       default:
+               goto out;
+       }
+
+       for (i = 0; i < 4; i++) {
+               u32 reg = SSI_SYS_STATUS(i * 2) + offset;
+               u32 status = rsnd_mod_read(mod, reg);
+               u32 val = 0xf << (shift * 4);
+
+               status &= val;
+               if (status) {
+                       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+                       struct device *dev = rsnd_priv_to_dev(priv);
+
+                       rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
+                                             rsnd_mod_name(mod), status);
+                       error = true;
+               }
+               rsnd_mod_write(mod, reg, val);
+       }
+out:
+       return error;
+}
+
+static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
+                                struct rsnd_dai_stream *io,
+                                enum rsnd_mod_type type)
+{
+       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+       int busif = rsnd_mod_id_sub(mod);
+
+       return &ssiu->busif_status[busif];
+}
+
+static int rsnd_ssiu_init(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
+                         struct rsnd_priv *priv)
+{
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+       u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
+       int use_busif = rsnd_ssi_use_busif(io);
+       int id = rsnd_mod_id(mod);
+       int is_clk_master = rsnd_rdai_is_clk_master(rdai);
+       u32 val1, val2;
+
+       /* clear status */
+       rsnd_ssiu_busif_err_status_clear(mod);
+
+       /* Gen4 doesn't have SSI_MODE */
+       if (rsnd_is_gen4(priv))
+               goto ssi_mode_setting_end;
+
+       /*
+        * SSI_MODE0
+        */
+       rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
+
+       /*
+        * SSI_MODE1 / SSI_MODE2
+        *
+        * FIXME
+        * sharing/multi with SSI0 are mainly supported
+        */
+       val1 = rsnd_mod_read(mod, SSI_MODE1);
+       val2 = rsnd_mod_read(mod, SSI_MODE2);
+       if (rsnd_ssi_is_pin_sharing(io)) {
+
+               ssis |= (1 << id);
+
+       } else if (ssis) {
+               /*
+                * Multi SSI
+                *
+                * set synchronized bit here
+                */
+
+               /* SSI4 is synchronized with SSI3 */
+               if (ssis & (1 << 4))
+                       val1 |= (1 << 20);
+               /* SSI012 are synchronized */
+               if (ssis == 0x0006)
+                       val1 |= (1 << 4);
+               /* SSI0129 are synchronized */
+               if (ssis == 0x0206)
+                       val2 |= (1 << 4);
+       }
+
+       /* SSI1 is sharing pin with SSI0 */
+       if (ssis & (1 << 1))
+               val1 |= is_clk_master ? 0x2 : 0x1;
+
+       /* SSI2 is sharing pin with SSI0 */
+       if (ssis & (1 << 2))
+               val1 |= is_clk_master ? 0x2 << 2 :
+                                       0x1 << 2;
+       /* SSI4 is sharing pin with SSI3 */
+       if (ssis & (1 << 4))
+               val1 |= is_clk_master ? 0x2 << 16 :
+                                       0x1 << 16;
+       /* SSI9 is sharing pin with SSI0 */
+       if (ssis & (1 << 9))
+               val2 |= is_clk_master ? 0x2 : 0x1;
+
+       rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
+       rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
+
+ssi_mode_setting_end:
+       /*
+        * Enable busif buffer over/under run interrupt.
+        * It will be handled from ssi.c
+        * see
+        *      __rsnd_ssi_interrupt()
+        */
+       rsnd_ssiu_busif_err_irq_enable(mod);
+
+       return 0;
+}
+
+static int rsnd_ssiu_quit(struct rsnd_mod *mod,
+                         struct rsnd_dai_stream *io,
+                         struct rsnd_priv *priv)
+{
+       /* disable busif buffer over/under run interrupt. */
+       rsnd_ssiu_busif_err_irq_disable(mod);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
+       .name           = SSIU_NAME,
+       .init           = rsnd_ssiu_init,
+       .quit           = rsnd_ssiu_quit,
+       .get_status     = rsnd_ssiu_get_status,
+};
+
+static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
+                              struct rsnd_dai_stream *io,
+                              struct rsnd_priv *priv)
+{
+       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+       u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
+       u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
+       int ret;
+       u32 mode = 0;
+
+       ret = rsnd_ssiu_init(mod, io, priv);
+       if (ret < 0)
+               return ret;
+
+       ssiu->usrcnt++;
+
+       /*
+        * TDM Extend/Split Mode
+        * see
+        *      rsnd_ssi_config_init()
+        */
+       if (rsnd_runtime_is_tdm(io))
+               mode = TDM_EXT;
+       else if (rsnd_runtime_is_tdm_split(io))
+               mode = TDM_SPLIT;
+
+       rsnd_mod_write(mod, SSI_MODE, mode);
+
+       if (rsnd_ssi_use_busif(io)) {
+               int id = rsnd_mod_id(mod);
+               int busif = rsnd_mod_id_sub(mod);
+               enum rsnd_reg adinr_reg, mode_reg, dalign_reg;
+
+               if ((id == 9) && (busif >= 4)) {
+                       adinr_reg = SSI9_BUSIF_ADINR(busif);
+                       mode_reg = SSI9_BUSIF_MODE(busif);
+                       dalign_reg = SSI9_BUSIF_DALIGN(busif);
+               } else {
+                       adinr_reg = SSI_BUSIF_ADINR(busif);
+                       mode_reg = SSI_BUSIF_MODE(busif);
+                       dalign_reg = SSI_BUSIF_DALIGN(busif);
+               }
+
+               rsnd_mod_write(mod, adinr_reg,
+                              rsnd_get_adinr_bit(mod, io) |
+                              (rsnd_io_is_play(io) ?
+                               rsnd_runtime_channel_after_ctu(io) :
+                               rsnd_runtime_channel_original(io)));
+               rsnd_mod_write(mod, mode_reg,
+                              rsnd_get_busif_shift(io, mod) | 1);
+               rsnd_mod_write(mod, dalign_reg,
+                              rsnd_get_dalign(mod, io));
+       }
+
+       if (has_hdmi0 || has_hdmi1) {
+               enum rsnd_mod_type rsnd_ssi_array[] = {
+                       RSND_MOD_SSIM1,
+                       RSND_MOD_SSIM2,
+                       RSND_MOD_SSIM3,
+               };
+               struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+               struct rsnd_mod *pos;
+               u32 val;
+               int i;
+
+               i = rsnd_mod_id(ssi_mod);
+
+               /* output all same SSI as default */
+               val =   i << 16 |
+                       i << 20 |
+                       i << 24 |
+                       i << 28 |
+                       i;
+
+               for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
+                       int shift = (i * 4) + 20;
+
+                       val     = (val & ~(0xF << shift)) |
+                               rsnd_mod_id(pos) << shift;
+               }
+
+               if (has_hdmi0)
+                       rsnd_mod_write(mod, HDMI0_SEL, val);
+               if (has_hdmi1)
+                       rsnd_mod_write(mod, HDMI1_SEL, val);
+       }
+
+       return 0;
+}
+
+static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
+                               struct rsnd_dai_stream *io,
+                               struct rsnd_priv *priv)
+{
+       int busif = rsnd_mod_id_sub(mod);
+
+       if (!rsnd_ssi_use_busif(io))
+               return 0;
+
+       rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
+
+       if (rsnd_ssi_multi_secondaries_runtime(io))
+               rsnd_mod_write(mod, SSI_CONTROL, 0x1);
+
+       return 0;
+}
+
+static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
+                              struct rsnd_dai_stream *io,
+                              struct rsnd_priv *priv)
+{
+       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+       int busif = rsnd_mod_id_sub(mod);
+
+       if (!rsnd_ssi_use_busif(io))
+               return 0;
+
+       rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
+
+       if (--ssiu->usrcnt)
+               return 0;
+
+       if (rsnd_ssi_multi_secondaries_runtime(io))
+               rsnd_mod_write(mod, SSI_CONTROL, 0);
+
+       return 0;
+}
+
+static int rsnd_ssiu_id(struct rsnd_mod *mod)
+{
+       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+
+       /* see rsnd_ssiu_probe() */
+       return ssiu->id;
+}
+
+static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
+{
+       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
+
+       /* see rsnd_ssiu_probe() */
+       return ssiu->id_sub;
+}
+
+static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
+                                         struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       int is_play = rsnd_io_is_play(io);
+       char *name;
+
+       /*
+        * It should use "rcar_sound,ssiu" on DT.
+        * But, we need to keep compatibility for old version.
+        *
+        * If it has "rcar_sound.ssiu", it will be used.
+        * If not, "rcar_sound.ssi" will be used.
+        * see
+        *      rsnd_ssi_dma_req()
+        *      rsnd_dma_of_path()
+        */
+
+       name = is_play ? "rx" : "tx";
+
+       return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
+                                       SSIU_NAME, mod, name);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void rsnd_ssiu_debug_info(struct seq_file *m,
+                                struct rsnd_dai_stream *io,
+                               struct rsnd_mod *mod)
+{
+       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSIU,
+                                 rsnd_mod_id(mod) * 0x80, 0x80);
+}
+#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info
+#else
+#define DEBUG_INFO
+#endif
+
+static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
+       .name           = SSIU_NAME,
+       .dma_req        = rsnd_ssiu_dma_req,
+       .init           = rsnd_ssiu_init_gen2,
+       .quit           = rsnd_ssiu_quit,
+       .start          = rsnd_ssiu_start_gen2,
+       .stop           = rsnd_ssiu_stop_gen2,
+       .get_status     = rsnd_ssiu_get_status,
+       DEBUG_INFO
+};
+
+static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
+               id = 0;
+
+       return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
+}
+
+static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
+                                              struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+       struct rsnd_ssiu *ssiu;
+       int is_dma_mode;
+       int i;
+
+       if (!ssi_mod)
+               return;
+
+       is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod);
+
+       /* select BUSIF0 */
+       for_each_rsnd_ssiu(ssiu, priv, i) {
+               struct rsnd_mod *mod = rsnd_mod_get(ssiu);
+
+               if (is_dma_mode &&
+                   (rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
+                   (rsnd_mod_id_sub(mod) == 0)) {
+                       rsnd_dai_connect(mod, io, mod->type);
+                       return;
+               }
+       }
+}
+
+void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
+                            struct device_node *playback,
+                            struct device_node *capture)
+{
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *node = rsnd_ssiu_of_node(priv);
+       struct rsnd_dai_stream *io_p = &rdai->playback;
+       struct rsnd_dai_stream *io_c = &rdai->capture;
+
+       /* use rcar_sound,ssiu if exist */
+       if (node) {
+               struct device_node *np;
+               int i = 0;
+
+               for_each_child_of_node(node, np) {
+                       struct rsnd_mod *mod;
+
+                       i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i);
+                       if (i < 0) {
+                               of_node_put(np);
+                               break;
+                       }
+
+                       mod = rsnd_ssiu_mod_get(priv, i);
+
+                       if (np == playback)
+                               rsnd_dai_connect(mod, io_p, mod->type);
+                       if (np == capture)
+                               rsnd_dai_connect(mod, io_c, mod->type);
+                       i++;
+               }
+
+               of_node_put(node);
+       }
+
+       /* Keep DT compatibility */
+       if (!rsnd_io_to_mod_ssiu(io_p))
+               rsnd_parse_connect_ssiu_compatible(priv, io_p);
+       if (!rsnd_io_to_mod_ssiu(io_c))
+               rsnd_parse_connect_ssiu_compatible(priv, io_c);
+}
+
+int rsnd_ssiu_probe(struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *node;
+       struct rsnd_ssiu *ssiu;
+       struct rsnd_mod_ops *ops;
+       const int *list = NULL;
+       int i, nr;
+
+       /*
+        * Keep DT compatibility.
+        * if it has "rcar_sound,ssiu", use it.
+        * if not, use "rcar_sound,ssi"
+        * see
+        *      rsnd_ssiu_bufsif_to_id()
+        */
+       node = rsnd_ssiu_of_node(priv);
+       if (node)
+               nr = rsnd_node_count(priv, node, SSIU_NAME);
+       else
+               nr = priv->ssi_nr;
+
+       if (!nr)
+               return -EINVAL;
+
+       ssiu    = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
+       if (!ssiu)
+               return -ENOMEM;
+
+       priv->ssiu      = ssiu;
+       priv->ssiu_nr   = nr;
+
+       if (rsnd_is_gen1(priv))
+               ops = &rsnd_ssiu_ops_gen1;
+       else
+               ops = &rsnd_ssiu_ops_gen2;
+
+       /* Keep compatibility */
+       nr = 0;
+       if ((node) &&
+           (ops == &rsnd_ssiu_ops_gen2)) {
+               ops->id         = rsnd_ssiu_id;
+               ops->id_sub     = rsnd_ssiu_id_sub;
+
+               if (rsnd_is_gen2(priv)) {
+                       list    = gen2_id;
+                       nr      = ARRAY_SIZE(gen2_id);
+               } else if (rsnd_is_gen3(priv)) {
+                       list    = gen3_id;
+                       nr      = ARRAY_SIZE(gen3_id);
+               } else if (rsnd_is_gen4(priv)) {
+                       list    = gen4_id;
+                       nr      = ARRAY_SIZE(gen4_id);
+               } else {
+                       dev_err(dev, "unknown SSIU\n");
+                       return -ENODEV;
+               }
+       }
+
+       for_each_rsnd_ssiu(ssiu, priv, i) {
+               int ret;
+
+               if (node) {
+                       int j;
+
+                       /*
+                        * see
+                        *      rsnd_ssiu_get_id()
+                        *      rsnd_ssiu_get_id_sub()
+                        */
+                       for (j = 0; j < nr; j++) {
+                               if (list[j] > i)
+                                       break;
+                               ssiu->id        = j;
+                               ssiu->id_sub    = i - list[ssiu->id];
+                       }
+               } else {
+                       ssiu->id = i;
+               }
+
+               ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
+                                   ops, NULL, RSND_MOD_SSIU, i);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void rsnd_ssiu_remove(struct rsnd_priv *priv)
+{
+       struct rsnd_ssiu *ssiu;
+       int i;
+
+       for_each_rsnd_ssiu(ssiu, priv, i) {
+               rsnd_mod_quit(rsnd_mod_get(ssiu));
+       }
+}
diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c
new file mode 100644 (file)
index 0000000..6efd017
--- /dev/null
@@ -0,0 +1,1212 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas RZ/G2L ASoC Serial Sound Interface (SSIF-2) Driver
+//
+// Copyright (C) 2021 Renesas Electronics Corp.
+// Copyright (C) 2019 Chris Brandt.
+//
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <sound/soc.h>
+
+/* REGISTER OFFSET */
+#define SSICR                  0x000
+#define SSISR                  0x004
+#define SSIFCR                 0x010
+#define SSIFSR                 0x014
+#define SSIFTDR                        0x018
+#define SSIFRDR                        0x01c
+#define SSIOFR                 0x020
+#define SSISCR                 0x024
+
+/* SSI REGISTER BITS */
+#define SSICR_DWL(x)           (((x) & 0x7) << 19)
+#define SSICR_SWL(x)           (((x) & 0x7) << 16)
+
+#define SSICR_CKS              BIT(30)
+#define SSICR_TUIEN            BIT(29)
+#define SSICR_TOIEN            BIT(28)
+#define SSICR_RUIEN            BIT(27)
+#define SSICR_ROIEN            BIT(26)
+#define SSICR_MST              BIT(14)
+#define SSICR_BCKP             BIT(13)
+#define SSICR_LRCKP            BIT(12)
+#define SSICR_CKDV(x)          (((x) & 0xf) << 4)
+#define SSICR_TEN              BIT(1)
+#define SSICR_REN              BIT(0)
+
+#define SSISR_TUIRQ            BIT(29)
+#define SSISR_TOIRQ            BIT(28)
+#define SSISR_RUIRQ            BIT(27)
+#define SSISR_ROIRQ            BIT(26)
+#define SSISR_IIRQ             BIT(25)
+
+#define SSIFCR_AUCKE           BIT(31)
+#define SSIFCR_SSIRST          BIT(16)
+#define SSIFCR_TIE             BIT(3)
+#define SSIFCR_RIE             BIT(2)
+#define SSIFCR_TFRST           BIT(1)
+#define SSIFCR_RFRST           BIT(0)
+#define SSIFCR_FIFO_RST                (SSIFCR_TFRST | SSIFCR_RFRST)
+
+#define SSIFSR_TDC_MASK                0x3f
+#define SSIFSR_TDC_SHIFT       24
+#define SSIFSR_RDC_MASK                0x3f
+#define SSIFSR_RDC_SHIFT       8
+
+#define SSIFSR_TDE             BIT(16)
+#define SSIFSR_RDF             BIT(0)
+
+#define SSIOFR_LRCONT          BIT(8)
+
+#define SSISCR_TDES(x)         (((x) & 0x1f) << 8)
+#define SSISCR_RDFS(x)         (((x) & 0x1f) << 0)
+
+/* Pre allocated buffers sizes */
+#define PREALLOC_BUFFER                (SZ_32K)
+#define PREALLOC_BUFFER_MAX    (SZ_32K)
+
+#define SSI_RATES              SNDRV_PCM_RATE_8000_48000 /* 8k-44.1kHz */
+#define SSI_FMTS               SNDRV_PCM_FMTBIT_S16_LE
+#define SSI_CHAN_MIN           2
+#define SSI_CHAN_MAX           2
+#define SSI_FIFO_DEPTH         32
+
+struct rz_ssi_priv;
+
+struct rz_ssi_stream {
+       struct rz_ssi_priv *priv;
+       struct snd_pcm_substream *substream;
+       int fifo_sample_size;   /* sample capacity of SSI FIFO */
+       int dma_buffer_pos;     /* The address for the next DMA descriptor */
+       int period_counter;     /* for keeping track of periods transferred */
+       int sample_width;
+       int buffer_pos;         /* current frame position in the buffer */
+       int running;            /* 0=stopped, 1=running */
+
+       int uerr_num;
+       int oerr_num;
+
+       struct dma_chan *dma_ch;
+
+       int (*transfer)(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm);
+};
+
+struct rz_ssi_priv {
+       void __iomem *base;
+       struct platform_device *pdev;
+       struct reset_control *rstc;
+       struct device *dev;
+       struct clk *sfr_clk;
+       struct clk *clk;
+
+       phys_addr_t phys;
+       int irq_int;
+       int irq_tx;
+       int irq_rx;
+       int irq_rt;
+
+       spinlock_t lock;
+
+       /*
+        * The SSI supports full-duplex transmission and reception.
+        * However, if an error occurs, channel reset (both transmission
+        * and reception reset) is required.
+        * So it is better to use as half-duplex (playing and recording
+        * should be done on separate channels).
+        */
+       struct rz_ssi_stream playback;
+       struct rz_ssi_stream capture;
+
+       /* clock */
+       unsigned long audio_mck;
+       unsigned long audio_clk_1;
+       unsigned long audio_clk_2;
+
+       bool lrckp_fsync_fall;  /* LR clock polarity (SSICR.LRCKP) */
+       bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */
+       bool dma_rt;
+
+       /* Full duplex communication support */
+       struct {
+               unsigned int rate;
+               unsigned int channels;
+               unsigned int sample_width;
+               unsigned int sample_bits;
+       } hw_params_cache;
+};
+
+static void rz_ssi_dma_complete(void *data);
+
+static void rz_ssi_reg_writel(struct rz_ssi_priv *priv, uint reg, u32 data)
+{
+       writel(data, (priv->base + reg));
+}
+
+static u32 rz_ssi_reg_readl(struct rz_ssi_priv *priv, uint reg)
+{
+       return readl(priv->base + reg);
+}
+
+static void rz_ssi_reg_mask_setl(struct rz_ssi_priv *priv, uint reg,
+                                u32 bclr, u32 bset)
+{
+       u32 val;
+
+       val = readl(priv->base + reg);
+       val = (val & ~bclr) | bset;
+       writel(val, (priv->base + reg));
+}
+
+static inline struct snd_soc_dai *
+rz_ssi_get_dai(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+
+       return snd_soc_rtd_to_cpu(rtd, 0);
+}
+
+static inline bool rz_ssi_stream_is_play(struct rz_ssi_priv *ssi,
+                                        struct snd_pcm_substream *substream)
+{
+       return substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+}
+
+static inline struct rz_ssi_stream *
+rz_ssi_stream_get(struct rz_ssi_priv *ssi, struct snd_pcm_substream *substream)
+{
+       struct rz_ssi_stream *stream = &ssi->playback;
+
+       if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+               stream = &ssi->capture;
+
+       return stream;
+}
+
+static inline bool rz_ssi_is_dma_enabled(struct rz_ssi_priv *ssi)
+{
+       return (ssi->playback.dma_ch && (ssi->dma_rt || ssi->capture.dma_ch));
+}
+
+static void rz_ssi_set_substream(struct rz_ssi_stream *strm,
+                                struct snd_pcm_substream *substream)
+{
+       struct rz_ssi_priv *ssi = strm->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ssi->lock, flags);
+       strm->substream = substream;
+       spin_unlock_irqrestore(&ssi->lock, flags);
+}
+
+static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi,
+                                  struct rz_ssi_stream *strm)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&ssi->lock, flags);
+       ret = strm->substream && strm->substream->runtime;
+       spin_unlock_irqrestore(&ssi->lock, flags);
+
+       return ret;
+}
+
+static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm)
+{
+       return strm->substream && strm->running;
+}
+
+static void rz_ssi_stream_init(struct rz_ssi_stream *strm,
+                              struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       rz_ssi_set_substream(strm, substream);
+       strm->sample_width = samples_to_bytes(runtime, 1);
+       strm->dma_buffer_pos = 0;
+       strm->period_counter = 0;
+       strm->buffer_pos = 0;
+
+       strm->oerr_num = 0;
+       strm->uerr_num = 0;
+       strm->running = 0;
+
+       /* fifo init */
+       strm->fifo_sample_size = SSI_FIFO_DEPTH;
+}
+
+static void rz_ssi_stream_quit(struct rz_ssi_priv *ssi,
+                              struct rz_ssi_stream *strm)
+{
+       struct snd_soc_dai *dai = rz_ssi_get_dai(strm->substream);
+
+       rz_ssi_set_substream(strm, NULL);
+
+       if (strm->oerr_num > 0)
+               dev_info(dai->dev, "overrun = %d\n", strm->oerr_num);
+
+       if (strm->uerr_num > 0)
+               dev_info(dai->dev, "underrun = %d\n", strm->uerr_num);
+}
+
+static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate,
+                           unsigned int channels)
+{
+       static s8 ckdv[16] = { 1,  2,  4,  8, 16, 32, 64, 128,
+                              6, 12, 24, 48, 96, -1, -1, -1 };
+       unsigned int channel_bits = 32; /* System Word Length */
+       unsigned long bclk_rate = rate * channels * channel_bits;
+       unsigned int div;
+       unsigned int i;
+       u32 ssicr = 0;
+       u32 clk_ckdv;
+
+       /* Clear AUCKE so we can set MST */
+       rz_ssi_reg_writel(ssi, SSIFCR, 0);
+
+       /* Continue to output LRCK pin even when idle */
+       rz_ssi_reg_writel(ssi, SSIOFR, SSIOFR_LRCONT);
+       if (ssi->audio_clk_1 && ssi->audio_clk_2) {
+               if (ssi->audio_clk_1 % bclk_rate)
+                       ssi->audio_mck = ssi->audio_clk_2;
+               else
+                       ssi->audio_mck = ssi->audio_clk_1;
+       }
+
+       /* Clock setting */
+       ssicr |= SSICR_MST;
+       if (ssi->audio_mck == ssi->audio_clk_1)
+               ssicr |= SSICR_CKS;
+       if (ssi->bckp_rise)
+               ssicr |= SSICR_BCKP;
+       if (ssi->lrckp_fsync_fall)
+               ssicr |= SSICR_LRCKP;
+
+       /* Determine the clock divider */
+       clk_ckdv = 0;
+       div = ssi->audio_mck / bclk_rate;
+       /* try to find an match */
+       for (i = 0; i < ARRAY_SIZE(ckdv); i++) {
+               if (ckdv[i] == div) {
+                       clk_ckdv = i;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(ckdv)) {
+               dev_err(ssi->dev, "Rate not divisible by audio clock source\n");
+               return -EINVAL;
+       }
+
+       /*
+        * DWL: Data Word Length = 16 bits
+        * SWL: System Word Length = 32 bits
+        */
+       ssicr |= SSICR_CKDV(clk_ckdv);
+       ssicr |= SSICR_DWL(1) | SSICR_SWL(3);
+       rz_ssi_reg_writel(ssi, SSICR, ssicr);
+       rz_ssi_reg_writel(ssi, SSIFCR, SSIFCR_AUCKE | SSIFCR_FIFO_RST);
+
+       return 0;
+}
+
+static void rz_ssi_set_idle(struct rz_ssi_priv *ssi)
+{
+       int timeout;
+
+       /* Disable irqs */
+       rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN |
+                            SSICR_RUIEN | SSICR_ROIEN, 0);
+       rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0);
+
+       /* Clear all error flags */
+       rz_ssi_reg_mask_setl(ssi, SSISR,
+                            (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ |
+                             SSISR_RUIRQ), 0);
+
+       /* Wait for idle */
+       timeout = 100;
+       while (--timeout) {
+               if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ)
+                       break;
+               udelay(1);
+       }
+
+       if (!timeout)
+               dev_info(ssi->dev, "timeout waiting for SSI idle\n");
+
+       /* Hold FIFOs in reset */
+       rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_FIFO_RST);
+}
+
+static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
+{
+       bool is_play = rz_ssi_stream_is_play(ssi, strm->substream);
+       bool is_full_duplex;
+       u32 ssicr, ssifcr;
+
+       is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) ||
+               rz_ssi_is_stream_running(&ssi->capture);
+       ssicr = rz_ssi_reg_readl(ssi, SSICR);
+       ssifcr = rz_ssi_reg_readl(ssi, SSIFCR);
+       if (!is_full_duplex) {
+               ssifcr &= ~0xF;
+       } else {
+               rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
+               rz_ssi_set_idle(ssi);
+               ssifcr &= ~SSIFCR_FIFO_RST;
+       }
+
+       /* FIFO interrupt thresholds */
+       if (rz_ssi_is_dma_enabled(ssi))
+               rz_ssi_reg_writel(ssi, SSISCR, 0);
+       else
+               rz_ssi_reg_writel(ssi, SSISCR,
+                                 SSISCR_TDES(strm->fifo_sample_size / 2 - 1) |
+                                 SSISCR_RDFS(0));
+
+       /* enable IRQ */
+       if (is_play) {
+               ssicr |= SSICR_TUIEN | SSICR_TOIEN;
+               ssifcr |= SSIFCR_TIE;
+               if (!is_full_duplex)
+                       ssifcr |= SSIFCR_RFRST;
+       } else {
+               ssicr |= SSICR_RUIEN | SSICR_ROIEN;
+               ssifcr |= SSIFCR_RIE;
+               if (!is_full_duplex)
+                       ssifcr |= SSIFCR_TFRST;
+       }
+
+       rz_ssi_reg_writel(ssi, SSICR, ssicr);
+       rz_ssi_reg_writel(ssi, SSIFCR, ssifcr);
+
+       /* Clear all error flags */
+       rz_ssi_reg_mask_setl(ssi, SSISR,
+                            (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ |
+                             SSISR_RUIRQ), 0);
+
+       strm->running = 1;
+       if (is_full_duplex)
+               ssicr |= SSICR_TEN | SSICR_REN;
+       else
+               ssicr |= is_play ? SSICR_TEN : SSICR_REN;
+
+       rz_ssi_reg_writel(ssi, SSICR, ssicr);
+
+       return 0;
+}
+
+static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
+{
+       strm->running = 0;
+
+       if (rz_ssi_is_stream_running(&ssi->playback) ||
+           rz_ssi_is_stream_running(&ssi->capture))
+               return 0;
+
+       /* Disable TX/RX */
+       rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
+
+       /* Cancel all remaining DMA transactions */
+       if (rz_ssi_is_dma_enabled(ssi))
+               dmaengine_terminate_async(strm->dma_ch);
+
+       rz_ssi_set_idle(ssi);
+
+       return 0;
+}
+
+static void rz_ssi_pointer_update(struct rz_ssi_stream *strm, int frames)
+{
+       struct snd_pcm_substream *substream = strm->substream;
+       struct snd_pcm_runtime *runtime;
+       int current_period;
+
+       if (!strm->running || !substream || !substream->runtime)
+               return;
+
+       runtime = substream->runtime;
+       strm->buffer_pos += frames;
+       WARN_ON(strm->buffer_pos > runtime->buffer_size);
+
+       /* ring buffer */
+       if (strm->buffer_pos == runtime->buffer_size)
+               strm->buffer_pos = 0;
+
+       current_period = strm->buffer_pos / runtime->period_size;
+       if (strm->period_counter != current_period) {
+               snd_pcm_period_elapsed(strm->substream);
+               strm->period_counter = current_period;
+       }
+}
+
+static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
+{
+       struct snd_pcm_substream *substream = strm->substream;
+       struct snd_pcm_runtime *runtime;
+       u16 *buf;
+       int fifo_samples;
+       int frames_left;
+       int samples;
+       int i;
+
+       if (!rz_ssi_stream_is_valid(ssi, strm))
+               return -EINVAL;
+
+       runtime = substream->runtime;
+
+       do {
+               /* frames left in this period */
+               frames_left = runtime->period_size -
+                             (strm->buffer_pos % runtime->period_size);
+               if (!frames_left)
+                       frames_left = runtime->period_size;
+
+               /* Samples in RX FIFO */
+               fifo_samples = (rz_ssi_reg_readl(ssi, SSIFSR) >>
+                               SSIFSR_RDC_SHIFT) & SSIFSR_RDC_MASK;
+
+               /* Only read full frames at a time */
+               samples = 0;
+               while (frames_left && (fifo_samples >= runtime->channels)) {
+                       samples += runtime->channels;
+                       fifo_samples -= runtime->channels;
+                       frames_left--;
+               }
+
+               /* not enough samples yet */
+               if (!samples)
+                       break;
+
+               /* calculate new buffer index */
+               buf = (u16 *)runtime->dma_area;
+               buf += strm->buffer_pos * runtime->channels;
+
+               /* Note, only supports 16-bit samples */
+               for (i = 0; i < samples; i++)
+                       *buf++ = (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16);
+
+               rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
+               rz_ssi_pointer_update(strm, samples / runtime->channels);
+       } while (!frames_left && fifo_samples >= runtime->channels);
+
+       return 0;
+}
+
+static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
+{
+       struct snd_pcm_substream *substream = strm->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int sample_space;
+       int samples = 0;
+       int frames_left;
+       int i;
+       u32 ssifsr;
+       u16 *buf;
+
+       if (!rz_ssi_stream_is_valid(ssi, strm))
+               return -EINVAL;
+
+       /* frames left in this period */
+       frames_left = runtime->period_size - (strm->buffer_pos %
+                                             runtime->period_size);
+       if (frames_left == 0)
+               frames_left = runtime->period_size;
+
+       sample_space = strm->fifo_sample_size;
+       ssifsr = rz_ssi_reg_readl(ssi, SSIFSR);
+       sample_space -= (ssifsr >> SSIFSR_TDC_SHIFT) & SSIFSR_TDC_MASK;
+
+       /* Only add full frames at a time */
+       while (frames_left && (sample_space >= runtime->channels)) {
+               samples += runtime->channels;
+               sample_space -= runtime->channels;
+               frames_left--;
+       }
+
+       /* no space to send anything right now */
+       if (samples == 0)
+               return 0;
+
+       /* calculate new buffer index */
+       buf = (u16 *)(runtime->dma_area);
+       buf += strm->buffer_pos * runtime->channels;
+
+       /* Note, only supports 16-bit samples */
+       for (i = 0; i < samples; i++)
+               rz_ssi_reg_writel(ssi, SSIFTDR, ((u32)(*buf++) << 16));
+
+       rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_TDE, 0);
+       rz_ssi_pointer_update(strm, samples / runtime->channels);
+
+       return 0;
+}
+
+static irqreturn_t rz_ssi_interrupt(int irq, void *data)
+{
+       struct rz_ssi_stream *strm_playback = NULL;
+       struct rz_ssi_stream *strm_capture = NULL;
+       struct rz_ssi_priv *ssi = data;
+       u32 ssisr = rz_ssi_reg_readl(ssi, SSISR);
+
+       if (ssi->playback.substream)
+               strm_playback = &ssi->playback;
+       if (ssi->capture.substream)
+               strm_capture = &ssi->capture;
+
+       if (!strm_playback && !strm_capture)
+               return IRQ_HANDLED; /* Left over TX/RX interrupt */
+
+       if (irq == ssi->irq_int) { /* error or idle */
+               bool is_stopped = false;
+               int i, count;
+
+               if (rz_ssi_is_dma_enabled(ssi))
+                       count = 4;
+               else
+                       count = 1;
+
+               if (ssisr & (SSISR_RUIRQ | SSISR_ROIRQ | SSISR_TUIRQ | SSISR_TOIRQ))
+                       is_stopped = true;
+
+               if (ssi->capture.substream && is_stopped) {
+                       if (ssisr & SSISR_RUIRQ)
+                               strm_capture->uerr_num++;
+                       if (ssisr & SSISR_ROIRQ)
+                               strm_capture->oerr_num++;
+
+                       rz_ssi_stop(ssi, strm_capture);
+               }
+
+               if (ssi->playback.substream && is_stopped) {
+                       if (ssisr & SSISR_TUIRQ)
+                               strm_playback->uerr_num++;
+                       if (ssisr & SSISR_TOIRQ)
+                               strm_playback->oerr_num++;
+
+                       rz_ssi_stop(ssi, strm_playback);
+               }
+
+               /* Clear all flags */
+               rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | SSISR_TUIRQ |
+                                    SSISR_ROIRQ | SSISR_RUIRQ, 0);
+
+               /* Add/remove more data */
+               if (ssi->capture.substream && is_stopped) {
+                       for (i = 0; i < count; i++)
+                               strm_capture->transfer(ssi, strm_capture);
+               }
+
+               if (ssi->playback.substream && is_stopped) {
+                       for (i = 0; i < count; i++)
+                               strm_playback->transfer(ssi, strm_playback);
+               }
+
+               /* Resume */
+               if (ssi->playback.substream && is_stopped)
+                       rz_ssi_start(ssi, &ssi->playback);
+               if (ssi->capture.substream && is_stopped)
+                       rz_ssi_start(ssi, &ssi->capture);
+       }
+
+       if (!rz_ssi_is_stream_running(&ssi->playback) &&
+           !rz_ssi_is_stream_running(&ssi->capture))
+               return IRQ_HANDLED;
+
+       /* tx data empty */
+       if (irq == ssi->irq_tx && rz_ssi_is_stream_running(&ssi->playback))
+               strm_playback->transfer(ssi, &ssi->playback);
+
+       /* rx data full */
+       if (irq == ssi->irq_rx && rz_ssi_is_stream_running(&ssi->capture)) {
+               strm_capture->transfer(ssi, &ssi->capture);
+               rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
+       }
+
+       if (irq == ssi->irq_rt) {
+               if (ssi->playback.substream) {
+                       strm_playback->transfer(ssi, &ssi->playback);
+               } else {
+                       strm_capture->transfer(ssi, &ssi->capture);
+                       rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int rz_ssi_dma_slave_config(struct rz_ssi_priv *ssi,
+                                  struct dma_chan *dma_ch, bool is_play)
+{
+       struct dma_slave_config cfg;
+
+       memset(&cfg, 0, sizeof(cfg));
+
+       cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+       cfg.dst_addr = ssi->phys + SSIFTDR;
+       cfg.src_addr = ssi->phys + SSIFRDR;
+       cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+       cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+       return dmaengine_slave_config(dma_ch, &cfg);
+}
+
+static int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi,
+                              struct rz_ssi_stream *strm)
+{
+       struct snd_pcm_substream *substream = strm->substream;
+       struct dma_async_tx_descriptor *desc;
+       struct snd_pcm_runtime *runtime;
+       enum dma_transfer_direction dir;
+       u32 dma_paddr, dma_size;
+       int amount;
+
+       if (!rz_ssi_stream_is_valid(ssi, strm))
+               return -EINVAL;
+
+       runtime = substream->runtime;
+       if (runtime->state == SNDRV_PCM_STATE_DRAINING)
+               /*
+                * Stream is ending, so do not queue up any more DMA
+                * transfers otherwise we play partial sound clips
+                * because we can't shut off the DMA quick enough.
+                */
+               return 0;
+
+       dir = rz_ssi_stream_is_play(ssi, substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+
+       /* Always transfer 1 period */
+       amount = runtime->period_size;
+
+       /* DMA physical address and size */
+       dma_paddr = runtime->dma_addr + frames_to_bytes(runtime,
+                                                       strm->dma_buffer_pos);
+       dma_size = frames_to_bytes(runtime, amount);
+       desc = dmaengine_prep_slave_single(strm->dma_ch, dma_paddr, dma_size,
+                                          dir,
+                                          DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_err(ssi->dev, "dmaengine_prep_slave_single() fail\n");
+               return -ENOMEM;
+       }
+
+       desc->callback = rz_ssi_dma_complete;
+       desc->callback_param = strm;
+
+       if (dmaengine_submit(desc) < 0) {
+               dev_err(ssi->dev, "dmaengine_submit() fail\n");
+               return -EIO;
+       }
+
+       /* Update DMA pointer */
+       strm->dma_buffer_pos += amount;
+       if (strm->dma_buffer_pos >= runtime->buffer_size)
+               strm->dma_buffer_pos = 0;
+
+       /* Start DMA */
+       dma_async_issue_pending(strm->dma_ch);
+
+       return 0;
+}
+
+static void rz_ssi_dma_complete(void *data)
+{
+       struct rz_ssi_stream *strm = (struct rz_ssi_stream *)data;
+
+       if (!strm->running || !strm->substream || !strm->substream->runtime)
+               return;
+
+       /* Note that next DMA transaction has probably already started */
+       rz_ssi_pointer_update(strm, strm->substream->runtime->period_size);
+
+       /* Queue up another DMA transaction */
+       rz_ssi_dma_transfer(strm->priv, strm);
+}
+
+static void rz_ssi_release_dma_channels(struct rz_ssi_priv *ssi)
+{
+       if (ssi->playback.dma_ch) {
+               dma_release_channel(ssi->playback.dma_ch);
+               ssi->playback.dma_ch = NULL;
+               if (ssi->dma_rt)
+                       ssi->dma_rt = false;
+       }
+
+       if (ssi->capture.dma_ch) {
+               dma_release_channel(ssi->capture.dma_ch);
+               ssi->capture.dma_ch = NULL;
+       }
+}
+
+static int rz_ssi_dma_request(struct rz_ssi_priv *ssi, struct device *dev)
+{
+       ssi->playback.dma_ch = dma_request_chan(dev, "tx");
+       if (IS_ERR(ssi->playback.dma_ch))
+               ssi->playback.dma_ch = NULL;
+
+       ssi->capture.dma_ch = dma_request_chan(dev, "rx");
+       if (IS_ERR(ssi->capture.dma_ch))
+               ssi->capture.dma_ch = NULL;
+
+       if (!ssi->playback.dma_ch && !ssi->capture.dma_ch) {
+               ssi->playback.dma_ch = dma_request_chan(dev, "rt");
+               if (IS_ERR(ssi->playback.dma_ch)) {
+                       ssi->playback.dma_ch = NULL;
+                       goto no_dma;
+               }
+
+               ssi->dma_rt = true;
+       }
+
+       if (!rz_ssi_is_dma_enabled(ssi))
+               goto no_dma;
+
+       if (ssi->playback.dma_ch &&
+           (rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, true) < 0))
+               goto no_dma;
+
+       if (ssi->capture.dma_ch &&
+           (rz_ssi_dma_slave_config(ssi, ssi->capture.dma_ch, false) < 0))
+               goto no_dma;
+
+       return 0;
+
+no_dma:
+       rz_ssi_release_dma_channels(ssi);
+
+       return -ENODEV;
+}
+
+static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                             struct snd_soc_dai *dai)
+{
+       struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
+       struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream);
+       int ret = 0, i, num_transfer = 1;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* Soft Reset */
+               if (!rz_ssi_is_stream_running(&ssi->playback) &&
+                   !rz_ssi_is_stream_running(&ssi->capture)) {
+                       rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST);
+                       rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0);
+                       udelay(5);
+               }
+
+               rz_ssi_stream_init(strm, substream);
+
+               if (ssi->dma_rt) {
+                       bool is_playback;
+
+                       is_playback = rz_ssi_stream_is_play(ssi, substream);
+                       ret = rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch,
+                                                     is_playback);
+                       /* Fallback to pio */
+                       if (ret < 0) {
+                               ssi->playback.transfer = rz_ssi_pio_send;
+                               ssi->capture.transfer = rz_ssi_pio_recv;
+                               rz_ssi_release_dma_channels(ssi);
+                       }
+               }
+
+               /* For DMA, queue up multiple DMA descriptors */
+               if (rz_ssi_is_dma_enabled(ssi))
+                       num_transfer = 4;
+
+               for (i = 0; i < num_transfer; i++) {
+                       ret = strm->transfer(ssi, strm);
+                       if (ret)
+                               goto done;
+               }
+
+               ret = rz_ssi_start(ssi, strm);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               rz_ssi_stop(ssi, strm);
+               rz_ssi_stream_quit(ssi, strm);
+               break;
+       }
+
+done:
+       return ret;
+}
+
+static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
+               break;
+       default:
+               dev_err(ssi->dev, "Codec should be clk and frame consumer\n");
+               return -EINVAL;
+       }
+
+       /*
+        * set clock polarity
+        *
+        * "normal" BCLK = Signal is available at rising edge of BCLK
+        * "normal" FSYNC = (I2S) Left ch starts with falling FSYNC edge
+        */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               ssi->bckp_rise = false;
+               ssi->lrckp_fsync_fall = false;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               ssi->bckp_rise = false;
+               ssi->lrckp_fsync_fall = true;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               ssi->bckp_rise = true;
+               ssi->lrckp_fsync_fall = false;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               ssi->bckp_rise = true;
+               ssi->lrckp_fsync_fall = true;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* only i2s support */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       default:
+               dev_err(ssi->dev, "Only I2S mode is supported.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate,
+                                     unsigned int channels,
+                                     unsigned int sample_width,
+                                     unsigned int sample_bits)
+{
+       if (ssi->hw_params_cache.rate != rate ||
+           ssi->hw_params_cache.channels != channels ||
+           ssi->hw_params_cache.sample_width != sample_width ||
+           ssi->hw_params_cache.sample_bits != sample_bits)
+               return false;
+
+       return true;
+}
+
+static void rz_ssi_cache_hw_params(struct rz_ssi_priv *ssi, unsigned int rate,
+                                  unsigned int channels,
+                                  unsigned int sample_width,
+                                  unsigned int sample_bits)
+{
+       ssi->hw_params_cache.rate = rate;
+       ssi->hw_params_cache.channels = channels;
+       ssi->hw_params_cache.sample_width = sample_width;
+       ssi->hw_params_cache.sample_bits = sample_bits;
+}
+
+static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
+       struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream);
+       unsigned int sample_bits = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+       unsigned int channels = params_channels(params);
+       unsigned int rate = params_rate(params);
+
+       if (sample_bits != 16) {
+               dev_err(ssi->dev, "Unsupported sample width: %d\n",
+                       sample_bits);
+               return -EINVAL;
+       }
+
+       if (channels != 2) {
+               dev_err(ssi->dev, "Number of channels not matched: %d\n",
+                       channels);
+               return -EINVAL;
+       }
+
+       if (rz_ssi_is_stream_running(&ssi->playback) ||
+           rz_ssi_is_stream_running(&ssi->capture)) {
+               if (rz_ssi_is_valid_hw_params(ssi, rate, channels,
+                                             strm->sample_width, sample_bits))
+                       return 0;
+
+               dev_err(ssi->dev, "Full duplex needs same HW params\n");
+               return -EINVAL;
+       }
+
+       rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width,
+                              sample_bits);
+
+       return rz_ssi_clk_setup(ssi, rate, channels);
+}
+
+static const struct snd_soc_dai_ops rz_ssi_dai_ops = {
+       .trigger        = rz_ssi_dai_trigger,
+       .set_fmt        = rz_ssi_dai_set_fmt,
+       .hw_params      = rz_ssi_dai_hw_params,
+};
+
+static const struct snd_pcm_hardware rz_ssi_pcm_hardware = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED    |
+                                 SNDRV_PCM_INFO_MMAP           |
+                                 SNDRV_PCM_INFO_MMAP_VALID,
+       .buffer_bytes_max       = PREALLOC_BUFFER,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8192,
+       .channels_min           = SSI_CHAN_MIN,
+       .channels_max           = SSI_CHAN_MAX,
+       .periods_min            = 1,
+       .periods_max            = 32,
+       .fifo_size              = 32 * 2,
+};
+
+static int rz_ssi_pcm_open(struct snd_soc_component *component,
+                          struct snd_pcm_substream *substream)
+{
+       snd_soc_set_runtime_hwparams(substream, &rz_ssi_pcm_hardware);
+
+       return snd_pcm_hw_constraint_integer(substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+}
+
+static snd_pcm_uframes_t rz_ssi_pcm_pointer(struct snd_soc_component *component,
+                                           struct snd_pcm_substream *substream)
+{
+       struct snd_soc_dai *dai = rz_ssi_get_dai(substream);
+       struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
+       struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream);
+
+       return strm->buffer_pos;
+}
+
+static int rz_ssi_pcm_new(struct snd_soc_component *component,
+                         struct snd_soc_pcm_runtime *rtd)
+{
+       snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
+                                      rtd->card->snd_card->dev,
+                                      PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+       return 0;
+}
+
+static struct snd_soc_dai_driver rz_ssi_soc_dai[] = {
+       {
+               .name                   = "rz-ssi-dai",
+               .playback = {
+                       .rates          = SSI_RATES,
+                       .formats        = SSI_FMTS,
+                       .channels_min   = SSI_CHAN_MIN,
+                       .channels_max   = SSI_CHAN_MAX,
+               },
+               .capture = {
+                       .rates          = SSI_RATES,
+                       .formats        = SSI_FMTS,
+                       .channels_min   = SSI_CHAN_MIN,
+                       .channels_max   = SSI_CHAN_MAX,
+               },
+               .ops = &rz_ssi_dai_ops,
+       },
+};
+
+static const struct snd_soc_component_driver rz_ssi_soc_component = {
+       .name                   = "rz-ssi",
+       .open                   = rz_ssi_pcm_open,
+       .pointer                = rz_ssi_pcm_pointer,
+       .pcm_construct          = rz_ssi_pcm_new,
+       .legacy_dai_naming      = 1,
+};
+
+static int rz_ssi_probe(struct platform_device *pdev)
+{
+       struct rz_ssi_priv *ssi;
+       struct clk *audio_clk;
+       struct resource *res;
+       int ret;
+
+       ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
+       if (!ssi)
+               return -ENOMEM;
+
+       ssi->pdev = pdev;
+       ssi->dev = &pdev->dev;
+       ssi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+       if (IS_ERR(ssi->base))
+               return PTR_ERR(ssi->base);
+
+       ssi->phys = res->start;
+       ssi->clk = devm_clk_get(&pdev->dev, "ssi");
+       if (IS_ERR(ssi->clk))
+               return PTR_ERR(ssi->clk);
+
+       ssi->sfr_clk = devm_clk_get(&pdev->dev, "ssi_sfr");
+       if (IS_ERR(ssi->sfr_clk))
+               return PTR_ERR(ssi->sfr_clk);
+
+       audio_clk = devm_clk_get(&pdev->dev, "audio_clk1");
+       if (IS_ERR(audio_clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk),
+                                    "no audio clk1");
+
+       ssi->audio_clk_1 = clk_get_rate(audio_clk);
+       audio_clk = devm_clk_get(&pdev->dev, "audio_clk2");
+       if (IS_ERR(audio_clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk),
+                                    "no audio clk2");
+
+       ssi->audio_clk_2 = clk_get_rate(audio_clk);
+       if (!(ssi->audio_clk_1 || ssi->audio_clk_2))
+               return dev_err_probe(&pdev->dev, -EINVAL,
+                                    "no audio clk1 or audio clk2");
+
+       ssi->audio_mck = ssi->audio_clk_1 ? ssi->audio_clk_1 : ssi->audio_clk_2;
+
+       /* Detect DMA support */
+       ret = rz_ssi_dma_request(ssi, &pdev->dev);
+       if (ret < 0) {
+               dev_warn(&pdev->dev, "DMA not available, using PIO\n");
+               ssi->playback.transfer = rz_ssi_pio_send;
+               ssi->capture.transfer = rz_ssi_pio_recv;
+       } else {
+               dev_info(&pdev->dev, "DMA enabled");
+               ssi->playback.transfer = rz_ssi_dma_transfer;
+               ssi->capture.transfer = rz_ssi_dma_transfer;
+       }
+
+       ssi->playback.priv = ssi;
+       ssi->capture.priv = ssi;
+
+       spin_lock_init(&ssi->lock);
+       dev_set_drvdata(&pdev->dev, ssi);
+
+       /* Error Interrupt */
+       ssi->irq_int = platform_get_irq_byname(pdev, "int_req");
+       if (ssi->irq_int < 0) {
+               rz_ssi_release_dma_channels(ssi);
+               return ssi->irq_int;
+       }
+
+       ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt,
+                              0, dev_name(&pdev->dev), ssi);
+       if (ret < 0) {
+               rz_ssi_release_dma_channels(ssi);
+               return dev_err_probe(&pdev->dev, ret,
+                                    "irq request error (int_req)\n");
+       }
+
+       if (!rz_ssi_is_dma_enabled(ssi)) {
+               /* Tx and Rx interrupts (pio only) */
+               ssi->irq_tx = platform_get_irq_byname(pdev, "dma_tx");
+               ssi->irq_rx = platform_get_irq_byname(pdev, "dma_rx");
+               if (ssi->irq_tx == -ENXIO && ssi->irq_rx == -ENXIO) {
+                       ssi->irq_rt = platform_get_irq_byname(pdev, "dma_rt");
+                       if (ssi->irq_rt < 0)
+                               return ssi->irq_rt;
+
+                       ret = devm_request_irq(&pdev->dev, ssi->irq_rt,
+                                              &rz_ssi_interrupt, 0,
+                                              dev_name(&pdev->dev), ssi);
+                       if (ret < 0)
+                               return dev_err_probe(&pdev->dev, ret,
+                                                    "irq request error (dma_rt)\n");
+               } else {
+                       if (ssi->irq_tx < 0)
+                               return ssi->irq_tx;
+
+                       if (ssi->irq_rx < 0)
+                               return ssi->irq_rx;
+
+                       ret = devm_request_irq(&pdev->dev, ssi->irq_tx,
+                                              &rz_ssi_interrupt, 0,
+                                              dev_name(&pdev->dev), ssi);
+                       if (ret < 0)
+                               return dev_err_probe(&pdev->dev, ret,
+                                               "irq request error (dma_tx)\n");
+
+                       ret = devm_request_irq(&pdev->dev, ssi->irq_rx,
+                                              &rz_ssi_interrupt, 0,
+                                              dev_name(&pdev->dev), ssi);
+                       if (ret < 0)
+                               return dev_err_probe(&pdev->dev, ret,
+                                               "irq request error (dma_rx)\n");
+               }
+       }
+
+       ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+       if (IS_ERR(ssi->rstc)) {
+               ret = PTR_ERR(ssi->rstc);
+               goto err_reset;
+       }
+
+       reset_control_deassert(ssi->rstc);
+       pm_runtime_enable(&pdev->dev);
+       ret = pm_runtime_resume_and_get(&pdev->dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n");
+               goto err_pm;
+       }
+
+       ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component,
+                                             rz_ssi_soc_dai,
+                                             ARRAY_SIZE(rz_ssi_soc_dai));
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to register snd component\n");
+               goto err_snd_soc;
+       }
+
+       return 0;
+
+err_snd_soc:
+       pm_runtime_put(ssi->dev);
+err_pm:
+       pm_runtime_disable(ssi->dev);
+       reset_control_assert(ssi->rstc);
+err_reset:
+       rz_ssi_release_dma_channels(ssi);
+
+       return ret;
+}
+
+static void rz_ssi_remove(struct platform_device *pdev)
+{
+       struct rz_ssi_priv *ssi = dev_get_drvdata(&pdev->dev);
+
+       rz_ssi_release_dma_channels(ssi);
+
+       pm_runtime_put(ssi->dev);
+       pm_runtime_disable(ssi->dev);
+       reset_control_assert(ssi->rstc);
+}
+
+static const struct of_device_id rz_ssi_of_match[] = {
+       { .compatible = "renesas,rz-ssi", },
+       {/* Sentinel */},
+};
+MODULE_DEVICE_TABLE(of, rz_ssi_of_match);
+
+static struct platform_driver rz_ssi_driver = {
+       .driver = {
+               .name   = "rz-ssi-pcm-audio",
+               .of_match_table = rz_ssi_of_match,
+       },
+       .probe          = rz_ssi_probe,
+       .remove         = rz_ssi_remove,
+};
+
+module_platform_driver(rz_ssi_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Renesas RZ/G2L ASoC Serial Sound Interface Driver");
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
diff --git a/sound/soc/renesas/sh7760-ac97.c b/sound/soc/renesas/sh7760-ac97.c
new file mode 100644 (file)
index 0000000..d267243
--- /dev/null
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Generic AC97 sound support for SH7760
+//
+// (c) 2007 Manuel Lauss
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/io.h>
+
+#define IPSEL 0xFE400034
+
+SND_SOC_DAILINK_DEFS(ac97,
+       DAILINK_COMP_ARRAY(COMP_CPU("hac-dai.0")),      /* HAC0 */
+       DAILINK_COMP_ARRAY(COMP_CODEC("ac97-codec", "ac97-hifi")),
+       DAILINK_COMP_ARRAY(COMP_PLATFORM("sh7760-pcm-audio")));
+
+static struct snd_soc_dai_link sh7760_ac97_dai = {
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       SND_SOC_DAILINK_REG(ac97),
+};
+
+static struct snd_soc_card sh7760_ac97_soc_machine  = {
+       .name = "SH7760 AC97",
+       .owner = THIS_MODULE,
+       .dai_link = &sh7760_ac97_dai,
+       .num_links = 1,
+};
+
+static struct platform_device *sh7760_ac97_snd_device;
+
+static int __init sh7760_ac97_init(void)
+{
+       int ret;
+       unsigned short ipsel;
+
+       /* enable both AC97 controllers in pinmux reg */
+       ipsel = __raw_readw(IPSEL);
+       __raw_writew(ipsel | (3 << 10), IPSEL);
+
+       ret = -ENOMEM;
+       sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!sh7760_ac97_snd_device)
+               goto out;
+
+       platform_set_drvdata(sh7760_ac97_snd_device,
+                            &sh7760_ac97_soc_machine);
+       ret = platform_device_add(sh7760_ac97_snd_device);
+
+       if (ret)
+               platform_device_put(sh7760_ac97_snd_device);
+
+out:
+       return ret;
+}
+
+static void __exit sh7760_ac97_exit(void)
+{
+       platform_device_unregister(sh7760_ac97_snd_device);
+}
+
+module_init(sh7760_ac97_init);
+module_exit(sh7760_ac97_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/renesas/siu.h b/sound/soc/renesas/siu.h
new file mode 100644 (file)
index 0000000..a675c36
--- /dev/null
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
+
+#ifndef SIU_H
+#define SIU_H
+
+/* Common kernel and user-space firmware-building defines and types */
+
+#define YRAM0_SIZE             (0x0040 / 4)            /* 16 */
+#define YRAM1_SIZE             (0x0080 / 4)            /* 32 */
+#define YRAM2_SIZE             (0x0040 / 4)            /* 16 */
+#define YRAM3_SIZE             (0x0080 / 4)            /* 32 */
+#define YRAM4_SIZE             (0x0080 / 4)            /* 32 */
+#define YRAM_DEF_SIZE          (YRAM0_SIZE + YRAM1_SIZE + YRAM2_SIZE + \
+                                YRAM3_SIZE + YRAM4_SIZE)
+#define YRAM_FIR_SIZE          (0x0400 / 4)            /* 256 */
+#define YRAM_IIR_SIZE          (0x0200 / 4)            /* 128 */
+
+#define XRAM0_SIZE             (0x0400 / 4)            /* 256 */
+#define XRAM1_SIZE             (0x0200 / 4)            /* 128 */
+#define XRAM2_SIZE             (0x0200 / 4)            /* 128 */
+
+/* PRAM program array size */
+#define PRAM0_SIZE             (0x0100 / 4)            /* 64 */
+#define PRAM1_SIZE             ((0x2000 - 0x0100) / 4) /* 1984 */
+
+#include <linux/types.h>
+
+struct siu_spb_param {
+       __u32   ab1a;   /* input FIFO address */
+       __u32   ab0a;   /* output FIFO address */
+       __u32   dir;    /* 0=the ather except CPUOUTPUT, 1=CPUINPUT */
+       __u32   event;  /* SPB program starting conditions */
+       __u32   stfifo; /* STFIFO register setting value */
+       __u32   trdat;  /* TRDAT register setting value */
+};
+
+struct siu_firmware {
+       __u32                   yram_fir_coeff[YRAM_FIR_SIZE];
+       __u32                   pram0[PRAM0_SIZE];
+       __u32                   pram1[PRAM1_SIZE];
+       __u32                   yram0[YRAM0_SIZE];
+       __u32                   yram1[YRAM1_SIZE];
+       __u32                   yram2[YRAM2_SIZE];
+       __u32                   yram3[YRAM3_SIZE];
+       __u32                   yram4[YRAM4_SIZE];
+       __u32                   spbpar_num;
+       struct siu_spb_param    spbpar[32];
+};
+
+#ifdef __KERNEL__
+
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/sh_dma.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#define SIU_PERIOD_BYTES_MAX   8192            /* DMA transfer/period size */
+#define SIU_PERIOD_BYTES_MIN   256             /* DMA transfer/period size */
+#define SIU_PERIODS_MAX                64              /* Max periods in buffer */
+#define SIU_PERIODS_MIN                4               /* Min periods in buffer */
+#define SIU_BUFFER_BYTES_MAX   (SIU_PERIOD_BYTES_MAX * SIU_PERIODS_MAX)
+
+/* SIU ports: only one can be used at a time */
+enum {
+       SIU_PORT_A,
+       SIU_PORT_B,
+       SIU_PORT_NUM,
+};
+
+/* SIU clock configuration */
+enum {
+       SIU_CLKA_PLL,
+       SIU_CLKA_EXT,
+       SIU_CLKB_PLL,
+       SIU_CLKB_EXT
+};
+
+struct device;
+struct siu_info {
+       struct device           *dev;
+       int                     port_id;
+       u32 __iomem             *pram;
+       u32 __iomem             *xram;
+       u32 __iomem             *yram;
+       u32 __iomem             *reg;
+       struct siu_firmware     fw;
+};
+
+struct siu_stream {
+       struct work_struct              work;
+       struct snd_pcm_substream        *substream;
+       snd_pcm_format_t                format;
+       size_t                          buf_bytes;
+       size_t                          period_bytes;
+       int                             cur_period;     /* Period currently in dma */
+       u32                             volume;
+       snd_pcm_sframes_t               xfer_cnt;       /* Number of frames */
+       u8                              rw_flg;         /* transfer status */
+       /* DMA status */
+       struct dma_chan                 *chan;          /* DMA channel */
+       struct dma_async_tx_descriptor  *tx_desc;
+       dma_cookie_t                    cookie;
+       struct sh_dmae_slave            param;
+};
+
+struct siu_port {
+       unsigned long           play_cap;       /* Used to track full duplex */
+       struct snd_pcm          *pcm;
+       struct siu_stream       playback;
+       struct siu_stream       capture;
+       u32                     stfifo;         /* STFIFO value from firmware */
+       u32                     trdat;          /* TRDAT value from firmware */
+};
+
+extern struct siu_port *siu_ports[SIU_PORT_NUM];
+
+static inline struct siu_port *siu_port_info(struct snd_pcm_substream *substream)
+{
+       struct platform_device *pdev =
+               to_platform_device(substream->pcm->card->dev);
+       return siu_ports[pdev->id];
+}
+
+/* Register access */
+static inline void siu_write32(u32 __iomem *addr, u32 val)
+{
+       __raw_writel(val, addr);
+}
+
+static inline u32 siu_read32(u32 __iomem *addr)
+{
+       return __raw_readl(addr);
+}
+
+/* SIU registers */
+#define SIU_IFCTL      (0x000 / sizeof(u32))
+#define SIU_SRCTL      (0x004 / sizeof(u32))
+#define SIU_SFORM      (0x008 / sizeof(u32))
+#define SIU_CKCTL      (0x00c / sizeof(u32))
+#define SIU_TRDAT      (0x010 / sizeof(u32))
+#define SIU_STFIFO     (0x014 / sizeof(u32))
+#define SIU_DPAK       (0x01c / sizeof(u32))
+#define SIU_CKREV      (0x020 / sizeof(u32))
+#define SIU_EVNTC      (0x028 / sizeof(u32))
+#define SIU_SBCTL      (0x040 / sizeof(u32))
+#define SIU_SBPSET     (0x044 / sizeof(u32))
+#define SIU_SBFSTS     (0x068 / sizeof(u32))
+#define SIU_SBDVCA     (0x06c / sizeof(u32))
+#define SIU_SBDVCB     (0x070 / sizeof(u32))
+#define SIU_SBACTIV    (0x074 / sizeof(u32))
+#define SIU_DMAIA      (0x090 / sizeof(u32))
+#define SIU_DMAIB      (0x094 / sizeof(u32))
+#define SIU_DMAOA      (0x098 / sizeof(u32))
+#define SIU_DMAOB      (0x09c / sizeof(u32))
+#define SIU_DMAML      (0x0a0 / sizeof(u32))
+#define SIU_SPSTS      (0x0cc / sizeof(u32))
+#define SIU_SPCTL      (0x0d0 / sizeof(u32))
+#define SIU_BRGASEL    (0x100 / sizeof(u32))
+#define SIU_BRRA       (0x104 / sizeof(u32))
+#define SIU_BRGBSEL    (0x108 / sizeof(u32))
+#define SIU_BRRB       (0x10c / sizeof(u32))
+
+extern const struct snd_soc_component_driver siu_component;
+extern struct siu_info *siu_i2s_data;
+
+int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
+void siu_free_port(struct siu_port *port_info);
+
+#endif
+
+#endif /* SIU_H */
diff --git a/sound/soc/renesas/siu_dai.c b/sound/soc/renesas/siu_dai.c
new file mode 100644 (file)
index 0000000..7e771a1
--- /dev/null
@@ -0,0 +1,800 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <asm/clock.h>
+#include <asm/siu.h>
+
+#include <sound/control.h>
+#include <sound/soc.h>
+
+#include "siu.h"
+
+/* Board specifics */
+#if defined(CONFIG_CPU_SUBTYPE_SH7722)
+# define SIU_MAX_VOLUME                0x1000
+#else
+# define SIU_MAX_VOLUME                0x7fff
+#endif
+
+#define PRAM_SIZE      0x2000
+#define XRAM_SIZE      0x800
+#define YRAM_SIZE      0x800
+
+#define XRAM_OFFSET    0x4000
+#define YRAM_OFFSET    0x6000
+#define REG_OFFSET     0xc000
+
+#define PLAYBACK_ENABLED       1
+#define CAPTURE_ENABLED                2
+
+#define VOLUME_CAPTURE         0
+#define VOLUME_PLAYBACK                1
+#define DFLT_VOLUME_LEVEL      0x08000800
+
+/*
+ * SPDIF is only available on port A and on some SIU implementations it is only
+ * available for input. Due to the lack of hardware to test it, SPDIF is left
+ * disabled in this driver version
+ */
+struct format_flag {
+       u32     i2s;
+       u32     pcm;
+       u32     spdif;
+       u32     mask;
+};
+
+struct port_flag {
+       struct format_flag      playback;
+       struct format_flag      capture;
+};
+
+struct siu_info *siu_i2s_data;
+
+static struct port_flag siu_flags[SIU_PORT_NUM] = {
+       [SIU_PORT_A] = {
+               .playback = {
+                       .i2s    = 0x50000000,
+                       .pcm    = 0x40000000,
+                       .spdif  = 0x80000000,   /* not on all SIU versions */
+                       .mask   = 0xd0000000,
+               },
+               .capture = {
+                       .i2s    = 0x05000000,
+                       .pcm    = 0x04000000,
+                       .spdif  = 0x08000000,
+                       .mask   = 0x0d000000,
+               },
+       },
+       [SIU_PORT_B] = {
+               .playback = {
+                       .i2s    = 0x00500000,
+                       .pcm    = 0x00400000,
+                       .spdif  = 0,            /* impossible - turn off */
+                       .mask   = 0x00500000,
+               },
+               .capture = {
+                       .i2s    = 0x00050000,
+                       .pcm    = 0x00040000,
+                       .spdif  = 0,            /* impossible - turn off */
+                       .mask   = 0x00050000,
+               },
+       },
+};
+
+static void siu_dai_start(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+
+       dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
+
+       /* Issue software reset to siu */
+       siu_write32(base + SIU_SRCTL, 0);
+
+       /* Wait for the reset to take effect */
+       udelay(1);
+
+       port_info->stfifo = 0;
+       port_info->trdat = 0;
+
+       /* portA, portB, SIU operate */
+       siu_write32(base + SIU_SRCTL, 0x301);
+
+       /* portA=256fs, portB=256fs */
+       siu_write32(base + SIU_CKCTL, 0x40400000);
+
+       /* portA's BRG does not divide SIUCKA */
+       siu_write32(base + SIU_BRGASEL, 0);
+       siu_write32(base + SIU_BRRA, 0);
+
+       /* portB's BRG divides SIUCKB by half */
+       siu_write32(base + SIU_BRGBSEL, 1);
+       siu_write32(base + SIU_BRRB, 0);
+
+       siu_write32(base + SIU_IFCTL, 0x44440000);
+
+       /* portA: 32 bit/fs, master; portB: 32 bit/fs, master */
+       siu_write32(base + SIU_SFORM, 0x0c0c0000);
+
+       /*
+        * Volume levels: looks like the DSP firmware implements volume controls
+        * differently from what's described in the datasheet
+        */
+       siu_write32(base + SIU_SBDVCA, port_info->playback.volume);
+       siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
+}
+
+static void siu_dai_stop(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+
+       /* SIU software reset */
+       siu_write32(base + SIU_SRCTL, 0);
+}
+
+static void siu_dai_spbAselect(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_data;
+       struct siu_firmware *fw = &info->fw;
+       u32 *ydef = fw->yram0;
+       u32 idx;
+
+       /* path A use */
+       if (!info->port_id)
+               idx = 1;                /* portA */
+       else
+               idx = 2;                /* portB */
+
+       ydef[0] = (fw->spbpar[idx].ab1a << 16) |
+               (fw->spbpar[idx].ab0a << 8) |
+               (fw->spbpar[idx].dir << 7) | 3;
+       ydef[1] = fw->yram0[1]; /* 0x03000300 */
+       ydef[2] = (16 / 2) << 24;
+       ydef[3] = fw->yram0[3]; /* 0 */
+       ydef[4] = fw->yram0[4]; /* 0 */
+       ydef[7] = fw->spbpar[idx].event;
+       port_info->stfifo |= fw->spbpar[idx].stfifo;
+       port_info->trdat |= fw->spbpar[idx].trdat;
+}
+
+static void siu_dai_spbBselect(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_data;
+       struct siu_firmware *fw = &info->fw;
+       u32 *ydef = fw->yram0;
+       u32 idx;
+
+       /* path B use */
+       if (!info->port_id)
+               idx = 7;                /* portA */
+       else
+               idx = 8;                /* portB */
+
+       ydef[5] = (fw->spbpar[idx].ab1a << 16) |
+               (fw->spbpar[idx].ab0a << 8) | 1;
+       ydef[6] = fw->spbpar[idx].event;
+       port_info->stfifo |= fw->spbpar[idx].stfifo;
+       port_info->trdat |= fw->spbpar[idx].trdat;
+}
+
+static void siu_dai_open(struct siu_stream *siu_stream)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+       u32 srctl, ifctl;
+
+       srctl = siu_read32(base + SIU_SRCTL);
+       ifctl = siu_read32(base + SIU_IFCTL);
+
+       switch (info->port_id) {
+       case SIU_PORT_A:
+               /* portA operates */
+               srctl |= 0x200;
+               ifctl &= ~0xc2;
+               break;
+       case SIU_PORT_B:
+               /* portB operates */
+               srctl |= 0x100;
+               ifctl &= ~0x31;
+               break;
+       }
+
+       siu_write32(base + SIU_SRCTL, srctl);
+       /* Unmute and configure portA */
+       siu_write32(base + SIU_IFCTL, ifctl);
+}
+
+/*
+ * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower
+ * packing is supported
+ */
+static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+       u32 dpak;
+
+       dpak = siu_read32(base + SIU_DPAK);
+
+       switch (info->port_id) {
+       case SIU_PORT_A:
+               dpak &= ~0xc0000000;
+               break;
+       case SIU_PORT_B:
+               dpak &= ~0x00c00000;
+               break;
+       }
+
+       siu_write32(base + SIU_DPAK, dpak);
+}
+
+static int siu_dai_spbstart(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+       struct siu_firmware *fw = &info->fw;
+       u32 *ydef = fw->yram0;
+       int cnt;
+       u32 __iomem *add;
+       u32 *ptr;
+
+       /* Load SPB Program in PRAM */
+       ptr = fw->pram0;
+       add = info->pram;
+       for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++)
+               siu_write32(add, *ptr);
+
+       ptr = fw->pram1;
+       add = info->pram + (0x0100 / sizeof(u32));
+       for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++)
+               siu_write32(add, *ptr);
+
+       /* XRAM initialization */
+       add = info->xram;
+       for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++)
+               siu_write32(add, 0);
+
+       /* YRAM variable area initialization */
+       add = info->yram;
+       for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++)
+               siu_write32(add, ydef[cnt]);
+
+       /* YRAM FIR coefficient area initialization */
+       add = info->yram + (0x0200 / sizeof(u32));
+       for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++)
+               siu_write32(add, fw->yram_fir_coeff[cnt]);
+
+       /* YRAM IIR coefficient area initialization */
+       add = info->yram + (0x0600 / sizeof(u32));
+       for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++)
+               siu_write32(add, 0);
+
+       siu_write32(base + SIU_TRDAT, port_info->trdat);
+       port_info->trdat = 0x0;
+
+
+       /* SPB start condition: software */
+       siu_write32(base + SIU_SBACTIV, 0);
+       /* Start SPB */
+       siu_write32(base + SIU_SBCTL, 0xc0000000);
+       /* Wait for program to halt */
+       cnt = 0x10000;
+       while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000)
+               cpu_relax();
+
+       if (!cnt)
+               return -EBUSY;
+
+       /* SPB program start address setting */
+       siu_write32(base + SIU_SBPSET, 0x00400000);
+       /* SPB hardware start(FIFOCTL source) */
+       siu_write32(base + SIU_SBACTIV, 0xc0000000);
+
+       return 0;
+}
+
+static void siu_dai_spbstop(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+
+       siu_write32(base + SIU_SBACTIV, 0);
+       /* SPB stop */
+       siu_write32(base + SIU_SBCTL, 0);
+
+       port_info->stfifo = 0;
+}
+
+/*             API functions           */
+
+/* Playback and capture hardware properties are identical */
+static const struct snd_pcm_hardware siu_dai_pcm_hw = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED,
+       .formats                = SNDRV_PCM_FMTBIT_S16,
+       .rates                  = SNDRV_PCM_RATE_8000_48000,
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = SIU_BUFFER_BYTES_MAX,
+       .period_bytes_min       = SIU_PERIOD_BYTES_MIN,
+       .period_bytes_max       = SIU_PERIOD_BYTES_MAX,
+       .periods_min            = SIU_PERIODS_MIN,
+       .periods_max            = SIU_PERIODS_MAX,
+};
+
+static int siu_dai_info_volume(struct snd_kcontrol *kctrl,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       struct siu_port *port_info = snd_kcontrol_chip(kctrl);
+
+       dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = SIU_MAX_VOLUME;
+
+       return 0;
+}
+
+static int siu_dai_get_volume(struct snd_kcontrol *kctrl,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct siu_port *port_info = snd_kcontrol_chip(kctrl);
+       struct device *dev = port_info->pcm->card->dev;
+       u32 vol;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       switch (kctrl->private_value) {
+       case VOLUME_PLAYBACK:
+               /* Playback is always on port 0 */
+               vol = port_info->playback.volume;
+               ucontrol->value.integer.value[0] = vol & 0xffff;
+               ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
+               break;
+       case VOLUME_CAPTURE:
+               /* Capture is always on port 1 */
+               vol = port_info->capture.volume;
+               ucontrol->value.integer.value[0] = vol & 0xffff;
+               ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
+               break;
+       default:
+               dev_err(dev, "%s() invalid private_value=%ld\n",
+                       __func__, kctrl->private_value);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int siu_dai_put_volume(struct snd_kcontrol *kctrl,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct siu_port *port_info = snd_kcontrol_chip(kctrl);
+       struct device *dev = port_info->pcm->card->dev;
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+       u32 new_vol;
+       u32 cur_vol;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] > SIU_MAX_VOLUME ||
+           ucontrol->value.integer.value[1] < 0 ||
+           ucontrol->value.integer.value[1] > SIU_MAX_VOLUME)
+               return -EINVAL;
+
+       new_vol = ucontrol->value.integer.value[0] |
+               ucontrol->value.integer.value[1] << 16;
+
+       /* See comment above - DSP firmware implementation */
+       switch (kctrl->private_value) {
+       case VOLUME_PLAYBACK:
+               /* Playback is always on port 0 */
+               cur_vol = port_info->playback.volume;
+               siu_write32(base + SIU_SBDVCA, new_vol);
+               port_info->playback.volume = new_vol;
+               break;
+       case VOLUME_CAPTURE:
+               /* Capture is always on port 1 */
+               cur_vol = port_info->capture.volume;
+               siu_write32(base + SIU_SBDVCB, new_vol);
+               port_info->capture.volume = new_vol;
+               break;
+       default:
+               dev_err(dev, "%s() invalid private_value=%ld\n",
+                       __func__, kctrl->private_value);
+               return -EINVAL;
+       }
+
+       if (cur_vol != new_vol)
+               return 1;
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new playback_controls = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "PCM Playback Volume",
+       .index          = 0,
+       .info           = siu_dai_info_volume,
+       .get            = siu_dai_get_volume,
+       .put            = siu_dai_put_volume,
+       .private_value  = VOLUME_PLAYBACK,
+};
+
+static const struct snd_kcontrol_new capture_controls = {
+       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name           = "PCM Capture Volume",
+       .index          = 0,
+       .info           = siu_dai_info_volume,
+       .get            = siu_dai_get_volume,
+       .put            = siu_dai_put_volume,
+       .private_value  = VOLUME_CAPTURE,
+};
+
+int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card)
+{
+       struct device *dev = card->dev;
+       struct snd_kcontrol *kctrl;
+       int ret;
+
+       *port_info = kzalloc(sizeof(**port_info), GFP_KERNEL);
+       if (!*port_info)
+               return -ENOMEM;
+
+       dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info);
+
+       (*port_info)->playback.volume = DFLT_VOLUME_LEVEL;
+       (*port_info)->capture.volume = DFLT_VOLUME_LEVEL;
+
+       /*
+        * Add mixer support. The SPB is used to change the volume. Both
+        * ports use the same SPB. Therefore, we only register one
+        * control instance since it will be used by both channels.
+        * In error case we continue without controls.
+        */
+       kctrl = snd_ctl_new1(&playback_controls, *port_info);
+       ret = snd_ctl_add(card, kctrl);
+       if (ret < 0)
+               dev_err(dev,
+                       "failed to add playback controls %p port=%d err=%d\n",
+                       kctrl, port, ret);
+
+       kctrl = snd_ctl_new1(&capture_controls, *port_info);
+       ret = snd_ctl_add(card, kctrl);
+       if (ret < 0)
+               dev_err(dev,
+                       "failed to add capture controls %p port=%d err=%d\n",
+                       kctrl, port, ret);
+
+       return 0;
+}
+
+void siu_free_port(struct siu_port *port_info)
+{
+       kfree(port_info);
+}
+
+static int siu_dai_startup(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
+{
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
+       struct snd_pcm_runtime *rt = substream->runtime;
+       struct siu_port *port_info = siu_port_info(substream);
+       int ret;
+
+       dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
+               info->port_id, port_info);
+
+       snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw);
+
+       ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
+       if (unlikely(ret < 0))
+               return ret;
+
+       siu_dai_start(port_info);
+
+       return 0;
+}
+
+static void siu_dai_shutdown(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
+       struct siu_port *port_info = siu_port_info(substream);
+
+       dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
+               info->port_id, port_info);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               port_info->play_cap &= ~PLAYBACK_ENABLED;
+       else
+               port_info->play_cap &= ~CAPTURE_ENABLED;
+
+       /* Stop the siu if the other stream is not using it */
+       if (!port_info->play_cap) {
+               /* during stmread or stmwrite ? */
+               if (WARN_ON(port_info->playback.rw_flg || port_info->capture.rw_flg))
+                       return;
+               siu_dai_spbstop(port_info);
+               siu_dai_stop(port_info);
+       }
+}
+
+/* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */
+static int siu_dai_prepare(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
+{
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
+       struct snd_pcm_runtime *rt = substream->runtime;
+       struct siu_port *port_info = siu_port_info(substream);
+       struct siu_stream *siu_stream;
+       int self, ret;
+
+       dev_dbg(substream->pcm->card->dev,
+               "%s: port %d, active streams %lx, %d channels\n",
+               __func__, info->port_id, port_info->play_cap, rt->channels);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               self = PLAYBACK_ENABLED;
+               siu_stream = &port_info->playback;
+       } else {
+               self = CAPTURE_ENABLED;
+               siu_stream = &port_info->capture;
+       }
+
+       /* Set up the siu if not already done */
+       if (!port_info->play_cap) {
+               siu_stream->rw_flg = 0; /* stream-data transfer flag */
+
+               siu_dai_spbAselect(port_info);
+               siu_dai_spbBselect(port_info);
+
+               siu_dai_open(siu_stream);
+
+               siu_dai_pcmdatapack(siu_stream);
+
+               ret = siu_dai_spbstart(port_info);
+               if (ret < 0)
+                       goto fail;
+       } else {
+               ret = 0;
+       }
+
+       port_info->play_cap |= self;
+
+fail:
+       return ret;
+}
+
+/*
+ * SIU can set bus format to I2S / PCM / SPDIF independently for playback and
+ * capture, however, the current API sets the bus format globally for a DAI.
+ */
+static int siu_dai_set_fmt(struct snd_soc_dai *dai,
+                          unsigned int fmt)
+{
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
+       u32 __iomem *base = info->reg;
+       u32 ifctl;
+
+       dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n",
+               __func__, fmt, info->port_id);
+
+       if (info->port_id < 0)
+               return -ENODEV;
+
+       /* Here select between I2S / PCM / SPDIF */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               ifctl = siu_flags[info->port_id].playback.i2s |
+                       siu_flags[info->port_id].capture.i2s;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ifctl = siu_flags[info->port_id].playback.pcm |
+                       siu_flags[info->port_id].capture.pcm;
+               break;
+       /* SPDIF disabled - see comment at the top */
+       default:
+               return -EINVAL;
+       }
+
+       ifctl |= ~(siu_flags[info->port_id].playback.mask |
+                  siu_flags[info->port_id].capture.mask) &
+               siu_read32(base + SIU_IFCTL);
+       siu_write32(base + SIU_IFCTL, ifctl);
+
+       return 0;
+}
+
+static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                             unsigned int freq, int dir)
+{
+       struct clk *siu_clk, *parent_clk;
+       char *siu_name, *parent_name;
+       int ret;
+
+       if (dir != SND_SOC_CLOCK_IN)
+               return -EINVAL;
+
+       dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id);
+
+       switch (clk_id) {
+       case SIU_CLKA_PLL:
+               siu_name = "siua_clk";
+               parent_name = "pll_clk";
+               break;
+       case SIU_CLKA_EXT:
+               siu_name = "siua_clk";
+               parent_name = "siumcka_clk";
+               break;
+       case SIU_CLKB_PLL:
+               siu_name = "siub_clk";
+               parent_name = "pll_clk";
+               break;
+       case SIU_CLKB_EXT:
+               siu_name = "siub_clk";
+               parent_name = "siumckb_clk";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       siu_clk = clk_get(dai->dev, siu_name);
+       if (IS_ERR(siu_clk)) {
+               dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__,
+                       PTR_ERR(siu_clk));
+               return PTR_ERR(siu_clk);
+       }
+
+       parent_clk = clk_get(dai->dev, parent_name);
+       if (IS_ERR(parent_clk)) {
+               ret = PTR_ERR(parent_clk);
+               dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret);
+               goto epclkget;
+       }
+
+       ret = clk_set_parent(siu_clk, parent_clk);
+       if (ret < 0) {
+               dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret);
+               goto eclksetp;
+       }
+
+       ret = clk_set_rate(siu_clk, freq);
+       if (ret < 0)
+               dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret);
+
+       /* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */
+eclksetp:
+       clk_put(parent_clk);
+epclkget:
+       clk_put(siu_clk);
+
+       return ret;
+}
+
+static const struct snd_soc_dai_ops siu_dai_ops = {
+       .startup        = siu_dai_startup,
+       .shutdown       = siu_dai_shutdown,
+       .prepare        = siu_dai_prepare,
+       .set_sysclk     = siu_dai_set_sysclk,
+       .set_fmt        = siu_dai_set_fmt,
+};
+
+static struct snd_soc_dai_driver siu_i2s_dai = {
+       .name   = "siu-i2s-dai",
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .formats = SNDRV_PCM_FMTBIT_S16,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .formats = SNDRV_PCM_FMTBIT_S16,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+        },
+       .ops = &siu_dai_ops,
+};
+
+static int siu_probe(struct platform_device *pdev)
+{
+       const struct firmware *fw_entry;
+       struct resource *res, *region;
+       struct siu_info *info;
+       int ret;
+
+       info = devm_kmalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       siu_i2s_data = info;
+       info->dev = &pdev->dev;
+
+       ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
+       if (ret)
+               return ret;
+
+       /*
+        * Loaded firmware is "const" - read only, but we have to modify it in
+        * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect()
+        */
+       memcpy(&info->fw, fw_entry->data, fw_entry->size);
+
+       release_firmware(fw_entry);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       region = devm_request_mem_region(&pdev->dev, res->start,
+                                        resource_size(res), pdev->name);
+       if (!region) {
+               dev_err(&pdev->dev, "SIU region already claimed\n");
+               return -EBUSY;
+       }
+
+       info->pram = devm_ioremap(&pdev->dev, res->start, PRAM_SIZE);
+       if (!info->pram)
+               return -ENOMEM;
+       info->xram = devm_ioremap(&pdev->dev, res->start + XRAM_OFFSET,
+                                 XRAM_SIZE);
+       if (!info->xram)
+               return -ENOMEM;
+       info->yram = devm_ioremap(&pdev->dev, res->start + YRAM_OFFSET,
+                                 YRAM_SIZE);
+       if (!info->yram)
+               return -ENOMEM;
+       info->reg = devm_ioremap(&pdev->dev, res->start + REG_OFFSET,
+                           resource_size(res) - REG_OFFSET);
+       if (!info->reg)
+               return -ENOMEM;
+
+       dev_set_drvdata(&pdev->dev, info);
+
+       /* register using ARRAY version so we can keep dai name */
+       ret = devm_snd_soc_register_component(&pdev->dev, &siu_component,
+                                             &siu_i2s_dai, 1);
+       if (ret < 0)
+               return ret;
+
+       pm_runtime_enable(&pdev->dev);
+
+       return 0;
+}
+
+static void siu_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+}
+
+static struct platform_driver siu_driver = {
+       .driver         = {
+               .name   = "siu-pcm-audio",
+       },
+       .probe          = siu_probe,
+       .remove         = siu_remove,
+};
+
+module_platform_driver(siu_driver);
+
+MODULE_AUTHOR("Carlos Munoz <carlos@kenati.com>");
+MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver");
+MODULE_LICENSE("GPL");
+
+MODULE_FIRMWARE("siu_spb.bin");
diff --git a/sound/soc/renesas/siu_pcm.c b/sound/soc/renesas/siu_pcm.c
new file mode 100644 (file)
index 0000000..f15ff36
--- /dev/null
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/siu.h>
+
+#include "siu.h"
+
+#define DRV_NAME "siu-i2s"
+#define GET_MAX_PERIODS(buf_bytes, period_bytes) \
+                               ((buf_bytes) / (period_bytes))
+#define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \
+                               ((buf_addr) + ((period_num) * (period_bytes)))
+
+#define RWF_STM_RD             0x01            /* Read in progress */
+#define RWF_STM_WT             0x02            /* Write in progress */
+
+struct siu_port *siu_ports[SIU_PORT_NUM];
+
+/* transfersize is number of u32 dma transfers per period */
+static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+       struct siu_stream *siu_stream = &port_info->playback;
+       u32 stfifo;
+
+       if (!siu_stream->rw_flg)
+               return -EPERM;
+
+       /* output FIFO disable */
+       stfifo = siu_read32(base + SIU_STFIFO);
+       siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18);
+       pr_debug("%s: STFIFO %x -> %x\n", __func__,
+                stfifo, stfifo & ~0x0c180c18);
+
+       /* during stmwrite clear */
+       siu_stream->rw_flg = 0;
+
+       return 0;
+}
+
+static int siu_pcm_stmwrite_start(struct siu_port *port_info)
+{
+       struct siu_stream *siu_stream = &port_info->playback;
+
+       if (siu_stream->rw_flg)
+               return -EPERM;
+
+       /* Current period in buffer */
+       port_info->playback.cur_period = 0;
+
+       /* during stmwrite flag set */
+       siu_stream->rw_flg = RWF_STM_WT;
+
+       /* DMA transfer start */
+       queue_work(system_highpri_wq, &siu_stream->work);
+
+       return 0;
+}
+
+static void siu_dma_tx_complete(void *arg)
+{
+       struct siu_stream *siu_stream = arg;
+
+       if (!siu_stream->rw_flg)
+               return;
+
+       /* Update completed period count */
+       if (++siu_stream->cur_period >=
+           GET_MAX_PERIODS(siu_stream->buf_bytes,
+                           siu_stream->period_bytes))
+               siu_stream->cur_period = 0;
+
+       pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n",
+               __func__, siu_stream->cur_period,
+               siu_stream->cur_period * siu_stream->period_bytes,
+               siu_stream->buf_bytes, siu_stream->cookie);
+
+       queue_work(system_highpri_wq, &siu_stream->work);
+
+       /* Notify alsa: a period is done */
+       snd_pcm_period_elapsed(siu_stream->substream);
+}
+
+static int siu_pcm_wr_set(struct siu_port *port_info,
+                         dma_addr_t buff, u32 size)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+       struct siu_stream *siu_stream = &port_info->playback;
+       struct snd_pcm_substream *substream = siu_stream->substream;
+       struct device *dev = substream->pcm->card->dev;
+       struct dma_async_tx_descriptor *desc;
+       dma_cookie_t cookie;
+       struct scatterlist sg;
+       u32 stfifo;
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
+                   size, offset_in_page(buff));
+       sg_dma_len(&sg) = size;
+       sg_dma_address(&sg) = buff;
+
+       desc = dmaengine_prep_slave_sg(siu_stream->chan,
+               &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_err(dev, "Failed to allocate a dma descriptor\n");
+               return -ENOMEM;
+       }
+
+       desc->callback = siu_dma_tx_complete;
+       desc->callback_param = siu_stream;
+       cookie = dmaengine_submit(desc);
+       if (cookie < 0) {
+               dev_err(dev, "Failed to submit a dma transfer\n");
+               return cookie;
+       }
+
+       siu_stream->tx_desc = desc;
+       siu_stream->cookie = cookie;
+
+       dma_async_issue_pending(siu_stream->chan);
+
+       /* only output FIFO enable */
+       stfifo = siu_read32(base + SIU_STFIFO);
+       siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18));
+       dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
+               stfifo, stfifo | (port_info->stfifo & 0x0c180c18));
+
+       return 0;
+}
+
+static int siu_pcm_rd_set(struct siu_port *port_info,
+                         dma_addr_t buff, size_t size)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+       struct siu_stream *siu_stream = &port_info->capture;
+       struct snd_pcm_substream *substream = siu_stream->substream;
+       struct device *dev = substream->pcm->card->dev;
+       struct dma_async_tx_descriptor *desc;
+       dma_cookie_t cookie;
+       struct scatterlist sg;
+       u32 stfifo;
+
+       dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff);
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
+                   size, offset_in_page(buff));
+       sg_dma_len(&sg) = size;
+       sg_dma_address(&sg) = buff;
+
+       desc = dmaengine_prep_slave_sg(siu_stream->chan,
+               &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_err(dev, "Failed to allocate dma descriptor\n");
+               return -ENOMEM;
+       }
+
+       desc->callback = siu_dma_tx_complete;
+       desc->callback_param = siu_stream;
+       cookie = dmaengine_submit(desc);
+       if (cookie < 0) {
+               dev_err(dev, "Failed to submit dma descriptor\n");
+               return cookie;
+       }
+
+       siu_stream->tx_desc = desc;
+       siu_stream->cookie = cookie;
+
+       dma_async_issue_pending(siu_stream->chan);
+
+       /* only input FIFO enable */
+       stfifo = siu_read32(base + SIU_STFIFO);
+       siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) |
+                   (port_info->stfifo & 0x13071307));
+       dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
+               stfifo, stfifo | (port_info->stfifo & 0x13071307));
+
+       return 0;
+}
+
+static void siu_io_work(struct work_struct *work)
+{
+       struct siu_stream *siu_stream = container_of(work, struct siu_stream,
+                                                    work);
+       struct snd_pcm_substream *substream = siu_stream->substream;
+       struct device *dev = substream->pcm->card->dev;
+       struct snd_pcm_runtime *rt = substream->runtime;
+       struct siu_port *port_info = siu_port_info(substream);
+
+       dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg);
+
+       if (!siu_stream->rw_flg) {
+               dev_dbg(dev, "%s: stream inactive\n", __func__);
+               return;
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               dma_addr_t buff;
+               size_t count;
+
+               buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
+                                               siu_stream->cur_period,
+                                               siu_stream->period_bytes);
+               count = siu_stream->period_bytes;
+
+               /* DMA transfer start */
+               siu_pcm_rd_set(port_info, buff, count);
+       } else {
+               siu_pcm_wr_set(port_info,
+                              (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
+                                               siu_stream->cur_period,
+                                               siu_stream->period_bytes),
+                              siu_stream->period_bytes);
+       }
+}
+
+/* Capture */
+static int siu_pcm_stmread_start(struct siu_port *port_info)
+{
+       struct siu_stream *siu_stream = &port_info->capture;
+
+       if (siu_stream->xfer_cnt > 0x1000000)
+               return -EINVAL;
+       if (siu_stream->rw_flg)
+               return -EPERM;
+
+       /* Current period in buffer */
+       siu_stream->cur_period = 0;
+
+       /* during stmread flag set */
+       siu_stream->rw_flg = RWF_STM_RD;
+
+       queue_work(system_highpri_wq, &siu_stream->work);
+
+       return 0;
+}
+
+static int siu_pcm_stmread_stop(struct siu_port *port_info)
+{
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+       struct siu_stream *siu_stream = &port_info->capture;
+       struct device *dev = siu_stream->substream->pcm->card->dev;
+       u32 stfifo;
+
+       if (!siu_stream->rw_flg)
+               return -EPERM;
+
+       /* input FIFO disable */
+       stfifo = siu_read32(base + SIU_STFIFO);
+       siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307);
+       dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
+               stfifo, stfifo & ~0x13071307);
+
+       /* during stmread flag clear */
+       siu_stream->rw_flg = 0;
+
+       return 0;
+}
+
+static bool filter(struct dma_chan *chan, void *secondary)
+{
+       struct sh_dmae_slave *param = secondary;
+
+       pr_debug("%s: secondary ID %d\n", __func__, param->shdma_slave.slave_id);
+
+       chan->private = &param->shdma_slave;
+       return true;
+}
+
+static int siu_pcm_open(struct snd_soc_component *component,
+                       struct snd_pcm_substream *ss)
+{
+       /* Playback / Capture */
+       struct siu_platform *pdata = component->dev->platform_data;
+       struct siu_info *info = siu_i2s_data;
+       struct siu_port *port_info = siu_port_info(ss);
+       struct siu_stream *siu_stream;
+       u32 port = info->port_id;
+       struct device *dev = ss->pcm->card->dev;
+       dma_cap_mask_t mask;
+       struct sh_dmae_slave *param;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info);
+
+       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               siu_stream = &port_info->playback;
+               param = &siu_stream->param;
+               param->shdma_slave.slave_id = port ? pdata->dma_slave_tx_b :
+                       pdata->dma_slave_tx_a;
+       } else {
+               siu_stream = &port_info->capture;
+               param = &siu_stream->param;
+               param->shdma_slave.slave_id = port ? pdata->dma_slave_rx_b :
+                       pdata->dma_slave_rx_a;
+       }
+
+       /* Get DMA channel */
+       siu_stream->chan = dma_request_channel(mask, filter, param);
+       if (!siu_stream->chan) {
+               dev_err(dev, "DMA channel allocation failed!\n");
+               return -EBUSY;
+       }
+
+       siu_stream->substream = ss;
+
+       return 0;
+}
+
+static int siu_pcm_close(struct snd_soc_component *component,
+                        struct snd_pcm_substream *ss)
+{
+       struct siu_info *info = siu_i2s_data;
+       struct device *dev = ss->pcm->card->dev;
+       struct siu_port *port_info = siu_port_info(ss);
+       struct siu_stream *siu_stream;
+
+       dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
+
+       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               siu_stream = &port_info->playback;
+       else
+               siu_stream = &port_info->capture;
+
+       dma_release_channel(siu_stream->chan);
+       siu_stream->chan = NULL;
+
+       siu_stream->substream = NULL;
+
+       return 0;
+}
+
+static int siu_pcm_prepare(struct snd_soc_component *component,
+                          struct snd_pcm_substream *ss)
+{
+       struct siu_info *info = siu_i2s_data;
+       struct siu_port *port_info = siu_port_info(ss);
+       struct device *dev = ss->pcm->card->dev;
+       struct snd_pcm_runtime *rt;
+       struct siu_stream *siu_stream;
+       snd_pcm_sframes_t xfer_cnt;
+
+       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               siu_stream = &port_info->playback;
+       else
+               siu_stream = &port_info->capture;
+
+       rt = siu_stream->substream->runtime;
+
+       siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss);
+       siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss);
+
+       dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__,
+               info->port_id, rt->channels, siu_stream->period_bytes);
+
+       /* We only support buffers that are multiples of the period */
+       if (siu_stream->buf_bytes % siu_stream->period_bytes) {
+               dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n",
+                      __func__, siu_stream->buf_bytes,
+                      siu_stream->period_bytes);
+               return -EINVAL;
+       }
+
+       xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes);
+       if (!xfer_cnt || xfer_cnt > 0x1000000)
+               return -EINVAL;
+
+       siu_stream->format = rt->format;
+       siu_stream->xfer_cnt = xfer_cnt;
+
+       dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d "
+               "format=%d channels=%d xfer_cnt=%d\n", info->port_id,
+               (unsigned long)rt->dma_addr, siu_stream->buf_bytes,
+               siu_stream->period_bytes,
+               siu_stream->format, rt->channels, (int)xfer_cnt);
+
+       return 0;
+}
+
+static int siu_pcm_trigger(struct snd_soc_component *component,
+                          struct snd_pcm_substream *ss, int cmd)
+{
+       struct siu_info *info = siu_i2s_data;
+       struct device *dev = ss->pcm->card->dev;
+       struct siu_port *port_info = siu_port_info(ss);
+       int ret;
+
+       dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__,
+               info->port_id, port_info, cmd);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       ret = siu_pcm_stmwrite_start(port_info);
+               else
+                       ret = siu_pcm_stmread_start(port_info);
+
+               if (ret < 0)
+                       dev_warn(dev, "%s: start failed on port=%d\n",
+                                __func__, info->port_id);
+
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       siu_pcm_stmwrite_stop(port_info);
+               else
+                       siu_pcm_stmread_stop(port_info);
+               ret = 0;
+
+               break;
+       default:
+               dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+/*
+ * So far only resolution of one period is supported, subject to extending the
+ * dmangine API
+ */
+static snd_pcm_uframes_t
+siu_pcm_pointer_dma(struct snd_soc_component *component,
+                   struct snd_pcm_substream *ss)
+{
+       struct device *dev = ss->pcm->card->dev;
+       struct siu_info *info = siu_i2s_data;
+       u32 __iomem *base = info->reg;
+       struct siu_port *port_info = siu_port_info(ss);
+       struct snd_pcm_runtime *rt = ss->runtime;
+       size_t ptr;
+       struct siu_stream *siu_stream;
+
+       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               siu_stream = &port_info->playback;
+       else
+               siu_stream = &port_info->capture;
+
+       /*
+        * ptr is the offset into the buffer where the dma is currently at. We
+        * check if the dma buffer has just wrapped.
+        */
+       ptr = PERIOD_OFFSET(rt->dma_addr,
+                           siu_stream->cur_period,
+                           siu_stream->period_bytes) - rt->dma_addr;
+
+       dev_dbg(dev,
+               "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n",
+               __func__, info->port_id, siu_read32(base + SIU_EVNTC),
+               siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes,
+               siu_stream->cookie);
+
+       if (ptr >= siu_stream->buf_bytes)
+               ptr = 0;
+
+       return bytes_to_frames(ss->runtime, ptr);
+}
+
+static int siu_pcm_new(struct snd_soc_component *component,
+                      struct snd_soc_pcm_runtime *rtd)
+{
+       /* card->dev == socdev->dev, see snd_soc_new_pcms() */
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_pcm *pcm = rtd->pcm;
+       struct siu_info *info = siu_i2s_data;
+       struct platform_device *pdev = to_platform_device(card->dev);
+       int ret;
+       int i;
+
+       /* pdev->id selects between SIUA and SIUB */
+       if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM)
+               return -EINVAL;
+
+       info->port_id = pdev->id;
+
+       /*
+        * While the siu has 2 ports, only one port can be on at a time (only 1
+        * SPB). So far all the boards using the siu had only one of the ports
+        * wired to a codec. To simplify things, we only register one port with
+        * alsa. In case both ports are needed, it should be changed here
+        */
+       for (i = pdev->id; i < pdev->id + 1; i++) {
+               struct siu_port **port_info = &siu_ports[i];
+
+               ret = siu_init_port(i, port_info, card);
+               if (ret < 0)
+                       return ret;
+
+               snd_pcm_set_managed_buffer_all(pcm,
+                               SNDRV_DMA_TYPE_DEV, card->dev,
+                               SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX);
+
+               (*port_info)->pcm = pcm;
+
+               /* IO works */
+               INIT_WORK(&(*port_info)->playback.work, siu_io_work);
+               INIT_WORK(&(*port_info)->capture.work, siu_io_work);
+       }
+
+       dev_info(card->dev, "SuperH SIU driver initialized.\n");
+       return 0;
+}
+
+static void siu_pcm_free(struct snd_soc_component *component,
+                        struct snd_pcm *pcm)
+{
+       struct platform_device *pdev = to_platform_device(pcm->card->dev);
+       struct siu_port *port_info = siu_ports[pdev->id];
+
+       cancel_work_sync(&port_info->capture.work);
+       cancel_work_sync(&port_info->playback.work);
+
+       siu_free_port(port_info);
+
+       dev_dbg(pcm->card->dev, "%s\n", __func__);
+}
+
+const struct snd_soc_component_driver siu_component = {
+       .name                   = DRV_NAME,
+       .open                   = siu_pcm_open,
+       .close                  = siu_pcm_close,
+       .prepare                = siu_pcm_prepare,
+       .trigger                = siu_pcm_trigger,
+       .pointer                = siu_pcm_pointer_dma,
+       .pcm_construct          = siu_pcm_new,
+       .pcm_destruct           = siu_pcm_free,
+       .legacy_dai_naming      = 1,
+};
+EXPORT_SYMBOL_GPL(siu_component);
diff --git a/sound/soc/renesas/ssi.c b/sound/soc/renesas/ssi.c
new file mode 100644 (file)
index 0000000..96cf523
--- /dev/null
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Serial Sound Interface (I2S) support for SH7760/SH7780
+//
+// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+//
+// dont forget to set IPSEL/OMSEL register bits (in your board code) to
+// enable SSI output pins!
+
+/*
+ * LIMITATIONS:
+ *     The SSI unit has only one physical data line, so full duplex is
+ *     impossible.  This can be remedied  on the  SH7760 by  using the
+ *     other SSI unit for recording; however the SH7780 has only 1 SSI
+ *     unit, and its pins are shared with the AC97 unit,  among others.
+ *
+ * FEATURES:
+ *     The SSI features "compressed mode": in this mode it continuously
+ *     streams PCM data over the I2S lines and uses LRCK as a handshake
+ *     signal.  Can be used to send compressed data (AC3/DTS) to a DSP.
+ *     The number of bits sent over the wire in a frame can be adjusted
+ *     and can be independent from the actual sample bit depth. This is
+ *     useful to support TDM mode codecs like the AD1939 which have a
+ *     fixed TDM slot size, regardless of sample resolution.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/io.h>
+
+#define SSICR  0x00
+#define SSISR  0x04
+
+#define CR_DMAEN       (1 << 28)
+#define CR_CHNL_SHIFT  22
+#define CR_CHNL_MASK   (3 << CR_CHNL_SHIFT)
+#define CR_DWL_SHIFT   19
+#define CR_DWL_MASK    (7 << CR_DWL_SHIFT)
+#define CR_SWL_SHIFT   16
+#define CR_SWL_MASK    (7 << CR_SWL_SHIFT)
+#define CR_SCK_MASTER  (1 << 15)       /* bitclock master bit */
+#define CR_SWS_MASTER  (1 << 14)       /* wordselect master bit */
+#define CR_SCKP                (1 << 13)       /* I2Sclock polarity */
+#define CR_SWSP                (1 << 12)       /* LRCK polarity */
+#define CR_SPDP                (1 << 11)
+#define CR_SDTA                (1 << 10)       /* i2s alignment (msb/lsb) */
+#define CR_PDTA                (1 << 9)        /* fifo data alignment */
+#define CR_DEL         (1 << 8)        /* delay data by 1 i2sclk */
+#define CR_BREN                (1 << 7)        /* clock gating in burst mode */
+#define CR_CKDIV_SHIFT 4
+#define CR_CKDIV_MASK  (7 << CR_CKDIV_SHIFT)   /* bitclock divider */
+#define CR_MUTE                (1 << 3)        /* SSI mute */
+#define CR_CPEN                (1 << 2)        /* compressed mode */
+#define CR_TRMD                (1 << 1)        /* transmit/receive select */
+#define CR_EN          (1 << 0)        /* enable SSI */
+
+#define SSIREG(reg)    (*(unsigned long *)(ssi->mmio + (reg)))
+
+struct ssi_priv {
+       unsigned long mmio;
+       unsigned long sysclk;
+       int inuse;
+} ssi_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+       {
+               .mmio   = 0xFE680000,
+       },
+       {
+               .mmio   = 0xFE690000,
+       },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+       {
+               .mmio   = 0xFFE70000,
+       },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+/*
+ * track usage of the SSI; it is simplex-only so prevent attempts of
+ * concurrent playback + capture. FIXME: any locking required?
+ */
+static int ssi_startup(struct snd_pcm_substream *substream,
+                      struct snd_soc_dai *dai)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+       if (ssi->inuse) {
+               pr_debug("ssi: already in use!\n");
+               return -EBUSY;
+       } else
+               ssi->inuse = 1;
+       return 0;
+}
+
+static void ssi_shutdown(struct snd_pcm_substream *substream,
+                        struct snd_soc_dai *dai)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+
+       ssi->inuse = 0;
+}
+
+static int ssi_trigger(struct snd_pcm_substream *substream, int cmd,
+                      struct snd_soc_dai *dai)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               SSIREG(SSICR) |= CR_DMAEN | CR_EN;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ssi_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params,
+                        struct snd_soc_dai *dai)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+       unsigned long ssicr = SSIREG(SSICR);
+       unsigned int bits, channels, swl, recv, i;
+
+       channels = params_channels(params);
+       bits = params->msbits;
+       recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
+
+       pr_debug("ssi_hw_params() enter\nssicr was    %08lx\n", ssicr);
+       pr_debug("bits: %u channels: %u\n", bits, channels);
+
+       ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
+                  CR_SWL_MASK);
+
+       /* direction (send/receive) */
+       if (!recv)
+               ssicr |= CR_TRMD;       /* transmit */
+
+       /* channels */
+       if ((channels < 2) || (channels > 8) || (channels & 1)) {
+               pr_debug("ssi: invalid number of channels\n");
+               return -EINVAL;
+       }
+       ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT;
+
+       /* DATA WORD LENGTH (DWL): databits in audio sample */
+       i = 0;
+       switch (bits) {
+       case 32: ++i;
+       case 24: ++i;
+       case 22: ++i;
+       case 20: ++i;
+       case 18: ++i;
+       case 16: ++i;
+                ssicr |= i << CR_DWL_SHIFT;
+       case 8:  break;
+       default:
+               pr_debug("ssi: invalid sample width\n");
+               return -EINVAL;
+       }
+
+       /*
+        * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S
+        * wires. This is usually bits_per_sample x channels/2;  i.e. in
+        * Stereo mode  the SWL equals DWL.  SWL can  be bigger than the
+        * product of (channels_per_slot x samplebits), e.g.  for codecs
+        * like the AD1939 which  only accept 32bit wide TDM slots.  For
+        * "standard" I2S operation we set SWL = chans / 2 * DWL here.
+        * Waiting for ASoC to get TDM support ;-)
+        */
+       if ((bits > 16) && (bits <= 24)) {
+               bits = 24;      /* these are padded by the SSI */
+               /*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */
+       }
+       i = 0;
+       swl = (bits * channels) / 2;
+       switch (swl) {
+       case 256: ++i;
+       case 128: ++i;
+       case 64:  ++i;
+       case 48:  ++i;
+       case 32:  ++i;
+       case 16:  ++i;
+                 ssicr |= i << CR_SWL_SHIFT;
+       case 8:   break;
+       default:
+               pr_debug("ssi: invalid system word length computed\n");
+               return -EINVAL;
+       }
+
+       SSIREG(SSICR) = ssicr;
+
+       pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr);
+       return 0;
+}
+
+static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
+                         unsigned int freq, int dir)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
+
+       ssi->sysclk = freq;
+
+       return 0;
+}
+
+/*
+ * This divider is used to generate the SSI_SCK (I2S bitclock) from the
+ * clock at the HAC_BIT_CLK ("oversampling clock") pin.
+ */
+static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+       unsigned long ssicr;
+       int i;
+
+       i = 0;
+       ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK;
+       switch (div) {
+       case 16: ++i;
+       case 8:  ++i;
+       case 4:  ++i;
+       case 2:  ++i;
+                SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT);
+       case 1:  break;
+       default:
+               pr_debug("ssi: invalid sck divider %d\n", div);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+       unsigned long ssicr = SSIREG(SSICR);
+
+       pr_debug("ssi_set_fmt()\nssicr was    0x%08lx\n", ssicr);
+
+       ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP |
+                  CR_SWS_MASTER | CR_SCK_MASTER);
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               ssicr |= CR_DEL | CR_PDTA;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ssicr |= CR_DEL;
+               break;
+       default:
+               pr_debug("ssi: unsupported format\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+       case SND_SOC_DAIFMT_CONT:
+               break;
+       case SND_SOC_DAIFMT_GATED:
+               ssicr |= CR_BREN;
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               ssicr |= CR_SCKP;       /* sample data at low clkedge */
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               ssicr |= CR_SCKP | CR_SWSP;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               ssicr |= CR_SWSP;       /* word select starts low */
+               break;
+       default:
+               pr_debug("ssi: invalid inversion\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
+               break;
+       case SND_SOC_DAIFMT_BP_FC:
+               ssicr |= CR_SCK_MASTER;
+               break;
+       case SND_SOC_DAIFMT_BC_FP:
+               ssicr |= CR_SWS_MASTER;
+               break;
+       case SND_SOC_DAIFMT_BP_FP:
+               ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
+               break;
+       default:
+               pr_debug("ssi: invalid master/secondary configuration\n");
+               return -EINVAL;
+       }
+
+       SSIREG(SSICR) = ssicr;
+       pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr);
+
+       return 0;
+}
+
+/* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in
+ * Master mode,  so really this is board specific;  the SSI can do any
+ * rate with the right bitclk and divider settings.
+ */
+#define SSI_RATES      \
+       SNDRV_PCM_RATE_8000_192000
+
+/* the SSI can do 8-32 bit samples, with 8 possible channels */
+#define SSI_FMTS       \
+       (SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |  \
+        SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |  \
+        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |  \
+        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |  \
+        SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
+
+static const struct snd_soc_dai_ops ssi_dai_ops = {
+       .startup        = ssi_startup,
+       .shutdown       = ssi_shutdown,
+       .trigger        = ssi_trigger,
+       .hw_params      = ssi_hw_params,
+       .set_sysclk     = ssi_set_sysclk,
+       .set_clkdiv     = ssi_set_clkdiv,
+       .set_fmt        = ssi_set_fmt,
+};
+
+static struct snd_soc_dai_driver sh4_ssi_dai[] = {
+{
+       .name                   = "ssi-dai.0",
+       .playback = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .capture = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .ops = &ssi_dai_ops,
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+       .name                   = "ssi-dai.1",
+       .playback = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .capture = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .ops = &ssi_dai_ops,
+},
+#endif
+};
+
+static const struct snd_soc_component_driver sh4_ssi_component = {
+       .name                   = "sh4-ssi",
+       .legacy_dai_naming      = 1,
+};
+
+static int sh4_soc_dai_probe(struct platform_device *pdev)
+{
+       return devm_snd_soc_register_component(&pdev->dev, &sh4_ssi_component,
+                                              sh4_ssi_dai,
+                                              ARRAY_SIZE(sh4_ssi_dai));
+}
+
+static struct platform_driver sh4_ssi_driver = {
+       .driver = {
+                       .name = "sh4-ssi-dai",
+       },
+
+       .probe = sh4_soc_dai_probe,
+};
+
+module_platform_driver(sh4_ssi_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
deleted file mode 100644 (file)
index 4266329..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-menu "SoC Audio support for Renesas SoCs"
-       depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
-
-config SND_SOC_PCM_SH7760
-       tristate "SoC Audio support for Renesas SH7760"
-       depends on CPU_SUBTYPE_SH7760 && SH_DMABRG
-       help
-         Enable this option for SH7760 AC97/I2S audio support.
-
-
-##
-## Audio unit modules
-##
-
-config SND_SOC_SH4_HAC
-       tristate
-       select AC97_BUS
-       select SND_SOC_AC97_BUS
-
-config SND_SOC_SH4_SSI
-       tristate
-
-config SND_SOC_SH4_FSI
-       tristate "SH4 FSI support"
-       depends on SUPERH || COMMON_CLK
-       select SND_SIMPLE_CARD
-       help
-         This option enables FSI sound support
-
-config SND_SOC_SH4_SIU
-       tristate
-       depends on ARCH_SHMOBILE && HAVE_CLK
-       depends on DMADEVICES
-       select DMA_ENGINE
-       select SH_DMAE
-       select FW_LOADER
-
-config SND_SOC_RCAR
-       tristate "R-Car series SRU/SCU/SSIU/SSI support"
-       depends on COMMON_CLK
-       depends on OF
-       select SND_SIMPLE_CARD_UTILS
-       select SND_DMAENGINE_PCM
-       select REGMAP_MMIO
-       help
-         This option enables R-Car SRU/SCU/SSIU/SSI sound support
-
-config SND_SOC_RZ
-       tristate "RZ/G2L series SSIF-2 support"
-       depends on ARCH_RZG2L || COMPILE_TEST
-       help
-         This option enables RZ/G2L SSIF-2 sound support.
-
-##
-## Boards
-##
-
-config SND_SH7760_AC97
-       tristate "SH7760 AC97 sound support"
-       depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760
-       select SND_SOC_SH4_HAC
-       select SND_SOC_AC97_CODEC
-       help
-         This option enables generic sound support for the first
-         AC97 unit of the SH7760.
-
-config SND_SIU_MIGOR
-       tristate "SIU sound support on Migo-R"
-       depends on SH_MIGOR && I2C
-       select SND_SOC_SH4_SIU
-       select SND_SOC_WM8978
-       help
-         This option enables sound support for the SH7722 Migo-R board
-
-endmenu
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
deleted file mode 100644 (file)
index f0e19cb..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-## DMA engines
-snd-soc-dma-sh7760-y           := dma-sh7760.o
-obj-$(CONFIG_SND_SOC_PCM_SH7760)       += snd-soc-dma-sh7760.o
-
-## audio units found on some SH-4
-snd-soc-hac-y          := hac.o
-snd-soc-ssi-y          := ssi.o
-snd-soc-fsi-y          := fsi.o
-snd-soc-siu-y          := siu_pcm.o siu_dai.o
-obj-$(CONFIG_SND_SOC_SH4_HAC)  += snd-soc-hac.o
-obj-$(CONFIG_SND_SOC_SH4_SSI)  += snd-soc-ssi.o
-obj-$(CONFIG_SND_SOC_SH4_FSI)  += snd-soc-fsi.o
-obj-$(CONFIG_SND_SOC_SH4_SIU)  += snd-soc-siu.o
-
-## audio units for R-Car
-obj-$(CONFIG_SND_SOC_RCAR)     += rcar/
-
-## boards
-snd-soc-sh7760-ac97-y          := sh7760-ac97.o
-snd-soc-migor-y                        := migor.o
-
-obj-$(CONFIG_SND_SH7760_AC97)  += snd-soc-sh7760-ac97.o
-obj-$(CONFIG_SND_SIU_MIGOR)    += snd-soc-migor.o
-
-# RZ/G2L
-snd-soc-rz-ssi-y               := rz-ssi.o
-obj-$(CONFIG_SND_SOC_RZ)       += snd-soc-rz-ssi.o
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
deleted file mode 100644 (file)
index c535394..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// SH7760 ("camelot") DMABRG audio DMA unit support
-//
-// Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
-//
-// The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
-// trigger an interrupt when one half of the programmed transfer size
-// has been xmitted.
-//
-// FIXME: little-endian only for now
-
-#include <linux/module.h>
-#include <linux/gfp.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <asm/dmabrg.h>
-
-
-/* registers and bits */
-#define BRGATXSAR      0x00
-#define BRGARXDAR      0x04
-#define BRGATXTCR      0x08
-#define BRGARXTCR      0x0C
-#define BRGACR         0x10
-#define BRGATXTCNT     0x14
-#define BRGARXTCNT     0x18
-
-#define ACR_RAR                (1 << 18)
-#define ACR_RDS                (1 << 17)
-#define ACR_RDE                (1 << 16)
-#define ACR_TAR                (1 << 2)
-#define ACR_TDS                (1 << 1)
-#define ACR_TDE                (1 << 0)
-
-/* receiver/transmitter data alignment */
-#define ACR_RAM_NONE   (0 << 24)
-#define ACR_RAM_4BYTE  (1 << 24)
-#define ACR_RAM_2WORD  (2 << 24)
-#define ACR_TAM_NONE   (0 << 8)
-#define ACR_TAM_4BYTE  (1 << 8)
-#define ACR_TAM_2WORD  (2 << 8)
-
-
-struct camelot_pcm {
-       unsigned long mmio;  /* DMABRG audio channel control reg MMIO */
-       unsigned int txid;    /* ID of first DMABRG IRQ for this unit */
-
-       struct snd_pcm_substream *tx_ss;
-       unsigned long tx_period_size;
-       unsigned int  tx_period;
-
-       struct snd_pcm_substream *rx_ss;
-       unsigned long rx_period_size;
-       unsigned int  rx_period;
-
-} cam_pcm_data[2] = {
-       {
-               .mmio   =       0xFE3C0040,
-               .txid   =       DMABRGIRQ_A0TXF,
-       },
-       {
-               .mmio   =       0xFE3C0060,
-               .txid   =       DMABRGIRQ_A1TXF,
-       },
-};
-
-#define BRGREG(x)      (*(unsigned long *)(cam->mmio + (x)))
-
-/*
- * set a minimum of 16kb per period, to avoid interrupt-"storm" and
- * resulting skipping. In general, the bigger the minimum size, the
- * better for overall system performance. (The SH7760 is a puny CPU
- * with a slow SDRAM interface and poor internal bus bandwidth,
- * *especially* when the LCDC is active).  The minimum for the DMAC
- * is 8 bytes; 16kbytes are enough to get skip-free playback of a
- * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain
- * reasonable responsiveness in MPlayer.
- */
-#define DMABRG_PERIOD_MIN              16 * 1024
-#define DMABRG_PERIOD_MAX              0x03fffffc
-#define DMABRG_PREALLOC_BUFFER         32 * 1024
-#define DMABRG_PREALLOC_BUFFER_MAX     32 * 1024
-
-static const struct snd_pcm_hardware camelot_pcm_hardware = {
-       .info = (SNDRV_PCM_INFO_MMAP |
-               SNDRV_PCM_INFO_INTERLEAVED |
-               SNDRV_PCM_INFO_BLOCK_TRANSFER |
-               SNDRV_PCM_INFO_MMAP_VALID |
-               SNDRV_PCM_INFO_BATCH),
-       .buffer_bytes_max =     DMABRG_PERIOD_MAX,
-       .period_bytes_min =     DMABRG_PERIOD_MIN,
-       .period_bytes_max =     DMABRG_PERIOD_MAX / 2,
-       .periods_min =          2,
-       .periods_max =          2,
-       .fifo_size =            128,
-};
-
-static void camelot_txdma(void *data)
-{
-       struct camelot_pcm *cam = data;
-       cam->tx_period ^= 1;
-       snd_pcm_period_elapsed(cam->tx_ss);
-}
-
-static void camelot_rxdma(void *data)
-{
-       struct camelot_pcm *cam = data;
-       cam->rx_period ^= 1;
-       snd_pcm_period_elapsed(cam->rx_ss);
-}
-
-static int camelot_pcm_open(struct snd_soc_component *component,
-                           struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
-       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
-       int ret, dmairq;
-
-       snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware);
-
-       /* DMABRG buffer half/full events */
-       dmairq = (recv) ? cam->txid + 2 : cam->txid;
-       if (recv) {
-               cam->rx_ss = substream;
-               ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
-               if (unlikely(ret)) {
-                       pr_debug("audio unit %d irqs already taken!\n",
-                            snd_soc_rtd_to_cpu(rtd, 0)->id);
-                       return -EBUSY;
-               }
-               (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
-       } else {
-               cam->tx_ss = substream;
-               ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
-               if (unlikely(ret)) {
-                       pr_debug("audio unit %d irqs already taken!\n",
-                            snd_soc_rtd_to_cpu(rtd, 0)->id);
-                       return -EBUSY;
-               }
-               (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
-       }
-       return 0;
-}
-
-static int camelot_pcm_close(struct snd_soc_component *component,
-                            struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
-       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
-       int dmairq;
-
-       dmairq = (recv) ? cam->txid + 2 : cam->txid;
-
-       if (recv)
-               cam->rx_ss = NULL;
-       else
-               cam->tx_ss = NULL;
-
-       dmabrg_free_irq(dmairq + 1);
-       dmabrg_free_irq(dmairq);
-
-       return 0;
-}
-
-static int camelot_hw_params(struct snd_soc_component *component,
-                            struct snd_pcm_substream *substream,
-                            struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
-       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
-
-       if (recv) {
-               cam->rx_period_size = params_period_bytes(hw_params);
-               cam->rx_period = 0;
-       } else {
-               cam->tx_period_size = params_period_bytes(hw_params);
-               cam->tx_period = 0;
-       }
-       return 0;
-}
-
-static int camelot_prepare(struct snd_soc_component *component,
-                          struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
-
-       pr_debug("PCM data: addr %pad len %zu\n", &runtime->dma_addr,
-                runtime->dma_bytes);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
-               BRGREG(BRGATXTCR) = runtime->dma_bytes;
-       } else {
-               BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area;
-               BRGREG(BRGARXTCR) = runtime->dma_bytes;
-       }
-
-       return 0;
-}
-
-static inline void dmabrg_play_dma_start(struct camelot_pcm *cam)
-{
-       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
-       /* start DMABRG engine: XFER start, auto-addr-reload */
-       BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD;
-}
-
-static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam)
-{
-       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
-       /* forcibly terminate data transmission */
-       BRGREG(BRGACR) = acr | ACR_TDS;
-}
-
-static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam)
-{
-       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
-       /* start DMABRG engine: recv start, auto-reload */
-       BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD;
-}
-
-static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
-{
-       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
-       /* forcibly terminate data receiver */
-       BRGREG(BRGACR) = acr | ACR_RDS;
-}
-
-static int camelot_trigger(struct snd_soc_component *component,
-                          struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
-       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               if (recv)
-                       dmabrg_rec_dma_start(cam);
-               else
-                       dmabrg_play_dma_start(cam);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               if (recv)
-                       dmabrg_rec_dma_stop(cam);
-               else
-                       dmabrg_play_dma_stop(cam);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static snd_pcm_uframes_t camelot_pos(struct snd_soc_component *component,
-                                    struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-       struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id];
-       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
-       unsigned long pos;
-
-       /* cannot use the DMABRG pointer register: under load, by the
-        * time ALSA comes around to read the register, it is already
-        * far ahead (or worse, already done with the fragment) of the
-        * position at the time the IRQ was triggered, which results in
-        * fast-playback sound in my test application (ScummVM)
-        */
-       if (recv)
-               pos = cam->rx_period ? cam->rx_period_size : 0;
-       else
-               pos = cam->tx_period ? cam->tx_period_size : 0;
-
-       return bytes_to_frames(runtime, pos);
-}
-
-static int camelot_pcm_new(struct snd_soc_component *component,
-                          struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_pcm *pcm = rtd->pcm;
-
-       /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
-        * in MMAP mode (i.e. aplay -M)
-        */
-       snd_pcm_set_managed_buffer_all(pcm,
-               SNDRV_DMA_TYPE_CONTINUOUS,
-               NULL,
-               DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX);
-
-       return 0;
-}
-
-static const struct snd_soc_component_driver sh7760_soc_component = {
-       .open           = camelot_pcm_open,
-       .close          = camelot_pcm_close,
-       .hw_params      = camelot_hw_params,
-       .prepare        = camelot_prepare,
-       .trigger        = camelot_trigger,
-       .pointer        = camelot_pos,
-       .pcm_construct  = camelot_pcm_new,
-};
-
-static int sh7760_soc_platform_probe(struct platform_device *pdev)
-{
-       return devm_snd_soc_register_component(&pdev->dev, &sh7760_soc_component,
-                                              NULL, 0);
-}
-
-static struct platform_driver sh7760_pcm_driver = {
-       .driver = {
-                       .name = "sh7760-pcm-audio",
-       },
-
-       .probe = sh7760_soc_platform_probe,
-};
-
-module_platform_driver(sh7760_pcm_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
-MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
deleted file mode 100644 (file)
index 221ce91..0000000
+++ /dev/null
@@ -1,2119 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Fifo-attached Serial Interface (FSI) support for SH7724
-//
-// Copyright (C) 2009 Renesas Solutions Corp.
-// Kuninori Morimoto <morimoto.kuninori@renesas.com>
-//
-// Based on ssi.c
-// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
-
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/pm_runtime.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/scatterlist.h>
-#include <linux/sh_dma.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/workqueue.h>
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-#include <sound/sh_fsi.h>
-
-/* PortA/PortB register */
-#define REG_DO_FMT     0x0000
-#define REG_DOFF_CTL   0x0004
-#define REG_DOFF_ST    0x0008
-#define REG_DI_FMT     0x000C
-#define REG_DIFF_CTL   0x0010
-#define REG_DIFF_ST    0x0014
-#define REG_CKG1       0x0018
-#define REG_CKG2       0x001C
-#define REG_DIDT       0x0020
-#define REG_DODT       0x0024
-#define REG_MUTE_ST    0x0028
-#define REG_OUT_DMAC   0x002C
-#define REG_OUT_SEL    0x0030
-#define REG_IN_DMAC    0x0038
-
-/* master register */
-#define MST_CLK_RST    0x0210
-#define MST_SOFT_RST   0x0214
-#define MST_FIFO_SZ    0x0218
-
-/* core register (depend on FSI version) */
-#define A_MST_CTLR     0x0180
-#define B_MST_CTLR     0x01A0
-#define CPU_INT_ST     0x01F4
-#define CPU_IEMSK      0x01F8
-#define CPU_IMSK       0x01FC
-#define INT_ST         0x0200
-#define IEMSK          0x0204
-#define IMSK           0x0208
-
-/* DO_FMT */
-/* DI_FMT */
-#define CR_BWS_MASK    (0x3 << 20) /* FSI2 */
-#define CR_BWS_24      (0x0 << 20) /* FSI2 */
-#define CR_BWS_16      (0x1 << 20) /* FSI2 */
-#define CR_BWS_20      (0x2 << 20) /* FSI2 */
-
-#define CR_DTMD_PCM            (0x0 << 8) /* FSI2 */
-#define CR_DTMD_SPDIF_PCM      (0x1 << 8) /* FSI2 */
-#define CR_DTMD_SPDIF_STREAM   (0x2 << 8) /* FSI2 */
-
-#define CR_MONO                (0x0 << 4)
-#define CR_MONO_D      (0x1 << 4)
-#define CR_PCM         (0x2 << 4)
-#define CR_I2S         (0x3 << 4)
-#define CR_TDM         (0x4 << 4)
-#define CR_TDM_D       (0x5 << 4)
-
-/* OUT_DMAC */
-/* IN_DMAC */
-#define VDMD_MASK      (0x3 << 4)
-#define VDMD_FRONT     (0x0 << 4) /* Package in front */
-#define VDMD_BACK      (0x1 << 4) /* Package in back */
-#define VDMD_STREAM    (0x2 << 4) /* Stream mode(16bit * 2) */
-
-#define DMA_ON         (0x1 << 0)
-
-/* DOFF_CTL */
-/* DIFF_CTL */
-#define IRQ_HALF       0x00100000
-#define FIFO_CLR       0x00000001
-
-/* DOFF_ST */
-#define ERR_OVER       0x00000010
-#define ERR_UNDER      0x00000001
-#define ST_ERR         (ERR_OVER | ERR_UNDER)
-
-/* CKG1 */
-#define ACKMD_MASK     0x00007000
-#define BPFMD_MASK     0x00000700
-#define DIMD           (1 << 4)
-#define DOMD           (1 << 0)
-
-/* A/B MST_CTLR */
-#define BP     (1 << 4)        /* Fix the signal of Biphase output */
-#define SE     (1 << 0)        /* Fix the master clock */
-
-/* CLK_RST */
-#define CRB    (1 << 4)
-#define CRA    (1 << 0)
-
-/* IO SHIFT / MACRO */
-#define BI_SHIFT       12
-#define BO_SHIFT       8
-#define AI_SHIFT       4
-#define AO_SHIFT       0
-#define AB_IO(param, shift)    (param << shift)
-
-/* SOFT_RST */
-#define PBSR           (1 << 12) /* Port B Software Reset */
-#define PASR           (1 <<  8) /* Port A Software Reset */
-#define IR             (1 <<  4) /* Interrupt Reset */
-#define FSISR          (1 <<  0) /* Software Reset */
-
-/* OUT_SEL (FSI2) */
-#define DMMD           (1 << 4) /* SPDIF output timing 0: Biphase only */
-                                /*                     1: Biphase and serial */
-
-/* FIFO_SZ */
-#define FIFO_SZ_MASK   0x7
-
-#define FSI_RATES SNDRV_PCM_RATE_8000_96000
-
-#define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
-
-/*
- * bus options
- *
- * 0x000000BA
- *
- * A : sample widtht 16bit setting
- * B : sample widtht 24bit setting
- */
-
-#define SHIFT_16DATA           0
-#define SHIFT_24DATA           4
-
-#define PACKAGE_24BITBUS_BACK          0
-#define PACKAGE_24BITBUS_FRONT         1
-#define PACKAGE_16BITBUS_STREAM                2
-
-#define BUSOP_SET(s, a)        ((a) << SHIFT_ ## s ## DATA)
-#define BUSOP_GET(s, a)        (((a) >> SHIFT_ ## s ## DATA) & 0xF)
-
-/*
- * FSI driver use below type name for variable
- *
- * xxx_num     : number of data
- * xxx_pos     : position of data
- * xxx_capa    : capacity of data
- */
-
-/*
- *     period/frame/sample image
- *
- * ex) PCM (2ch)
- *
- * period pos                                     period pos
- *   [n]                                            [n + 1]
- *   |<-------------------- period--------------------->|
- * ==|============================================ ... =|==
- *   |                                                 |
- *   ||<-----  frame ----->|<------ frame ----->|  ... |
- *   |+--------------------+--------------------+- ... |
- *   ||[ sample ][ sample ]|[ sample ][ sample ]|  ... |
- *   |+--------------------+--------------------+- ... |
- * ==|============================================ ... =|==
- */
-
-/*
- *     FSI FIFO image
- *
- *     |            |
- *     |            |
- *     | [ sample ] |
- *     | [ sample ] |
- *     | [ sample ] |
- *     | [ sample ] |
- *             --> go to codecs
- */
-
-/*
- *     FSI clock
- *
- * FSIxCLK [CPG] (ick) ------->        |
- *                             |-> FSI_DIV (div)-> FSI2
- * FSIxCK [external] (xck) --->        |
- */
-
-/*
- *             struct
- */
-
-struct fsi_stream_handler;
-struct fsi_stream {
-
-       /*
-        * these are initialized by fsi_stream_init()
-        */
-       struct snd_pcm_substream *substream;
-       int fifo_sample_capa;   /* sample capacity of FSI FIFO */
-       int buff_sample_capa;   /* sample capacity of ALSA buffer */
-       int buff_sample_pos;    /* sample position of ALSA buffer */
-       int period_samples;     /* sample number / 1 period */
-       int period_pos;         /* current period position */
-       int sample_width;       /* sample width */
-       int uerr_num;
-       int oerr_num;
-
-       /*
-        * bus options
-        */
-       u32 bus_option;
-
-       /*
-        * these are initialized by fsi_handler_init()
-        */
-       struct fsi_stream_handler *handler;
-       struct fsi_priv         *priv;
-
-       /*
-        * these are for DMAEngine
-        */
-       struct dma_chan         *chan;
-       int                     dma_id;
-};
-
-struct fsi_clk {
-       /* see [FSI clock] */
-       struct clk *own;
-       struct clk *xck;
-       struct clk *ick;
-       struct clk *div;
-       int (*set_rate)(struct device *dev,
-                       struct fsi_priv *fsi);
-
-       unsigned long rate;
-       unsigned int count;
-};
-
-struct fsi_priv {
-       void __iomem *base;
-       phys_addr_t phys;
-       struct fsi_master *master;
-
-       struct fsi_stream playback;
-       struct fsi_stream capture;
-
-       struct fsi_clk clock;
-
-       u32 fmt;
-
-       int chan_num:16;
-       unsigned int clk_master:1;
-       unsigned int clk_cpg:1;
-       unsigned int spdif:1;
-       unsigned int enable_stream:1;
-       unsigned int bit_clk_inv:1;
-       unsigned int lr_clk_inv:1;
-};
-
-struct fsi_stream_handler {
-       int (*init)(struct fsi_priv *fsi, struct fsi_stream *io);
-       int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io);
-       int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev);
-       int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
-       int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
-       int (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
-                          int enable);
-};
-#define fsi_stream_handler_call(io, func, args...)     \
-       (!(io) ? -ENODEV :                              \
-        !((io)->handler->func) ? 0 :                   \
-        (io)->handler->func(args))
-
-struct fsi_core {
-       int ver;
-
-       u32 int_st;
-       u32 iemsk;
-       u32 imsk;
-       u32 a_mclk;
-       u32 b_mclk;
-};
-
-struct fsi_master {
-       void __iomem *base;
-       struct fsi_priv fsia;
-       struct fsi_priv fsib;
-       const struct fsi_core *core;
-       spinlock_t lock;
-};
-
-static inline int fsi_stream_is_play(struct fsi_priv *fsi,
-                                    struct fsi_stream *io)
-{
-       return &fsi->playback == io;
-}
-
-
-/*
- *             basic read write function
- */
-
-static void __fsi_reg_write(u32 __iomem *reg, u32 data)
-{
-       /* valid data area is 24bit */
-       data &= 0x00ffffff;
-
-       __raw_writel(data, reg);
-}
-
-static u32 __fsi_reg_read(u32 __iomem *reg)
-{
-       return __raw_readl(reg);
-}
-
-static void __fsi_reg_mask_set(u32 __iomem *reg, u32 mask, u32 data)
-{
-       u32 val = __fsi_reg_read(reg);
-
-       val &= ~mask;
-       val |= data & mask;
-
-       __fsi_reg_write(reg, val);
-}
-
-#define fsi_reg_write(p, r, d)\
-       __fsi_reg_write((p->base + REG_##r), d)
-
-#define fsi_reg_read(p, r)\
-       __fsi_reg_read((p->base + REG_##r))
-
-#define fsi_reg_mask_set(p, r, m, d)\
-       __fsi_reg_mask_set((p->base + REG_##r), m, d)
-
-#define fsi_master_read(p, r) _fsi_master_read(p, MST_##r)
-#define fsi_core_read(p, r)   _fsi_master_read(p, p->core->r)
-static u32 _fsi_master_read(struct fsi_master *master, u32 reg)
-{
-       u32 ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&master->lock, flags);
-       ret = __fsi_reg_read(master->base + reg);
-       spin_unlock_irqrestore(&master->lock, flags);
-
-       return ret;
-}
-
-#define fsi_master_mask_set(p, r, m, d) _fsi_master_mask_set(p, MST_##r, m, d)
-#define fsi_core_mask_set(p, r, m, d)  _fsi_master_mask_set(p, p->core->r, m, d)
-static void _fsi_master_mask_set(struct fsi_master *master,
-                              u32 reg, u32 mask, u32 data)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&master->lock, flags);
-       __fsi_reg_mask_set(master->base + reg, mask, data);
-       spin_unlock_irqrestore(&master->lock, flags);
-}
-
-/*
- *             basic function
- */
-static int fsi_version(struct fsi_master *master)
-{
-       return master->core->ver;
-}
-
-static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
-{
-       return fsi->master;
-}
-
-static int fsi_is_clk_master(struct fsi_priv *fsi)
-{
-       return fsi->clk_master;
-}
-
-static int fsi_is_port_a(struct fsi_priv *fsi)
-{
-       return fsi->master->base == fsi->base;
-}
-
-static int fsi_is_spdif(struct fsi_priv *fsi)
-{
-       return fsi->spdif;
-}
-
-static int fsi_is_enable_stream(struct fsi_priv *fsi)
-{
-       return fsi->enable_stream;
-}
-
-static int fsi_is_play(struct snd_pcm_substream *substream)
-{
-       return substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-}
-
-static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-
-       return  snd_soc_rtd_to_cpu(rtd, 0);
-}
-
-static struct fsi_priv *fsi_get_priv_frm_dai(struct snd_soc_dai *dai)
-{
-       struct fsi_master *master = snd_soc_dai_get_drvdata(dai);
-
-       if (dai->id == 0)
-               return &master->fsia;
-       else
-               return &master->fsib;
-}
-
-static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
-{
-       return fsi_get_priv_frm_dai(fsi_get_dai(substream));
-}
-
-static u32 fsi_get_port_shift(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       int is_play = fsi_stream_is_play(fsi, io);
-       int is_porta = fsi_is_port_a(fsi);
-       u32 shift;
-
-       if (is_porta)
-               shift = is_play ? AO_SHIFT : AI_SHIFT;
-       else
-               shift = is_play ? BO_SHIFT : BI_SHIFT;
-
-       return shift;
-}
-
-static int fsi_frame2sample(struct fsi_priv *fsi, int frames)
-{
-       return frames * fsi->chan_num;
-}
-
-static int fsi_sample2frame(struct fsi_priv *fsi, int samples)
-{
-       return samples / fsi->chan_num;
-}
-
-static int fsi_get_current_fifo_samples(struct fsi_priv *fsi,
-                                       struct fsi_stream *io)
-{
-       int is_play = fsi_stream_is_play(fsi, io);
-       u32 status;
-       int frames;
-
-       status = is_play ?
-               fsi_reg_read(fsi, DOFF_ST) :
-               fsi_reg_read(fsi, DIFF_ST);
-
-       frames = 0x1ff & (status >> 8);
-
-       return fsi_frame2sample(fsi, frames);
-}
-
-static void fsi_count_fifo_err(struct fsi_priv *fsi)
-{
-       u32 ostatus = fsi_reg_read(fsi, DOFF_ST);
-       u32 istatus = fsi_reg_read(fsi, DIFF_ST);
-
-       if (ostatus & ERR_OVER)
-               fsi->playback.oerr_num++;
-
-       if (ostatus & ERR_UNDER)
-               fsi->playback.uerr_num++;
-
-       if (istatus & ERR_OVER)
-               fsi->capture.oerr_num++;
-
-       if (istatus & ERR_UNDER)
-               fsi->capture.uerr_num++;
-
-       fsi_reg_write(fsi, DOFF_ST, 0);
-       fsi_reg_write(fsi, DIFF_ST, 0);
-}
-
-/*
- *             fsi_stream_xx() function
- */
-static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi,
-                                       struct snd_pcm_substream *substream)
-{
-       return fsi_is_play(substream) ? &fsi->playback : &fsi->capture;
-}
-
-static int fsi_stream_is_working(struct fsi_priv *fsi,
-                                struct fsi_stream *io)
-{
-       struct fsi_master *master = fsi_get_master(fsi);
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&master->lock, flags);
-       ret = !!(io->substream && io->substream->runtime);
-       spin_unlock_irqrestore(&master->lock, flags);
-
-       return ret;
-}
-
-static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io)
-{
-       return io->priv;
-}
-
-static void fsi_stream_init(struct fsi_priv *fsi,
-                           struct fsi_stream *io,
-                           struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct fsi_master *master = fsi_get_master(fsi);
-       unsigned long flags;
-
-       spin_lock_irqsave(&master->lock, flags);
-       io->substream   = substream;
-       io->buff_sample_capa    = fsi_frame2sample(fsi, runtime->buffer_size);
-       io->buff_sample_pos     = 0;
-       io->period_samples      = fsi_frame2sample(fsi, runtime->period_size);
-       io->period_pos          = 0;
-       io->sample_width        = samples_to_bytes(runtime, 1);
-       io->bus_option          = 0;
-       io->oerr_num    = -1; /* ignore 1st err */
-       io->uerr_num    = -1; /* ignore 1st err */
-       fsi_stream_handler_call(io, init, fsi, io);
-       spin_unlock_irqrestore(&master->lock, flags);
-}
-
-static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       struct snd_soc_dai *dai = fsi_get_dai(io->substream);
-       struct fsi_master *master = fsi_get_master(fsi);
-       unsigned long flags;
-
-       spin_lock_irqsave(&master->lock, flags);
-
-       if (io->oerr_num > 0)
-               dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
-
-       if (io->uerr_num > 0)
-               dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
-
-       fsi_stream_handler_call(io, quit, fsi, io);
-       io->substream   = NULL;
-       io->buff_sample_capa    = 0;
-       io->buff_sample_pos     = 0;
-       io->period_samples      = 0;
-       io->period_pos          = 0;
-       io->sample_width        = 0;
-       io->bus_option          = 0;
-       io->oerr_num    = 0;
-       io->uerr_num    = 0;
-       spin_unlock_irqrestore(&master->lock, flags);
-}
-
-static int fsi_stream_transfer(struct fsi_stream *io)
-{
-       struct fsi_priv *fsi = fsi_stream_to_priv(io);
-       if (!fsi)
-               return -EIO;
-
-       return fsi_stream_handler_call(io, transfer, fsi, io);
-}
-
-#define fsi_stream_start(fsi, io)\
-       fsi_stream_handler_call(io, start_stop, fsi, io, 1)
-
-#define fsi_stream_stop(fsi, io)\
-       fsi_stream_handler_call(io, start_stop, fsi, io, 0)
-
-static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev)
-{
-       struct fsi_stream *io;
-       int ret1, ret2;
-
-       io = &fsi->playback;
-       ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev);
-
-       io = &fsi->capture;
-       ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev);
-
-       if (ret1 < 0)
-               return ret1;
-       if (ret2 < 0)
-               return ret2;
-
-       return 0;
-}
-
-static int fsi_stream_remove(struct fsi_priv *fsi)
-{
-       struct fsi_stream *io;
-       int ret1, ret2;
-
-       io = &fsi->playback;
-       ret1 = fsi_stream_handler_call(io, remove, fsi, io);
-
-       io = &fsi->capture;
-       ret2 = fsi_stream_handler_call(io, remove, fsi, io);
-
-       if (ret1 < 0)
-               return ret1;
-       if (ret2 < 0)
-               return ret2;
-
-       return 0;
-}
-
-/*
- *     format/bus/dma setting
- */
-static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io,
-                                u32 bus, struct device *dev)
-{
-       struct fsi_master *master = fsi_get_master(fsi);
-       int is_play = fsi_stream_is_play(fsi, io);
-       u32 fmt = fsi->fmt;
-
-       if (fsi_version(master) >= 2) {
-               u32 dma = 0;
-
-               /*
-                * FSI2 needs DMA/Bus setting
-                */
-               switch (bus) {
-               case PACKAGE_24BITBUS_FRONT:
-                       fmt |= CR_BWS_24;
-                       dma |= VDMD_FRONT;
-                       dev_dbg(dev, "24bit bus / package in front\n");
-                       break;
-               case PACKAGE_16BITBUS_STREAM:
-                       fmt |= CR_BWS_16;
-                       dma |= VDMD_STREAM;
-                       dev_dbg(dev, "16bit bus / stream mode\n");
-                       break;
-               case PACKAGE_24BITBUS_BACK:
-               default:
-                       fmt |= CR_BWS_24;
-                       dma |= VDMD_BACK;
-                       dev_dbg(dev, "24bit bus / package in back\n");
-                       break;
-               }
-
-               if (is_play)
-                       fsi_reg_write(fsi, OUT_DMAC,    dma);
-               else
-                       fsi_reg_write(fsi, IN_DMAC,     dma);
-       }
-
-       if (is_play)
-               fsi_reg_write(fsi, DO_FMT, fmt);
-       else
-               fsi_reg_write(fsi, DI_FMT, fmt);
-}
-
-/*
- *             irq function
- */
-
-static void fsi_irq_enable(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       u32 data = AB_IO(1, fsi_get_port_shift(fsi, io));
-       struct fsi_master *master = fsi_get_master(fsi);
-
-       fsi_core_mask_set(master, imsk,  data, data);
-       fsi_core_mask_set(master, iemsk, data, data);
-}
-
-static void fsi_irq_disable(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       u32 data = AB_IO(1, fsi_get_port_shift(fsi, io));
-       struct fsi_master *master = fsi_get_master(fsi);
-
-       fsi_core_mask_set(master, imsk,  data, 0);
-       fsi_core_mask_set(master, iemsk, data, 0);
-}
-
-static u32 fsi_irq_get_status(struct fsi_master *master)
-{
-       return fsi_core_read(master, int_st);
-}
-
-static void fsi_irq_clear_status(struct fsi_priv *fsi)
-{
-       u32 data = 0;
-       struct fsi_master *master = fsi_get_master(fsi);
-
-       data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->playback));
-       data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->capture));
-
-       /* clear interrupt factor */
-       fsi_core_mask_set(master, int_st, data, 0);
-}
-
-/*
- *             SPDIF master clock function
- *
- * These functions are used later FSI2
- */
-static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
-{
-       struct fsi_master *master = fsi_get_master(fsi);
-       u32 mask, val;
-
-       mask = BP | SE;
-       val = enable ? mask : 0;
-
-       fsi_is_port_a(fsi) ?
-               fsi_core_mask_set(master, a_mclk, mask, val) :
-               fsi_core_mask_set(master, b_mclk, mask, val);
-}
-
-/*
- *             clock function
- */
-static int fsi_clk_init(struct device *dev,
-                       struct fsi_priv *fsi,
-                       int xck,
-                       int ick,
-                       int div,
-                       int (*set_rate)(struct device *dev,
-                                       struct fsi_priv *fsi))
-{
-       struct fsi_clk *clock = &fsi->clock;
-       int is_porta = fsi_is_port_a(fsi);
-
-       clock->xck      = NULL;
-       clock->ick      = NULL;
-       clock->div      = NULL;
-       clock->rate     = 0;
-       clock->count    = 0;
-       clock->set_rate = set_rate;
-
-       clock->own = devm_clk_get(dev, NULL);
-       if (IS_ERR(clock->own))
-               return -EINVAL;
-
-       /* external clock */
-       if (xck) {
-               clock->xck = devm_clk_get(dev, is_porta ? "xcka" : "xckb");
-               if (IS_ERR(clock->xck)) {
-                       dev_err(dev, "can't get xck clock\n");
-                       return -EINVAL;
-               }
-               if (clock->xck == clock->own) {
-                       dev_err(dev, "cpu doesn't support xck clock\n");
-                       return -EINVAL;
-               }
-       }
-
-       /* FSIACLK/FSIBCLK */
-       if (ick) {
-               clock->ick = devm_clk_get(dev,  is_porta ? "icka" : "ickb");
-               if (IS_ERR(clock->ick)) {
-                       dev_err(dev, "can't get ick clock\n");
-                       return -EINVAL;
-               }
-               if (clock->ick == clock->own) {
-                       dev_err(dev, "cpu doesn't support ick clock\n");
-                       return -EINVAL;
-               }
-       }
-
-       /* FSI-DIV */
-       if (div) {
-               clock->div = devm_clk_get(dev,  is_porta ? "diva" : "divb");
-               if (IS_ERR(clock->div)) {
-                       dev_err(dev, "can't get div clock\n");
-                       return -EINVAL;
-               }
-               if (clock->div == clock->own) {
-                       dev_err(dev, "cpu doesn't support div clock\n");
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-
-#define fsi_clk_invalid(fsi) fsi_clk_valid(fsi, 0)
-static void fsi_clk_valid(struct fsi_priv *fsi, unsigned long rate)
-{
-       fsi->clock.rate = rate;
-}
-
-static int fsi_clk_is_valid(struct fsi_priv *fsi)
-{
-       return  fsi->clock.set_rate &&
-               fsi->clock.rate;
-}
-
-static int fsi_clk_enable(struct device *dev,
-                         struct fsi_priv *fsi)
-{
-       struct fsi_clk *clock = &fsi->clock;
-       int ret = -EINVAL;
-
-       if (!fsi_clk_is_valid(fsi))
-               return ret;
-
-       if (0 == clock->count) {
-               ret = clock->set_rate(dev, fsi);
-               if (ret < 0) {
-                       fsi_clk_invalid(fsi);
-                       return ret;
-               }
-
-               ret = clk_enable(clock->xck);
-               if (ret)
-                       goto err;
-               ret = clk_enable(clock->ick);
-               if (ret)
-                       goto disable_xck;
-               ret = clk_enable(clock->div);
-               if (ret)
-                       goto disable_ick;
-
-               clock->count++;
-       }
-
-       return ret;
-
-disable_ick:
-       clk_disable(clock->ick);
-disable_xck:
-       clk_disable(clock->xck);
-err:
-       return ret;
-}
-
-static int fsi_clk_disable(struct device *dev,
-                           struct fsi_priv *fsi)
-{
-       struct fsi_clk *clock = &fsi->clock;
-
-       if (!fsi_clk_is_valid(fsi))
-               return -EINVAL;
-
-       if (1 == clock->count--) {
-               clk_disable(clock->xck);
-               clk_disable(clock->ick);
-               clk_disable(clock->div);
-       }
-
-       return 0;
-}
-
-static int fsi_clk_set_ackbpf(struct device *dev,
-                             struct fsi_priv *fsi,
-                             int ackmd, int bpfmd)
-{
-       u32 data = 0;
-
-       /* check ackmd/bpfmd relationship */
-       if (bpfmd > ackmd) {
-               dev_err(dev, "unsupported rate (%d/%d)\n", ackmd, bpfmd);
-               return -EINVAL;
-       }
-
-       /*  ACKMD */
-       switch (ackmd) {
-       case 512:
-               data |= (0x0 << 12);
-               break;
-       case 256:
-               data |= (0x1 << 12);
-               break;
-       case 128:
-               data |= (0x2 << 12);
-               break;
-       case 64:
-               data |= (0x3 << 12);
-               break;
-       case 32:
-               data |= (0x4 << 12);
-               break;
-       default:
-               dev_err(dev, "unsupported ackmd (%d)\n", ackmd);
-               return -EINVAL;
-       }
-
-       /* BPFMD */
-       switch (bpfmd) {
-       case 32:
-               data |= (0x0 << 8);
-               break;
-       case 64:
-               data |= (0x1 << 8);
-               break;
-       case 128:
-               data |= (0x2 << 8);
-               break;
-       case 256:
-               data |= (0x3 << 8);
-               break;
-       case 512:
-               data |= (0x4 << 8);
-               break;
-       case 16:
-               data |= (0x7 << 8);
-               break;
-       default:
-               dev_err(dev, "unsupported bpfmd (%d)\n", bpfmd);
-               return -EINVAL;
-       }
-
-       dev_dbg(dev, "ACKMD/BPFMD = %d/%d\n", ackmd, bpfmd);
-
-       fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
-       udelay(10);
-
-       return 0;
-}
-
-static int fsi_clk_set_rate_external(struct device *dev,
-                                    struct fsi_priv *fsi)
-{
-       struct clk *xck = fsi->clock.xck;
-       struct clk *ick = fsi->clock.ick;
-       unsigned long rate = fsi->clock.rate;
-       unsigned long xrate;
-       int ackmd, bpfmd;
-       int ret = 0;
-
-       /* check clock rate */
-       xrate = clk_get_rate(xck);
-       if (xrate % rate) {
-               dev_err(dev, "unsupported clock rate\n");
-               return -EINVAL;
-       }
-
-       clk_set_parent(ick, xck);
-       clk_set_rate(ick, xrate);
-
-       bpfmd = fsi->chan_num * 32;
-       ackmd = xrate / rate;
-
-       dev_dbg(dev, "external/rate = %ld/%ld\n", xrate, rate);
-
-       ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd);
-       if (ret < 0)
-               dev_err(dev, "%s failed", __func__);
-
-       return ret;
-}
-
-static int fsi_clk_set_rate_cpg(struct device *dev,
-                               struct fsi_priv *fsi)
-{
-       struct clk *ick = fsi->clock.ick;
-       struct clk *div = fsi->clock.div;
-       unsigned long rate = fsi->clock.rate;
-       unsigned long target = 0; /* 12288000 or 11289600 */
-       unsigned long actual, cout;
-       unsigned long diff, min;
-       unsigned long best_cout, best_act;
-       int adj;
-       int ackmd, bpfmd;
-       int ret = -EINVAL;
-
-       if (!(12288000 % rate))
-               target = 12288000;
-       if (!(11289600 % rate))
-               target = 11289600;
-       if (!target) {
-               dev_err(dev, "unsupported rate\n");
-               return ret;
-       }
-
-       bpfmd = fsi->chan_num * 32;
-       ackmd = target / rate;
-       ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd);
-       if (ret < 0) {
-               dev_err(dev, "%s failed", __func__);
-               return ret;
-       }
-
-       /*
-        * The clock flow is
-        *
-        * [CPG] = cout => [FSI_DIV] = audio => [FSI] => [codec]
-        *
-        * But, it needs to find best match of CPG and FSI_DIV
-        * combination, since it is difficult to generate correct
-        * frequency of audio clock from ick clock only.
-        * Because ick is created from its parent clock.
-        *
-        * target       = rate x [512/256/128/64]fs
-        * cout         = round(target x adjustment)
-        * actual       = cout / adjustment (by FSI-DIV) ~= target
-        * audio        = actual
-        */
-       min = ~0;
-       best_cout = 0;
-       best_act = 0;
-       for (adj = 1; adj < 0xffff; adj++) {
-
-               cout = target * adj;
-               if (cout > 100000000) /* max clock = 100MHz */
-                       break;
-
-               /* cout/actual audio clock */
-               cout    = clk_round_rate(ick, cout);
-               actual  = cout / adj;
-
-               /* find best frequency */
-               diff = abs(actual - target);
-               if (diff < min) {
-                       min             = diff;
-                       best_cout       = cout;
-                       best_act        = actual;
-               }
-       }
-
-       ret = clk_set_rate(ick, best_cout);
-       if (ret < 0) {
-               dev_err(dev, "ick clock failed\n");
-               return -EIO;
-       }
-
-       ret = clk_set_rate(div, clk_round_rate(div, best_act));
-       if (ret < 0) {
-               dev_err(dev, "div clock failed\n");
-               return -EIO;
-       }
-
-       dev_dbg(dev, "ick/div = %ld/%ld\n",
-               clk_get_rate(ick), clk_get_rate(div));
-
-       return ret;
-}
-
-static void fsi_pointer_update(struct fsi_stream *io, int size)
-{
-       io->buff_sample_pos += size;
-
-       if (io->buff_sample_pos >=
-           io->period_samples * (io->period_pos + 1)) {
-               struct snd_pcm_substream *substream = io->substream;
-               struct snd_pcm_runtime *runtime = substream->runtime;
-
-               io->period_pos++;
-
-               if (io->period_pos >= runtime->periods) {
-                       io->buff_sample_pos = 0;
-                       io->period_pos = 0;
-               }
-
-               snd_pcm_period_elapsed(substream);
-       }
-}
-
-/*
- *             pio data transfer handler
- */
-static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples)
-{
-       int i;
-
-       if (fsi_is_enable_stream(fsi)) {
-               /*
-                * stream mode
-                * see
-                *      fsi_pio_push_init()
-                */
-               u32 *buf = (u32 *)_buf;
-
-               for (i = 0; i < samples / 2; i++)
-                       fsi_reg_write(fsi, DODT, buf[i]);
-       } else {
-               /* normal mode */
-               u16 *buf = (u16 *)_buf;
-
-               for (i = 0; i < samples; i++)
-                       fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
-       }
-}
-
-static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples)
-{
-       u16 *buf = (u16 *)_buf;
-       int i;
-
-       for (i = 0; i < samples; i++)
-               *(buf + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8);
-}
-
-static void fsi_pio_push32(struct fsi_priv *fsi, u8 *_buf, int samples)
-{
-       u32 *buf = (u32 *)_buf;
-       int i;
-
-       for (i = 0; i < samples; i++)
-               fsi_reg_write(fsi, DODT, *(buf + i));
-}
-
-static void fsi_pio_pop32(struct fsi_priv *fsi, u8 *_buf, int samples)
-{
-       u32 *buf = (u32 *)_buf;
-       int i;
-
-       for (i = 0; i < samples; i++)
-               *(buf + i) = fsi_reg_read(fsi, DIDT);
-}
-
-static u8 *fsi_pio_get_area(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       struct snd_pcm_runtime *runtime = io->substream->runtime;
-
-       return runtime->dma_area +
-               samples_to_bytes(runtime, io->buff_sample_pos);
-}
-
-static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io,
-               void (*run16)(struct fsi_priv *fsi, u8 *buf, int samples),
-               void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples),
-               int samples)
-{
-       u8 *buf;
-
-       if (!fsi_stream_is_working(fsi, io))
-               return -EINVAL;
-
-       buf = fsi_pio_get_area(fsi, io);
-
-       switch (io->sample_width) {
-       case 2:
-               run16(fsi, buf, samples);
-               break;
-       case 4:
-               run32(fsi, buf, samples);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       fsi_pointer_update(io, samples);
-
-       return 0;
-}
-
-static int fsi_pio_pop(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       int sample_residues;    /* samples in FSI fifo */
-       int sample_space;       /* ALSA free samples space */
-       int samples;
-
-       sample_residues = fsi_get_current_fifo_samples(fsi, io);
-       sample_space    = io->buff_sample_capa - io->buff_sample_pos;
-
-       samples = min(sample_residues, sample_space);
-
-       return fsi_pio_transfer(fsi, io,
-                                 fsi_pio_pop16,
-                                 fsi_pio_pop32,
-                                 samples);
-}
-
-static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       int sample_residues;    /* ALSA residue samples */
-       int sample_space;       /* FSI fifo free samples space */
-       int samples;
-
-       sample_residues = io->buff_sample_capa - io->buff_sample_pos;
-       sample_space    = io->fifo_sample_capa -
-               fsi_get_current_fifo_samples(fsi, io);
-
-       samples = min(sample_residues, sample_space);
-
-       return fsi_pio_transfer(fsi, io,
-                                 fsi_pio_push16,
-                                 fsi_pio_push32,
-                                 samples);
-}
-
-static int fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
-                              int enable)
-{
-       struct fsi_master *master = fsi_get_master(fsi);
-       u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
-
-       if (enable)
-               fsi_irq_enable(fsi, io);
-       else
-               fsi_irq_disable(fsi, io);
-
-       if (fsi_is_clk_master(fsi))
-               fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
-
-       return 0;
-}
-
-static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       /*
-        * we can use 16bit stream mode
-        * when "playback" and "16bit data"
-        * and platform allows "stream mode"
-        * see
-        *      fsi_pio_push16()
-        */
-       if (fsi_is_enable_stream(fsi))
-               io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
-                                BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
-       else
-               io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
-                                BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
-       return 0;
-}
-
-static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       /*
-        * always 24bit bus, package back when "capture"
-        */
-       io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
-                        BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
-       return 0;
-}
-
-static struct fsi_stream_handler fsi_pio_push_handler = {
-       .init           = fsi_pio_push_init,
-       .transfer       = fsi_pio_push,
-       .start_stop     = fsi_pio_start_stop,
-};
-
-static struct fsi_stream_handler fsi_pio_pop_handler = {
-       .init           = fsi_pio_pop_init,
-       .transfer       = fsi_pio_pop,
-       .start_stop     = fsi_pio_start_stop,
-};
-
-static irqreturn_t fsi_interrupt(int irq, void *data)
-{
-       struct fsi_master *master = data;
-       u32 int_st = fsi_irq_get_status(master);
-
-       /* clear irq status */
-       fsi_master_mask_set(master, SOFT_RST, IR, 0);
-       fsi_master_mask_set(master, SOFT_RST, IR, IR);
-
-       if (int_st & AB_IO(1, AO_SHIFT))
-               fsi_stream_transfer(&master->fsia.playback);
-       if (int_st & AB_IO(1, BO_SHIFT))
-               fsi_stream_transfer(&master->fsib.playback);
-       if (int_st & AB_IO(1, AI_SHIFT))
-               fsi_stream_transfer(&master->fsia.capture);
-       if (int_st & AB_IO(1, BI_SHIFT))
-               fsi_stream_transfer(&master->fsib.capture);
-
-       fsi_count_fifo_err(&master->fsia);
-       fsi_count_fifo_err(&master->fsib);
-
-       fsi_irq_clear_status(&master->fsia);
-       fsi_irq_clear_status(&master->fsib);
-
-       return IRQ_HANDLED;
-}
-
-/*
- *             dma data transfer handler
- */
-static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       /*
-        * 24bit data : 24bit bus / package in back
-        * 16bit data : 16bit bus / stream mode
-        */
-       io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
-                        BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
-
-       return 0;
-}
-
-static void fsi_dma_complete(void *data)
-{
-       struct fsi_stream *io = (struct fsi_stream *)data;
-       struct fsi_priv *fsi = fsi_stream_to_priv(io);
-
-       fsi_pointer_update(io, io->period_samples);
-
-       fsi_count_fifo_err(fsi);
-}
-
-static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       struct snd_soc_dai *dai = fsi_get_dai(io->substream);
-       struct snd_pcm_substream *substream = io->substream;
-       struct dma_async_tx_descriptor *desc;
-       int is_play = fsi_stream_is_play(fsi, io);
-       enum dma_transfer_direction dir;
-       int ret = -EIO;
-
-       if (is_play)
-               dir = DMA_MEM_TO_DEV;
-       else
-               dir = DMA_DEV_TO_MEM;
-
-       desc = dmaengine_prep_dma_cyclic(io->chan,
-                                        substream->runtime->dma_addr,
-                                        snd_pcm_lib_buffer_bytes(substream),
-                                        snd_pcm_lib_period_bytes(substream),
-                                        dir,
-                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               dev_err(dai->dev, "dmaengine_prep_dma_cyclic() fail\n");
-               goto fsi_dma_transfer_err;
-       }
-
-       desc->callback          = fsi_dma_complete;
-       desc->callback_param    = io;
-
-       if (dmaengine_submit(desc) < 0) {
-               dev_err(dai->dev, "tx_submit() fail\n");
-               goto fsi_dma_transfer_err;
-       }
-
-       dma_async_issue_pending(io->chan);
-
-       /*
-        * FIXME
-        *
-        * In DMAEngine case, codec and FSI cannot be started simultaneously
-        * since FSI is using the scheduler work queue.
-        * Therefore, in capture case, probably FSI FIFO will have got
-        * overflow error in this point.
-        * in that case, DMA cannot start transfer until error was cleared.
-        */
-       if (!is_play) {
-               if (ERR_OVER & fsi_reg_read(fsi, DIFF_ST)) {
-                       fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR);
-                       fsi_reg_write(fsi, DIFF_ST, 0);
-               }
-       }
-
-       ret = 0;
-
-fsi_dma_transfer_err:
-       return ret;
-}
-
-static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
-                                int start)
-{
-       struct fsi_master *master = fsi_get_master(fsi);
-       u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
-       u32 enable = start ? DMA_ON : 0;
-
-       fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable);
-
-       dmaengine_terminate_all(io->chan);
-
-       if (fsi_is_clk_master(fsi))
-               fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
-
-       return 0;
-}
-
-static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
-{
-       int is_play = fsi_stream_is_play(fsi, io);
-
-#ifdef CONFIG_SUPERH
-       dma_cap_mask_t mask;
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       io->chan = dma_request_channel(mask, shdma_chan_filter,
-                                      (void *)io->dma_id);
-#else
-       io->chan = dma_request_chan(dev, is_play ? "tx" : "rx");
-       if (IS_ERR(io->chan))
-               io->chan = NULL;
-#endif
-       if (io->chan) {
-               struct dma_slave_config cfg = {};
-               int ret;
-
-               if (is_play) {
-                       cfg.dst_addr            = fsi->phys + REG_DODT;
-                       cfg.dst_addr_width      = DMA_SLAVE_BUSWIDTH_4_BYTES;
-                       cfg.direction           = DMA_MEM_TO_DEV;
-               } else {
-                       cfg.src_addr            = fsi->phys + REG_DIDT;
-                       cfg.src_addr_width      = DMA_SLAVE_BUSWIDTH_4_BYTES;
-                       cfg.direction           = DMA_DEV_TO_MEM;
-               }
-
-               ret = dmaengine_slave_config(io->chan, &cfg);
-               if (ret < 0) {
-                       dma_release_channel(io->chan);
-                       io->chan = NULL;
-               }
-       }
-
-       if (!io->chan) {
-
-               /* switch to PIO handler */
-               if (is_play)
-                       fsi->playback.handler   = &fsi_pio_push_handler;
-               else
-                       fsi->capture.handler    = &fsi_pio_pop_handler;
-
-               dev_info(dev, "switch handler (dma => pio)\n");
-
-               /* probe again */
-               return fsi_stream_probe(fsi, dev);
-       }
-
-       return 0;
-}
-
-static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
-{
-       fsi_stream_stop(fsi, io);
-
-       if (io->chan)
-               dma_release_channel(io->chan);
-
-       io->chan = NULL;
-       return 0;
-}
-
-static struct fsi_stream_handler fsi_dma_push_handler = {
-       .init           = fsi_dma_init,
-       .probe          = fsi_dma_probe,
-       .transfer       = fsi_dma_transfer,
-       .remove         = fsi_dma_remove,
-       .start_stop     = fsi_dma_push_start_stop,
-};
-
-/*
- *             dai ops
- */
-static void fsi_fifo_init(struct fsi_priv *fsi,
-                         struct fsi_stream *io,
-                         struct device *dev)
-{
-       struct fsi_master *master = fsi_get_master(fsi);
-       int is_play = fsi_stream_is_play(fsi, io);
-       u32 shift, i;
-       int frame_capa;
-
-       /* get on-chip RAM capacity */
-       shift = fsi_master_read(master, FIFO_SZ);
-       shift >>= fsi_get_port_shift(fsi, io);
-       shift &= FIFO_SZ_MASK;
-       frame_capa = 256 << shift;
-       dev_dbg(dev, "fifo = %d words\n", frame_capa);
-
-       /*
-        * The maximum number of sample data varies depending
-        * on the number of channels selected for the format.
-        *
-        * FIFOs are used in 4-channel units in 3-channel mode
-        * and in 8-channel units in 5- to 7-channel mode
-        * meaning that more FIFOs than the required size of DPRAM
-        * are used.
-        *
-        * ex) if 256 words of DP-RAM is connected
-        * 1 channel:  256 (256 x 1 = 256)
-        * 2 channels: 128 (128 x 2 = 256)
-        * 3 channels:  64 ( 64 x 3 = 192)
-        * 4 channels:  64 ( 64 x 4 = 256)
-        * 5 channels:  32 ( 32 x 5 = 160)
-        * 6 channels:  32 ( 32 x 6 = 192)
-        * 7 channels:  32 ( 32 x 7 = 224)
-        * 8 channels:  32 ( 32 x 8 = 256)
-        */
-       for (i = 1; i < fsi->chan_num; i <<= 1)
-               frame_capa >>= 1;
-       dev_dbg(dev, "%d channel %d store\n",
-               fsi->chan_num, frame_capa);
-
-       io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa);
-
-       /*
-        * set interrupt generation factor
-        * clear FIFO
-        */
-       if (is_play) {
-               fsi_reg_write(fsi,      DOFF_CTL, IRQ_HALF);
-               fsi_reg_mask_set(fsi,   DOFF_CTL, FIFO_CLR, FIFO_CLR);
-       } else {
-               fsi_reg_write(fsi,      DIFF_CTL, IRQ_HALF);
-               fsi_reg_mask_set(fsi,   DIFF_CTL, FIFO_CLR, FIFO_CLR);
-       }
-}
-
-static int fsi_hw_startup(struct fsi_priv *fsi,
-                         struct fsi_stream *io,
-                         struct device *dev)
-{
-       u32 data = 0;
-
-       /* clock setting */
-       if (fsi_is_clk_master(fsi))
-               data = DIMD | DOMD;
-
-       fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
-
-       /* clock inversion (CKG2) */
-       data = 0;
-       if (fsi->bit_clk_inv)
-               data |= (1 << 0);
-       if (fsi->lr_clk_inv)
-               data |= (1 << 4);
-       if (fsi_is_clk_master(fsi))
-               data <<= 8;
-       fsi_reg_write(fsi, CKG2, data);
-
-       /* spdif ? */
-       if (fsi_is_spdif(fsi)) {
-               fsi_spdif_clk_ctrl(fsi, 1);
-               fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
-       }
-
-       /*
-        * get bus settings
-        */
-       data = 0;
-       switch (io->sample_width) {
-       case 2:
-               data = BUSOP_GET(16, io->bus_option);
-               break;
-       case 4:
-               data = BUSOP_GET(24, io->bus_option);
-               break;
-       }
-       fsi_format_bus_setup(fsi, io, data, dev);
-
-       /* irq clear */
-       fsi_irq_disable(fsi, io);
-       fsi_irq_clear_status(fsi);
-
-       /* fifo init */
-       fsi_fifo_init(fsi, io, dev);
-
-       /* start master clock */
-       if (fsi_is_clk_master(fsi))
-               return fsi_clk_enable(dev, fsi);
-
-       return 0;
-}
-
-static int fsi_hw_shutdown(struct fsi_priv *fsi,
-                           struct device *dev)
-{
-       /* stop master clock */
-       if (fsi_is_clk_master(fsi))
-               return fsi_clk_disable(dev, fsi);
-
-       return 0;
-}
-
-static int fsi_dai_startup(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
-{
-       struct fsi_priv *fsi = fsi_get_priv(substream);
-
-       fsi_clk_invalid(fsi);
-
-       return 0;
-}
-
-static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
-{
-       struct fsi_priv *fsi = fsi_get_priv(substream);
-
-       fsi_clk_invalid(fsi);
-}
-
-static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
-                          struct snd_soc_dai *dai)
-{
-       struct fsi_priv *fsi = fsi_get_priv(substream);
-       struct fsi_stream *io = fsi_stream_get(fsi, substream);
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               fsi_stream_init(fsi, io, substream);
-               if (!ret)
-                       ret = fsi_hw_startup(fsi, io, dai->dev);
-               if (!ret)
-                       ret = fsi_stream_start(fsi, io);
-               if (!ret)
-                       ret = fsi_stream_transfer(io);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               if (!ret)
-                       ret = fsi_hw_shutdown(fsi, dai->dev);
-               fsi_stream_stop(fsi, io);
-               fsi_stream_quit(fsi, io);
-               break;
-       }
-
-       return ret;
-}
-
-static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
-{
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               fsi->fmt = CR_I2S;
-               fsi->chan_num = 2;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               fsi->fmt = CR_PCM;
-               fsi->chan_num = 2;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
-{
-       struct fsi_master *master = fsi_get_master(fsi);
-
-       if (fsi_version(master) < 2)
-               return -EINVAL;
-
-       fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM;
-       fsi->chan_num = 2;
-
-       return 0;
-}
-
-static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-       struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai);
-       int ret;
-
-       /* set clock master audio interface */
-       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_BC_FC:
-               break;
-       case SND_SOC_DAIFMT_BP_FP:
-               fsi->clk_master = 1; /* cpu is master */
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* set clock inversion */
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_IF:
-               fsi->bit_clk_inv = 0;
-               fsi->lr_clk_inv = 1;
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               fsi->bit_clk_inv = 1;
-               fsi->lr_clk_inv = 0;
-               break;
-       case SND_SOC_DAIFMT_IB_IF:
-               fsi->bit_clk_inv = 1;
-               fsi->lr_clk_inv = 1;
-               break;
-       case SND_SOC_DAIFMT_NB_NF:
-       default:
-               fsi->bit_clk_inv = 0;
-               fsi->lr_clk_inv = 0;
-               break;
-       }
-
-       if (fsi_is_clk_master(fsi)) {
-               if (fsi->clk_cpg)
-                       fsi_clk_init(dai->dev, fsi, 0, 1, 1,
-                                    fsi_clk_set_rate_cpg);
-               else
-                       fsi_clk_init(dai->dev, fsi, 1, 1, 0,
-                                    fsi_clk_set_rate_external);
-       }
-
-       /* set format */
-       if (fsi_is_spdif(fsi))
-               ret = fsi_set_fmt_spdif(fsi);
-       else
-               ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
-
-       return ret;
-}
-
-static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
-                            struct snd_pcm_hw_params *params,
-                            struct snd_soc_dai *dai)
-{
-       struct fsi_priv *fsi = fsi_get_priv(substream);
-
-       if (fsi_is_clk_master(fsi))
-               fsi_clk_valid(fsi, params_rate(params));
-
-       return 0;
-}
-
-/*
- * Select below from Sound Card, not auto
- *     SND_SOC_DAIFMT_CBC_CFC
- *     SND_SOC_DAIFMT_CBP_CFP
- */
-static const u64 fsi_dai_formats =
-       SND_SOC_POSSIBLE_DAIFMT_I2S     |
-       SND_SOC_POSSIBLE_DAIFMT_LEFT_J  |
-       SND_SOC_POSSIBLE_DAIFMT_NB_NF   |
-       SND_SOC_POSSIBLE_DAIFMT_NB_IF   |
-       SND_SOC_POSSIBLE_DAIFMT_IB_NF   |
-       SND_SOC_POSSIBLE_DAIFMT_IB_IF;
-
-static const struct snd_soc_dai_ops fsi_dai_ops = {
-       .startup        = fsi_dai_startup,
-       .shutdown       = fsi_dai_shutdown,
-       .trigger        = fsi_dai_trigger,
-       .set_fmt        = fsi_dai_set_fmt,
-       .hw_params      = fsi_dai_hw_params,
-       .auto_selectable_formats        = &fsi_dai_formats,
-       .num_auto_selectable_formats    = 1,
-};
-
-/*
- *             pcm ops
- */
-
-static const struct snd_pcm_hardware fsi_pcm_hardware = {
-       .info =         SNDRV_PCM_INFO_INTERLEAVED      |
-                       SNDRV_PCM_INFO_MMAP             |
-                       SNDRV_PCM_INFO_MMAP_VALID,
-       .buffer_bytes_max       = 64 * 1024,
-       .period_bytes_min       = 32,
-       .period_bytes_max       = 8192,
-       .periods_min            = 1,
-       .periods_max            = 32,
-       .fifo_size              = 256,
-};
-
-static int fsi_pcm_open(struct snd_soc_component *component,
-                       struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int ret = 0;
-
-       snd_soc_set_runtime_hwparams(substream, &fsi_pcm_hardware);
-
-       ret = snd_pcm_hw_constraint_integer(runtime,
-                                           SNDRV_PCM_HW_PARAM_PERIODS);
-
-       return ret;
-}
-
-static snd_pcm_uframes_t fsi_pointer(struct snd_soc_component *component,
-                                    struct snd_pcm_substream *substream)
-{
-       struct fsi_priv *fsi = fsi_get_priv(substream);
-       struct fsi_stream *io = fsi_stream_get(fsi, substream);
-
-       return fsi_sample2frame(fsi, io->buff_sample_pos);
-}
-
-/*
- *             snd_soc_component
- */
-
-#define PREALLOC_BUFFER                (32 * 1024)
-#define PREALLOC_BUFFER_MAX    (32 * 1024)
-
-static int fsi_pcm_new(struct snd_soc_component *component,
-                      struct snd_soc_pcm_runtime *rtd)
-{
-       snd_pcm_set_managed_buffer_all(
-               rtd->pcm,
-               SNDRV_DMA_TYPE_DEV,
-               rtd->card->snd_card->dev,
-               PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
-       return 0;
-}
-
-/*
- *             alsa struct
- */
-
-static struct snd_soc_dai_driver fsi_soc_dai[] = {
-       {
-               .name                   = "fsia-dai",
-               .playback = {
-                       .rates          = FSI_RATES,
-                       .formats        = FSI_FMTS,
-                       .channels_min   = 2,
-                       .channels_max   = 2,
-               },
-               .capture = {
-                       .rates          = FSI_RATES,
-                       .formats        = FSI_FMTS,
-                       .channels_min   = 2,
-                       .channels_max   = 2,
-               },
-               .ops = &fsi_dai_ops,
-       },
-       {
-               .name                   = "fsib-dai",
-               .playback = {
-                       .rates          = FSI_RATES,
-                       .formats        = FSI_FMTS,
-                       .channels_min   = 2,
-                       .channels_max   = 2,
-               },
-               .capture = {
-                       .rates          = FSI_RATES,
-                       .formats        = FSI_FMTS,
-                       .channels_min   = 2,
-                       .channels_max   = 2,
-               },
-               .ops = &fsi_dai_ops,
-       },
-};
-
-static const struct snd_soc_component_driver fsi_soc_component = {
-       .name           = "fsi",
-       .open           = fsi_pcm_open,
-       .pointer        = fsi_pointer,
-       .pcm_construct  = fsi_pcm_new,
-};
-
-/*
- *             platform function
- */
-static void fsi_of_parse(char *name,
-                        struct device_node *np,
-                        struct sh_fsi_port_info *info,
-                        struct device *dev)
-{
-       int i;
-       char prop[128];
-       unsigned long flags = 0;
-       struct {
-               char *name;
-               unsigned int val;
-       } of_parse_property[] = {
-               { "spdif-connection",           SH_FSI_FMT_SPDIF },
-               { "stream-mode-support",        SH_FSI_ENABLE_STREAM_MODE },
-               { "use-internal-clock",         SH_FSI_CLK_CPG },
-       };
-
-       for (i = 0; i < ARRAY_SIZE(of_parse_property); i++) {
-               sprintf(prop, "%s,%s", name, of_parse_property[i].name);
-               if (of_property_present(np, prop))
-                       flags |= of_parse_property[i].val;
-       }
-       info->flags = flags;
-
-       dev_dbg(dev, "%s flags : %lx\n", name, info->flags);
-}
-
-static void fsi_port_info_init(struct fsi_priv *fsi,
-                              struct sh_fsi_port_info *info)
-{
-       if (info->flags & SH_FSI_FMT_SPDIF)
-               fsi->spdif = 1;
-
-       if (info->flags & SH_FSI_CLK_CPG)
-               fsi->clk_cpg = 1;
-
-       if (info->flags & SH_FSI_ENABLE_STREAM_MODE)
-               fsi->enable_stream = 1;
-}
-
-static void fsi_handler_init(struct fsi_priv *fsi,
-                            struct sh_fsi_port_info *info)
-{
-       fsi->playback.handler   = &fsi_pio_push_handler; /* default PIO */
-       fsi->playback.priv      = fsi;
-       fsi->capture.handler    = &fsi_pio_pop_handler;  /* default PIO */
-       fsi->capture.priv       = fsi;
-
-       if (info->tx_id) {
-               fsi->playback.dma_id  = info->tx_id;
-               fsi->playback.handler = &fsi_dma_push_handler;
-       }
-}
-
-static const struct fsi_core fsi1_core = {
-       .ver    = 1,
-
-       /* Interrupt */
-       .int_st = INT_ST,
-       .iemsk  = IEMSK,
-       .imsk   = IMSK,
-};
-
-static const struct fsi_core fsi2_core = {
-       .ver    = 2,
-
-       /* Interrupt */
-       .int_st = CPU_INT_ST,
-       .iemsk  = CPU_IEMSK,
-       .imsk   = CPU_IMSK,
-       .a_mclk = A_MST_CTLR,
-       .b_mclk = B_MST_CTLR,
-};
-
-static const struct of_device_id fsi_of_match[] = {
-       { .compatible = "renesas,sh_fsi",       .data = &fsi1_core},
-       { .compatible = "renesas,sh_fsi2",      .data = &fsi2_core},
-       {},
-};
-MODULE_DEVICE_TABLE(of, fsi_of_match);
-
-static const struct platform_device_id fsi_id_table[] = {
-       { "sh_fsi",     (kernel_ulong_t)&fsi1_core },
-       {},
-};
-MODULE_DEVICE_TABLE(platform, fsi_id_table);
-
-static int fsi_probe(struct platform_device *pdev)
-{
-       struct fsi_master *master;
-       struct device_node *np = pdev->dev.of_node;
-       struct sh_fsi_platform_info info;
-       const struct fsi_core *core;
-       struct fsi_priv *fsi;
-       struct resource *res;
-       unsigned int irq;
-       int ret;
-
-       memset(&info, 0, sizeof(info));
-
-       core = NULL;
-       if (np) {
-               core = of_device_get_match_data(&pdev->dev);
-               fsi_of_parse("fsia", np, &info.port_a, &pdev->dev);
-               fsi_of_parse("fsib", np, &info.port_b, &pdev->dev);
-       } else {
-               const struct platform_device_id *id_entry = pdev->id_entry;
-               if (id_entry)
-                       core = (struct fsi_core *)id_entry->driver_data;
-
-               if (pdev->dev.platform_data)
-                       memcpy(&info, pdev->dev.platform_data, sizeof(info));
-       }
-
-       if (!core) {
-               dev_err(&pdev->dev, "unknown fsi device\n");
-               return -ENODEV;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       irq = platform_get_irq(pdev, 0);
-       if (!res || (int)irq <= 0) {
-               dev_err(&pdev->dev, "Not enough FSI platform resources.\n");
-               return -ENODEV;
-       }
-
-       master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
-       if (!master)
-               return -ENOMEM;
-
-       master->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-       if (!master->base) {
-               dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n");
-               return -ENXIO;
-       }
-
-       /* master setting */
-       master->core            = core;
-       spin_lock_init(&master->lock);
-
-       /* FSI A setting */
-       fsi             = &master->fsia;
-       fsi->base       = master->base;
-       fsi->phys       = res->start;
-       fsi->master     = master;
-       fsi_port_info_init(fsi, &info.port_a);
-       fsi_handler_init(fsi, &info.port_a);
-       ret = fsi_stream_probe(fsi, &pdev->dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "FSIA stream probe failed\n");
-               return ret;
-       }
-
-       /* FSI B setting */
-       fsi             = &master->fsib;
-       fsi->base       = master->base + 0x40;
-       fsi->phys       = res->start + 0x40;
-       fsi->master     = master;
-       fsi_port_info_init(fsi, &info.port_b);
-       fsi_handler_init(fsi, &info.port_b);
-       ret = fsi_stream_probe(fsi, &pdev->dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "FSIB stream probe failed\n");
-               goto exit_fsia;
-       }
-
-       pm_runtime_enable(&pdev->dev);
-       dev_set_drvdata(&pdev->dev, master);
-
-       ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0,
-                              dev_name(&pdev->dev), master);
-       if (ret) {
-               dev_err(&pdev->dev, "irq request err\n");
-               goto exit_fsib;
-       }
-
-       ret = devm_snd_soc_register_component(&pdev->dev, &fsi_soc_component,
-                                   fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
-       if (ret < 0) {
-               dev_err(&pdev->dev, "cannot snd component register\n");
-               goto exit_fsib;
-       }
-
-       return ret;
-
-exit_fsib:
-       pm_runtime_disable(&pdev->dev);
-       fsi_stream_remove(&master->fsib);
-exit_fsia:
-       fsi_stream_remove(&master->fsia);
-
-       return ret;
-}
-
-static void fsi_remove(struct platform_device *pdev)
-{
-       struct fsi_master *master;
-
-       master = dev_get_drvdata(&pdev->dev);
-
-       pm_runtime_disable(&pdev->dev);
-
-       fsi_stream_remove(&master->fsia);
-       fsi_stream_remove(&master->fsib);
-}
-
-static void __fsi_suspend(struct fsi_priv *fsi,
-                         struct fsi_stream *io,
-                         struct device *dev)
-{
-       if (!fsi_stream_is_working(fsi, io))
-               return;
-
-       fsi_stream_stop(fsi, io);
-       fsi_hw_shutdown(fsi, dev);
-}
-
-static void __fsi_resume(struct fsi_priv *fsi,
-                        struct fsi_stream *io,
-                        struct device *dev)
-{
-       if (!fsi_stream_is_working(fsi, io))
-               return;
-
-       fsi_hw_startup(fsi, io, dev);
-       fsi_stream_start(fsi, io);
-}
-
-static int fsi_suspend(struct device *dev)
-{
-       struct fsi_master *master = dev_get_drvdata(dev);
-       struct fsi_priv *fsia = &master->fsia;
-       struct fsi_priv *fsib = &master->fsib;
-
-       __fsi_suspend(fsia, &fsia->playback, dev);
-       __fsi_suspend(fsia, &fsia->capture, dev);
-
-       __fsi_suspend(fsib, &fsib->playback, dev);
-       __fsi_suspend(fsib, &fsib->capture, dev);
-
-       return 0;
-}
-
-static int fsi_resume(struct device *dev)
-{
-       struct fsi_master *master = dev_get_drvdata(dev);
-       struct fsi_priv *fsia = &master->fsia;
-       struct fsi_priv *fsib = &master->fsib;
-
-       __fsi_resume(fsia, &fsia->playback, dev);
-       __fsi_resume(fsia, &fsia->capture, dev);
-
-       __fsi_resume(fsib, &fsib->playback, dev);
-       __fsi_resume(fsib, &fsib->capture, dev);
-
-       return 0;
-}
-
-static const struct dev_pm_ops fsi_pm_ops = {
-       .suspend                = fsi_suspend,
-       .resume                 = fsi_resume,
-};
-
-static struct platform_driver fsi_driver = {
-       .driver         = {
-               .name   = "fsi-pcm-audio",
-               .pm     = &fsi_pm_ops,
-               .of_match_table = fsi_of_match,
-       },
-       .probe          = fsi_probe,
-       .remove         = fsi_remove,
-       .id_table       = fsi_id_table,
-};
-
-module_platform_driver(fsi_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SuperH onchip FSI audio driver");
-MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
-MODULE_ALIAS("platform:fsi-pcm-audio");
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
deleted file mode 100644 (file)
index db618c0..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Hitachi Audio Controller (AC97) support for SH7760/SH7780
-//
-// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
-//
-// dont forget to set IPSEL/OMSEL register bits (in your board code) to
-// enable HAC output pins!
-
-/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
- * the FIRST can be used since ASoC does not pass any information to the
- * ac97_read/write() functions regarding WHICH unit to use.  You'll have
- * to edit the code a bit to use the other AC97 unit.          --mlau
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/ac97_codec.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-/* regs and bits */
-#define HACCR          0x08
-#define HACCSAR                0x20
-#define HACCSDR                0x24
-#define HACPCML                0x28
-#define HACPCMR                0x2C
-#define HACTIER                0x50
-#define        HACTSR          0x54
-#define HACRIER                0x58
-#define HACRSR         0x5C
-#define HACACR         0x60
-
-#define CR_CR          (1 << 15)       /* "codec-ready" indicator */
-#define CR_CDRT                (1 << 11)       /* cold reset */
-#define CR_WMRT                (1 << 10)       /* warm reset */
-#define CR_B9          (1 << 9)        /* the mysterious "bit 9" */
-#define CR_ST          (1 << 5)        /* AC97 link start bit */
-
-#define CSAR_RD                (1 << 19)       /* AC97 data read bit */
-#define CSAR_WR                (0)
-
-#define TSR_CMDAMT     (1 << 31)
-#define TSR_CMDDMT     (1 << 30)
-
-#define RSR_STARY      (1 << 22)
-#define RSR_STDRY      (1 << 21)
-
-#define ACR_DMARX16    (1 << 30)
-#define ACR_DMATX16    (1 << 29)
-#define ACR_TX12ATOM   (1 << 26)
-#define ACR_DMARX20    ((1 << 24) | (1 << 22))
-#define ACR_DMATX20    ((1 << 23) | (1 << 21))
-
-#define CSDR_SHIFT     4
-#define CSDR_MASK      (0xffff << CSDR_SHIFT)
-#define CSAR_SHIFT     12
-#define CSAR_MASK      (0x7f << CSAR_SHIFT)
-
-#define AC97_WRITE_RETRY       1
-#define AC97_READ_RETRY                5
-
-/* manual-suggested AC97 codec access timeouts (us) */
-#define TMO_E1 500     /* 21 < E1 < 1000 */
-#define TMO_E2 13      /* 13 < E2 */
-#define TMO_E3 21      /* 21 < E3 */
-#define TMO_E4 500     /* 21 < E4 < 1000 */
-
-struct hac_priv {
-       unsigned long mmio;     /* HAC base address */
-} hac_cpu_data[] = {
-#if defined(CONFIG_CPU_SUBTYPE_SH7760)
-       {
-               .mmio   = 0xFE240000,
-       },
-       {
-               .mmio   = 0xFE250000,
-       },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-       {
-               .mmio   = 0xFFE40000,
-       },
-#else
-#error "Unsupported SuperH SoC"
-#endif
-};
-
-#define HACREG(reg)    (*(unsigned long *)(hac->mmio + (reg)))
-
-/*
- * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906)
- */
-static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
-                             unsigned short *v)
-{
-       unsigned int to1, to2, i;
-       unsigned short adr;
-
-       for (i = AC97_READ_RETRY; i; i--) {
-               *v = 0;
-               /* wait for HAC to receive something from the codec */
-               for (to1 = TMO_E4;
-                    to1 && !(HACREG(HACRSR) & RSR_STARY);
-                    --to1)
-                       udelay(1);
-               for (to2 = TMO_E4; 
-                    to2 && !(HACREG(HACRSR) & RSR_STDRY);
-                    --to2)
-                       udelay(1);
-
-               if (!to1 && !to2)
-                       return 0;       /* codec comm is down */
-
-               adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT);
-               *v  = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT);
-
-               HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
-
-               if (r == adr)
-                       break;
-
-               /* manual says: wait at least 21 usec before retrying */
-               udelay(21);
-       }
-       HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
-       return i;
-}
-
-static unsigned short hac_read_codec_aux(struct hac_priv *hac,
-                                        unsigned short reg)
-{
-       unsigned short val;
-       unsigned int i, to;
-
-       for (i = AC97_READ_RETRY; i; i--) {
-               /* send_read_request */
-               local_irq_disable();
-               HACREG(HACTSR) &= ~(TSR_CMDAMT);
-               HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD;
-               local_irq_enable();
-
-               for (to = TMO_E3;
-                    to && !(HACREG(HACTSR) & TSR_CMDAMT);
-                    --to)
-                       udelay(1);
-
-               HACREG(HACTSR) &= ~TSR_CMDAMT;
-               val = 0;
-               if (hac_get_codec_data(hac, reg, &val) != 0)
-                       break;
-       }
-
-       return i ? val : ~0;
-}
-
-static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-                          unsigned short val)
-{
-       int unit_id = 0 /* ac97->private_data */;
-       struct hac_priv *hac = &hac_cpu_data[unit_id];
-       unsigned int i, to;
-       /* write_codec_aux */
-       for (i = AC97_WRITE_RETRY; i; i--) {
-               /* send_write_request */
-               local_irq_disable();
-               HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
-               HACREG(HACCSDR) = (val << CSDR_SHIFT);
-               HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD);
-               local_irq_enable();
-
-               /* poll-wait for CMDAMT and CMDDMT */
-               for (to = TMO_E1;
-                    to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT));
-                    --to)
-                       udelay(1);
-
-               HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT);
-               if (to)
-                       break;
-               /* timeout, try again */
-       }
-}
-
-static unsigned short hac_ac97_read(struct snd_ac97 *ac97,
-                                   unsigned short reg)
-{
-       int unit_id = 0 /* ac97->private_data */;
-       struct hac_priv *hac = &hac_cpu_data[unit_id];
-       return hac_read_codec_aux(hac, reg);
-}
-
-static void hac_ac97_warmrst(struct snd_ac97 *ac97)
-{
-       int unit_id = 0 /* ac97->private_data */;
-       struct hac_priv *hac = &hac_cpu_data[unit_id];
-       unsigned int tmo;
-
-       HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9;
-       msleep(10);
-       HACREG(HACCR) = CR_ST | CR_B9;
-       for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--)
-               udelay(1);
-
-       if (!tmo)
-               printk(KERN_INFO "hac: reset: AC97 link down!\n");
-       /* settings this bit lets us have a conversation with codec */
-       HACREG(HACACR) |= ACR_TX12ATOM;
-}
-
-static void hac_ac97_coldrst(struct snd_ac97 *ac97)
-{
-       int unit_id = 0 /* ac97->private_data */;
-       struct hac_priv *hac;
-       hac = &hac_cpu_data[unit_id];
-
-       HACREG(HACCR) = 0;
-       HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9;
-       msleep(10);
-       hac_ac97_warmrst(ac97);
-}
-
-static struct snd_ac97_bus_ops hac_ac97_ops = {
-       .read   = hac_ac97_read,
-       .write  = hac_ac97_write,
-       .reset  = hac_ac97_coldrst,
-       .warm_reset = hac_ac97_warmrst,
-};
-
-static int hac_hw_params(struct snd_pcm_substream *substream,
-                        struct snd_pcm_hw_params *params,
-                        struct snd_soc_dai *dai)
-{
-       struct hac_priv *hac = &hac_cpu_data[dai->id];
-       int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
-
-       switch (params->msbits) {
-       case 16:
-               HACREG(HACACR) |= d ?  ACR_DMARX16 :  ACR_DMATX16;
-               HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20;
-               break;
-       case 20:
-               HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16;
-               HACREG(HACACR) |= d ?  ACR_DMARX20 :  ACR_DMATX20;
-               break;
-       default:
-               pr_debug("hac: invalid depth %d bit\n", params->msbits);
-               return -EINVAL;
-               break;
-       }
-
-       return 0;
-}
-
-#define AC97_RATES     \
-       SNDRV_PCM_RATE_8000_192000
-
-#define AC97_FMTS      \
-       SNDRV_PCM_FMTBIT_S16_LE
-
-static const struct snd_soc_dai_ops hac_dai_ops = {
-       .hw_params      = hac_hw_params,
-};
-
-static struct snd_soc_dai_driver sh4_hac_dai[] = {
-{
-       .name                   = "hac-dai.0",
-       .playback = {
-               .rates          = AC97_RATES,
-               .formats        = AC97_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 2,
-       },
-       .capture = {
-               .rates          = AC97_RATES,
-               .formats        = AC97_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 2,
-       },
-       .ops = &hac_dai_ops,
-},
-#ifdef CONFIG_CPU_SUBTYPE_SH7760
-{
-       .name                   = "hac-dai.1",
-       .id                     = 1,
-       .playback = {
-               .rates          = AC97_RATES,
-               .formats        = AC97_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 2,
-       },
-       .capture = {
-               .rates          = AC97_RATES,
-               .formats        = AC97_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 2,
-       },
-       .ops = &hac_dai_ops,
-
-},
-#endif
-};
-
-static const struct snd_soc_component_driver sh4_hac_component = {
-       .name                   = "sh4-hac",
-       .legacy_dai_naming      = 1,
-};
-
-static int hac_soc_platform_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       ret = snd_soc_set_ac97_ops(&hac_ac97_ops);
-       if (ret != 0)
-               return ret;
-
-       return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component,
-                                         sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
-}
-
-static void hac_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_soc_set_ac97_ops(NULL);
-}
-
-static struct platform_driver hac_pcm_driver = {
-       .driver = {
-                       .name = "hac-pcm-audio",
-       },
-
-       .probe = hac_soc_platform_probe,
-       .remove = hac_soc_platform_remove,
-};
-
-module_platform_driver(hac_pcm_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
-MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
deleted file mode 100644 (file)
index 5a0bc6e..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// ALSA SoC driver for Migo-R
-//
-// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
-
-#include <linux/clkdev.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-
-#include <asm/clock.h>
-
-#include <cpu/sh7722.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include "../codecs/wm8978.h"
-#include "siu.h"
-
-/* Default 8000Hz sampling frequency */
-static unsigned long codec_freq = 8000 * 512;
-
-static unsigned int use_count;
-
-/* External clock, sourced from the codec at the SIUMCKB pin */
-static unsigned long siumckb_recalc(struct clk *clk)
-{
-       return codec_freq;
-}
-
-static struct sh_clk_ops siumckb_clk_ops = {
-       .recalc = siumckb_recalc,
-};
-
-static struct clk siumckb_clk = {
-       .ops            = &siumckb_clk_ops,
-       .rate           = 0, /* initialised at run-time */
-};
-
-static struct clk_lookup *siumckb_lookup;
-
-static int migor_hw_params(struct snd_pcm_substream *substream,
-                          struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-       struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
-       int ret;
-       unsigned int rate = params_rate(params);
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000,
-                                    SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512);
-       if (ret < 0)
-               return ret;
-
-       codec_freq = rate * 512;
-       /*
-        * This propagates the parent frequency change to children and
-        * recalculates the frequency table
-        */
-       clk_set_rate(&siumckb_clk, codec_freq);
-       dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
-
-       ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), SIU_CLKB_EXT,
-                                    codec_freq / 2, SND_SOC_CLOCK_IN);
-
-       if (!ret)
-               use_count++;
-
-       return ret;
-}
-
-static int migor_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-       struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
-
-       if (use_count) {
-               use_count--;
-
-               if (!use_count)
-                       snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0,
-                                              SND_SOC_CLOCK_IN);
-       } else {
-               dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n");
-       }
-
-       return 0;
-}
-
-static const struct snd_soc_ops migor_dai_ops = {
-       .hw_params = migor_hw_params,
-       .hw_free = migor_hw_free,
-};
-
-static const struct snd_soc_dapm_widget migor_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone", NULL),
-       SND_SOC_DAPM_MIC("Onboard Microphone", NULL),
-       SND_SOC_DAPM_MIC("External Microphone", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       /* Headphone output connected to LHP/RHP, enable OUT4 for VMID */
-       { "Headphone", NULL,  "OUT4 VMID" },
-       { "OUT4 VMID", NULL,  "LHP" },
-       { "OUT4 VMID", NULL,  "RHP" },
-
-       /* On-board microphone */
-       { "RMICN", NULL, "Mic Bias" },
-       { "RMICP", NULL, "Mic Bias" },
-       { "Mic Bias", NULL, "Onboard Microphone" },
-
-       /* External microphone */
-       { "LMICN", NULL, "Mic Bias" },
-       { "LMICP", NULL, "Mic Bias" },
-       { "Mic Bias", NULL, "External Microphone" },
-};
-
-/* migor digital audio interface glue - connects codec <--> CPU */
-SND_SOC_DAILINK_DEFS(wm8978,
-       DAILINK_COMP_ARRAY(COMP_CPU("siu-pcm-audio")),
-       DAILINK_COMP_ARRAY(COMP_CODEC("wm8978.0-001a", "wm8978-hifi")),
-       DAILINK_COMP_ARRAY(COMP_PLATFORM("siu-pcm-audio")));
-
-static struct snd_soc_dai_link migor_dai = {
-       .name = "wm8978",
-       .stream_name = "WM8978",
-       .dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S |
-                  SND_SOC_DAIFMT_CBS_CFS,
-       .ops = &migor_dai_ops,
-       SND_SOC_DAILINK_REG(wm8978),
-};
-
-/* migor audio machine driver */
-static struct snd_soc_card snd_soc_migor = {
-       .name = "Migo-R",
-       .owner = THIS_MODULE,
-       .dai_link = &migor_dai,
-       .num_links = 1,
-
-       .dapm_widgets = migor_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(migor_dapm_widgets),
-       .dapm_routes = audio_map,
-       .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static struct platform_device *migor_snd_device;
-
-static int __init migor_init(void)
-{
-       int ret;
-
-       ret = clk_register(&siumckb_clk);
-       if (ret < 0)
-               return ret;
-
-       siumckb_lookup = clkdev_create(&siumckb_clk, "siumckb_clk", NULL);
-       if (!siumckb_lookup) {
-               ret = -ENOMEM;
-               goto eclkdevalloc;
-       }
-
-       /* Port number used on this machine: port B */
-       migor_snd_device = platform_device_alloc("soc-audio", 1);
-       if (!migor_snd_device) {
-               ret = -ENOMEM;
-               goto epdevalloc;
-       }
-
-       platform_set_drvdata(migor_snd_device, &snd_soc_migor);
-
-       ret = platform_device_add(migor_snd_device);
-       if (ret)
-               goto epdevadd;
-
-       return 0;
-
-epdevadd:
-       platform_device_put(migor_snd_device);
-epdevalloc:
-       clkdev_drop(siumckb_lookup);
-eclkdevalloc:
-       clk_unregister(&siumckb_clk);
-       return ret;
-}
-
-static void __exit migor_exit(void)
-{
-       clkdev_drop(siumckb_lookup);
-       clk_unregister(&siumckb_clk);
-       platform_device_unregister(migor_snd_device);
-}
-
-module_init(migor_init);
-module_exit(migor_exit);
-
-MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
-MODULE_DESCRIPTION("ALSA SoC Migor");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
deleted file mode 100644 (file)
index 45eb875..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-snd-soc-rcar-y         := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o
-obj-$(CONFIG_SND_SOC_RCAR)     += snd-soc-rcar.o
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
deleted file mode 100644 (file)
index 0f190ab..0000000
+++ /dev/null
@@ -1,775 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Helper routines for R-Car sound ADG.
-//
-//  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-#include "rsnd.h"
-
-#define CLKA   0
-#define CLKB   1
-#define CLKC   2
-#define CLKI   3
-#define CLKINMAX 4
-
-#define CLKOUT 0
-#define CLKOUT1        1
-#define CLKOUT2        2
-#define CLKOUT3        3
-#define CLKOUTMAX 4
-
-#define BRRx_MASK(x) (0x3FF & x)
-
-static struct rsnd_mod_ops adg_ops = {
-       .name = "adg",
-};
-
-#define ADG_HZ_441     0
-#define ADG_HZ_48      1
-#define ADG_HZ_SIZE    2
-
-struct rsnd_adg {
-       struct clk *clkin[CLKINMAX];
-       struct clk *clkout[CLKOUTMAX];
-       struct clk *null_clk;
-       struct clk_onecell_data onecell;
-       struct rsnd_mod mod;
-       int clkin_rate[CLKINMAX];
-       int clkin_size;
-       int clkout_size;
-       u32 ckr;
-       u32 brga;
-       u32 brgb;
-
-       int brg_rate[ADG_HZ_SIZE]; /* BRGA / BRGB */
-};
-
-#define for_each_rsnd_clkin(pos, adg, i)       \
-       for (i = 0;                             \
-            (i < adg->clkin_size) &&           \
-            ((pos) = adg->clkin[i]);           \
-            i++)
-#define for_each_rsnd_clkout(pos, adg, i)      \
-       for (i = 0;                             \
-            (i < adg->clkout_size) &&          \
-            ((pos) = adg->clkout[i]);  \
-            i++)
-#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
-
-static const char * const clkin_name_gen4[] = {
-       [CLKA]  = "clkin",
-};
-
-static const char * const clkin_name_gen2[] = {
-       [CLKA]  = "clk_a",
-       [CLKB]  = "clk_b",
-       [CLKC]  = "clk_c",
-       [CLKI]  = "clk_i",
-};
-
-static const char * const clkout_name_gen2[] = {
-       [CLKOUT]  = "audio_clkout",
-       [CLKOUT1] = "audio_clkout1",
-       [CLKOUT2] = "audio_clkout2",
-       [CLKOUT3] = "audio_clkout3",
-};
-
-static u32 rsnd_adg_calculate_brgx(unsigned long div)
-{
-       int i;
-
-       if (!div)
-               return 0;
-
-       for (i = 3; i >= 0; i--) {
-               int ratio = 2 << (i * 2);
-               if (0 == (div % ratio))
-                       return (u32)((i << 8) | ((div / ratio) - 1));
-       }
-
-       return ~0;
-}
-
-static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
-{
-       struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
-       int id = rsnd_mod_id(ssi_mod);
-       int ws = id;
-
-       if (rsnd_ssi_is_pin_sharing(io)) {
-               switch (id) {
-               case 1:
-               case 2:
-               case 9:
-                       ws = 0;
-                       break;
-               case 4:
-                       ws = 3;
-                       break;
-               case 8:
-                       ws = 7;
-                       break;
-               }
-       } else {
-               /*
-                * SSI8 is not connected to ADG.
-                * Thus SSI9 is using ws = 8
-                */
-               if (id == 9)
-                       ws = 8;
-       }
-
-       return (0x6 + ws) << 8;
-}
-
-static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
-                                      struct rsnd_dai_stream *io,
-                                      unsigned int target_rate,
-                                      unsigned int *target_val,
-                                      unsigned int *target_en)
-{
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int sel;
-       unsigned int val, en;
-       unsigned int min, diff;
-       unsigned int sel_rate[] = {
-               adg->clkin_rate[CLKA],  /* 0000: CLKA */
-               adg->clkin_rate[CLKB],  /* 0001: CLKB */
-               adg->clkin_rate[CLKC],  /* 0010: CLKC */
-               adg->brg_rate[ADG_HZ_441],      /* 0011: BRGA */
-               adg->brg_rate[ADG_HZ_48],       /* 0100: BRGB */
-       };
-
-       min = ~0;
-       val = 0;
-       en = 0;
-       for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
-               int idx = 0;
-               int step = 2;
-               int div;
-
-               if (!sel_rate[sel])
-                       continue;
-
-               for (div = 2; div <= 98304; div += step) {
-                       diff = abs(target_rate - sel_rate[sel] / div);
-                       if (min > diff) {
-                               val = (sel << 8) | idx;
-                               min = diff;
-                               en = 1 << (sel + 1); /* fixme */
-                       }
-
-                       /*
-                        * step of 0_0000 / 0_0001 / 0_1101
-                        * are out of order
-                        */
-                       if ((idx > 2) && (idx % 2))
-                               step *= 2;
-                       if (idx == 0x1c) {
-                               div += step;
-                               step *= 2;
-                       }
-                       idx++;
-               }
-       }
-
-       if (min == ~0) {
-               dev_err(dev, "no Input clock\n");
-               return;
-       }
-
-       *target_val = val;
-       if (target_en)
-               *target_en = en;
-}
-
-static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
-                                      struct rsnd_dai_stream *io,
-                                      unsigned int in_rate,
-                                      unsigned int out_rate,
-                                      u32 *in, u32 *out, u32 *en)
-{
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       unsigned int target_rate;
-       u32 *target_val;
-       u32 _in;
-       u32 _out;
-       u32 _en;
-
-       /* default = SSI WS */
-       _in =
-       _out = rsnd_adg_ssi_ws_timing_gen2(io);
-
-       target_rate = 0;
-       target_val = NULL;
-       _en = 0;
-       if (runtime->rate != in_rate) {
-               target_rate = out_rate;
-               target_val  = &_out;
-       } else if (runtime->rate != out_rate) {
-               target_rate = in_rate;
-               target_val  = &_in;
-       }
-
-       if (target_rate)
-               __rsnd_adg_get_timesel_ratio(priv, io,
-                                            target_rate,
-                                            target_val, &_en);
-
-       if (in)
-               *in = _in;
-       if (out)
-               *out = _out;
-       if (en)
-               *en = _en;
-}
-
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
-                                struct rsnd_dai_stream *io)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-       int id = rsnd_mod_id(cmd_mod);
-       int shift = (id % 2) ? 16 : 0;
-       u32 mask, val;
-
-       rsnd_adg_get_timesel_ratio(priv, io,
-                                  rsnd_src_get_in_rate(priv, io),
-                                  rsnd_src_get_out_rate(priv, io),
-                                  NULL, &val, NULL);
-
-       val  = val      << shift;
-       mask = 0x0f1f   << shift;
-
-       rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val);
-
-       return 0;
-}
-
-int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
-                                 struct rsnd_dai_stream *io,
-                                 unsigned int in_rate,
-                                 unsigned int out_rate)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-       u32 in, out;
-       u32 mask, en;
-       int id = rsnd_mod_id(src_mod);
-       int shift = (id % 2) ? 16 : 0;
-
-       rsnd_mod_make_sure(src_mod, RSND_MOD_SRC);
-
-       rsnd_adg_get_timesel_ratio(priv, io,
-                                  in_rate, out_rate,
-                                  &in, &out, &en);
-
-       in   = in       << shift;
-       out  = out      << shift;
-       mask = 0x0f1f   << shift;
-
-       rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2),  mask, in);
-       rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out);
-
-       if (en)
-               rsnd_mod_bset(adg_mod, DIV_EN, en, en);
-
-       return 0;
-}
-
-static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int id = rsnd_mod_id(ssi_mod);
-       int shift = (id % 4) * 8;
-       u32 mask = 0xFF << shift;
-
-       rsnd_mod_make_sure(ssi_mod, RSND_MOD_SSI);
-
-       val = val << shift;
-
-       /*
-        * SSI 8 is not connected to ADG.
-        * it works with SSI 7
-        */
-       if (id == 8)
-               return;
-
-       rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val);
-
-       dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
-}
-
-int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
-{
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct clk *clk;
-       int i;
-       int sel_table[] = {
-               [CLKA] = 0x1,
-               [CLKB] = 0x2,
-               [CLKC] = 0x3,
-               [CLKI] = 0x0,
-       };
-
-       /*
-        * find suitable clock from
-        * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
-        */
-       for_each_rsnd_clkin(clk, adg, i)
-               if (rate == adg->clkin_rate[i])
-                       return sel_table[i];
-
-       /*
-        * find divided clock from BRGA/BRGB
-        */
-       if (rate == adg->brg_rate[ADG_HZ_441])
-               return 0x10;
-
-       if (rate == adg->brg_rate[ADG_HZ_48])
-               return 0x20;
-
-       return -EIO;
-}
-
-int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
-{
-       rsnd_adg_set_ssi_clk(ssi_mod, 0);
-
-       return 0;
-}
-
-int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-       int data;
-       u32 ckr = 0;
-
-       data = rsnd_adg_clk_query(priv, rate);
-       if (data < 0)
-               return data;
-
-       rsnd_adg_set_ssi_clk(ssi_mod, data);
-
-       if (0 == (rate % 8000))
-               ckr = 0x80000000; /* BRGB output = 48kHz */
-
-       rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
-
-       dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
-               (ckr) ? 'B' : 'A',
-               (ckr) ? adg->brg_rate[ADG_HZ_48] :
-                       adg->brg_rate[ADG_HZ_441]);
-
-       return 0;
-}
-
-void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
-{
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
-       struct clk *clk;
-       int i;
-
-       if (enable) {
-               rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr);
-               rsnd_mod_write(adg_mod, BRRA,  adg->brga);
-               rsnd_mod_write(adg_mod, BRRB,  adg->brgb);
-       }
-
-       for_each_rsnd_clkin(clk, adg, i) {
-               if (enable) {
-                       clk_prepare_enable(clk);
-
-                       /*
-                        * We shouldn't use clk_get_rate() under
-                        * atomic context. Let's keep it when
-                        * rsnd_adg_clk_enable() was called
-                        */
-                       adg->clkin_rate[i] = clk_get_rate(clk);
-               } else {
-                       clk_disable_unprepare(clk);
-               }
-       }
-}
-
-static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv,
-                                           const char * const name,
-                                           const char *parent)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct clk *clk;
-
-       clk = clk_register_fixed_rate(dev, name, parent, 0, 0);
-       if (IS_ERR_OR_NULL(clk)) {
-               dev_err(dev, "create null clk error\n");
-               return ERR_CAST(clk);
-       }
-
-       return clk;
-}
-
-static struct clk *rsnd_adg_null_clk_get(struct rsnd_priv *priv)
-{
-       struct rsnd_adg *adg = priv->adg;
-
-       if (!adg->null_clk) {
-               static const char * const name = "rsnd_adg_null";
-
-               adg->null_clk = rsnd_adg_create_null_clk(priv, name, NULL);
-       }
-
-       return adg->null_clk;
-}
-
-static void rsnd_adg_null_clk_clean(struct rsnd_priv *priv)
-{
-       struct rsnd_adg *adg = priv->adg;
-
-       if (adg->null_clk)
-               clk_unregister_fixed_rate(adg->null_clk);
-}
-
-static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
-{
-       struct rsnd_adg *adg = priv->adg;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct clk *clk;
-       const char * const *clkin_name;
-       int clkin_size;
-       int i;
-
-       clkin_name = clkin_name_gen2;
-       clkin_size = ARRAY_SIZE(clkin_name_gen2);
-       if (rsnd_is_gen4(priv)) {
-               clkin_name = clkin_name_gen4;
-               clkin_size = ARRAY_SIZE(clkin_name_gen4);
-       }
-
-       for (i = 0; i < clkin_size; i++) {
-               clk = devm_clk_get(dev, clkin_name[i]);
-
-               if (IS_ERR_OR_NULL(clk))
-                       clk = rsnd_adg_null_clk_get(priv);
-               if (IS_ERR_OR_NULL(clk))
-                       goto err;
-
-               adg->clkin[i] = clk;
-       }
-
-       adg->clkin_size = clkin_size;
-
-       return 0;
-
-err:
-       dev_err(dev, "adg clock IN get failed\n");
-
-       rsnd_adg_null_clk_clean(priv);
-
-       return -EIO;
-}
-
-static void rsnd_adg_unregister_clkout(struct rsnd_priv *priv)
-{
-       struct rsnd_adg *adg = priv->adg;
-       struct clk *clk;
-       int i;
-
-       for_each_rsnd_clkout(clk, adg, i)
-               clk_unregister_fixed_rate(clk);
-}
-
-static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
-{
-       struct rsnd_adg *adg = priv->adg;
-       struct clk *clk;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *np = dev->of_node;
-       struct property *prop;
-       u32 ckr, brgx, brga, brgb;
-       u32 req_rate[ADG_HZ_SIZE] = {};
-       uint32_t count = 0;
-       unsigned long req_Hz[ADG_HZ_SIZE];
-       int clkout_size;
-       int i, req_size;
-       int approximate = 0;
-       const char *parent_clk_name = NULL;
-       const char * const *clkout_name;
-       int brg_table[] = {
-               [CLKA] = 0x0,
-               [CLKB] = 0x1,
-               [CLKC] = 0x4,
-               [CLKI] = 0x2,
-       };
-
-       ckr = 0;
-       brga = 0xff; /* default */
-       brgb = 0xff; /* default */
-
-       /*
-        * ADG supports BRRA/BRRB output only
-        * this means all clkout0/1/2/3 will be same rate
-        */
-       prop = of_find_property(np, "clock-frequency", NULL);
-       if (!prop)
-               goto rsnd_adg_get_clkout_end;
-
-       req_size = prop->length / sizeof(u32);
-       if (req_size > ADG_HZ_SIZE) {
-               dev_err(dev, "too many clock-frequency\n");
-               return -EINVAL;
-       }
-
-       of_property_read_u32_array(np, "clock-frequency", req_rate, req_size);
-       req_Hz[ADG_HZ_48]  = 0;
-       req_Hz[ADG_HZ_441] = 0;
-       for (i = 0; i < req_size; i++) {
-               if (0 == (req_rate[i] % 44100))
-                       req_Hz[ADG_HZ_441] = req_rate[i];
-               if (0 == (req_rate[i] % 48000))
-                       req_Hz[ADG_HZ_48] = req_rate[i];
-       }
-
-       /*
-        * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
-        * have 44.1kHz or 48kHz base clocks for now.
-        *
-        * SSI itself can divide parent clock by 1/1 - 1/16
-        * see
-        *      rsnd_adg_ssi_clk_try_start()
-        *      rsnd_ssi_master_clk_start()
-        */
-
-       /*
-        * [APPROXIMATE]
-        *
-        * clk_i (internal clock) can't create accurate rate, it will be approximate rate.
-        *
-        * <Note>
-        *
-        * clk_i needs x2 of required maximum rate.
-        * see
-        *      - Minimum division of BRRA/BRRB
-        *      - rsnd_ssi_clk_query()
-        *
-        * Sample Settings for TDM 8ch, 32bit width
-        *
-        *      8(ch) x 32(bit) x 44100(Hz) x 2<Note> = 22579200
-        *      8(ch) x 32(bit) x 48000(Hz) x 2<Note> = 24576000
-        *
-        *      clock-frequency = <22579200 24576000>;
-        */
-       for_each_rsnd_clkin(clk, adg, i) {
-               u32 rate, div;
-
-               rate = clk_get_rate(clk);
-
-               if (0 == rate) /* not used */
-                       continue;
-
-               /* BRGA */
-
-               if (i == CLKI)
-                       /* see [APPROXIMATE] */
-                       rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441];
-               if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) {
-                       div = rate / req_Hz[ADG_HZ_441];
-                       brgx = rsnd_adg_calculate_brgx(div);
-                       if (BRRx_MASK(brgx) == brgx) {
-                               brga = brgx;
-                               adg->brg_rate[ADG_HZ_441] = rate / div;
-                               ckr |= brg_table[i] << 20;
-                               if (req_Hz[ADG_HZ_441])
-                                       parent_clk_name = __clk_get_name(clk);
-                               if (i == CLKI)
-                                       approximate = 1;
-                       }
-               }
-
-               /* BRGB */
-
-               if (i == CLKI)
-                       /* see [APPROXIMATE] */
-                       rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48];
-               if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) {
-                       div = rate / req_Hz[ADG_HZ_48];
-                       brgx = rsnd_adg_calculate_brgx(div);
-                       if (BRRx_MASK(brgx) == brgx) {
-                               brgb = brgx;
-                               adg->brg_rate[ADG_HZ_48] = rate / div;
-                               ckr |= brg_table[i] << 16;
-                               if (req_Hz[ADG_HZ_48])
-                                       parent_clk_name = __clk_get_name(clk);
-                               if (i == CLKI)
-                                       approximate = 1;
-                       }
-               }
-       }
-
-       if (!(adg->brg_rate[ADG_HZ_48]  && req_Hz[ADG_HZ_48]) &&
-           !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441]))
-               goto rsnd_adg_get_clkout_end;
-
-       if (approximate)
-               dev_info(dev, "It uses CLK_I as approximate rate");
-
-       clkout_name = clkout_name_gen2;
-       clkout_size = ARRAY_SIZE(clkout_name_gen2);
-       if (rsnd_is_gen4(priv))
-               clkout_size = 1; /* reuse clkout_name_gen2[] */
-
-       /*
-        * ADG supports BRRA/BRRB output only.
-        * this means all clkout0/1/2/3 will be * same rate
-        */
-
-       of_property_read_u32(np, "#clock-cells", &count);
-       /*
-        * for clkout
-        */
-       if (!count) {
-               clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
-                                             parent_clk_name, 0, req_rate[0]);
-               if (IS_ERR_OR_NULL(clk))
-                       goto err;
-
-               adg->clkout[CLKOUT] = clk;
-               adg->clkout_size = 1;
-               of_clk_add_provider(np, of_clk_src_simple_get, clk);
-       }
-       /*
-        * for clkout0/1/2/3
-        */
-       else {
-               for (i = 0; i < clkout_size; i++) {
-                       clk = clk_register_fixed_rate(dev, clkout_name[i],
-                                                     parent_clk_name, 0,
-                                                     req_rate[0]);
-                       if (IS_ERR_OR_NULL(clk))
-                               goto err;
-
-                       adg->clkout[i] = clk;
-               }
-               adg->onecell.clks       = adg->clkout;
-               adg->onecell.clk_num    = clkout_size;
-               adg->clkout_size        = clkout_size;
-               of_clk_add_provider(np, of_clk_src_onecell_get,
-                                   &adg->onecell);
-       }
-
-rsnd_adg_get_clkout_end:
-       adg->ckr = ckr;
-       adg->brga = brga;
-       adg->brgb = brgb;
-
-       return 0;
-
-err:
-       dev_err(dev, "adg clock OUT get failed\n");
-
-       rsnd_adg_unregister_clkout(priv);
-
-       return -EIO;
-}
-
-#if defined(DEBUG) || defined(CONFIG_DEBUG_FS)
-__printf(3, 4)
-static void dbg_msg(struct device *dev, struct seq_file *m,
-                                  const char *fmt, ...)
-{
-       char msg[128];
-       va_list args;
-
-       va_start(args, fmt);
-       vsnprintf(msg, sizeof(msg), fmt, args);
-       va_end(args);
-
-       if (m)
-               seq_puts(m, msg);
-       else
-               dev_dbg(dev, "%s", msg);
-}
-
-void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m)
-{
-       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct clk *clk;
-       int i;
-
-       for_each_rsnd_clkin(clk, adg, i)
-               dbg_msg(dev, m, "%-18s : %pa : %ld\n",
-                       __clk_get_name(clk), clk, clk_get_rate(clk));
-
-       dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
-               adg->ckr, adg->brga, adg->brgb);
-       dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->brg_rate[ADG_HZ_441]);
-       dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->brg_rate[ADG_HZ_48]);
-
-       /*
-        * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
-        * by BRGCKR::BRGCKR_31
-        */
-       for_each_rsnd_clkout(clk, adg, i)
-               dbg_msg(dev, m, "%-18s : %pa : %ld\n",
-                       __clk_get_name(clk), clk, clk_get_rate(clk));
-}
-#else
-#define rsnd_adg_clk_dbg_info(priv, m)
-#endif
-
-int rsnd_adg_probe(struct rsnd_priv *priv)
-{
-       struct rsnd_adg *adg;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int ret;
-
-       adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
-       if (!adg)
-               return -ENOMEM;
-
-       ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
-                     NULL, 0, 0);
-       if (ret)
-               return ret;
-
-       priv->adg = adg;
-
-       ret = rsnd_adg_get_clkin(priv);
-       if (ret)
-               return ret;
-
-       ret = rsnd_adg_get_clkout(priv);
-       if (ret)
-               return ret;
-
-       rsnd_adg_clk_enable(priv);
-       rsnd_adg_clk_dbg_info(priv, NULL);
-
-       return 0;
-}
-
-void rsnd_adg_remove(struct rsnd_priv *priv)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *np = dev->of_node;
-
-       rsnd_adg_unregister_clkout(priv);
-
-       of_clk_del_provider(np);
-
-       rsnd_adg_clk_disable(priv);
-
-       /* It should be called after rsnd_adg_clk_disable() */
-       rsnd_adg_null_clk_clean(priv);
-}
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
deleted file mode 100644 (file)
index 8d9a1e3..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car CMD support
-//
-// Copyright (C) 2015 Renesas Solutions Corp.
-// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-#include "rsnd.h"
-
-struct rsnd_cmd {
-       struct rsnd_mod mod;
-};
-
-#define CMD_NAME "cmd"
-
-#define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
-#define for_each_rsnd_cmd(pos, priv, i)                                        \
-       for ((i) = 0;                                                   \
-            ((i) < rsnd_cmd_nr(priv)) &&                               \
-                    ((pos) = (struct rsnd_cmd *)(priv)->cmd + i);      \
-            i++)
-
-static int rsnd_cmd_init(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
-       struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       u32 data;
-       static const u32 path[] = {
-               [1] = 1 << 0,
-               [5] = 1 << 8,
-               [6] = 1 << 12,
-               [9] = 1 << 15,
-       };
-
-       if (!mix && !dvc)
-               return 0;
-
-       if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1)
-               return -ENXIO;
-
-       if (mix) {
-               struct rsnd_dai *rdai;
-               int i;
-
-               /*
-                * it is assuming that integrater is well understanding about
-                * data path. Here doesn't check impossible connection,
-                * like src2 + src5
-                */
-               data = 0;
-               for_each_rsnd_dai(rdai, priv, i) {
-                       struct rsnd_dai_stream *tio = &rdai->playback;
-                       struct rsnd_mod *src = rsnd_io_to_mod_src(tio);
-
-                       if (mix == rsnd_io_to_mod_mix(tio))
-                               data |= path[rsnd_mod_id(src)];
-
-                       tio = &rdai->capture;
-                       src = rsnd_io_to_mod_src(tio);
-                       if (mix == rsnd_io_to_mod_mix(tio))
-                               data |= path[rsnd_mod_id(src)];
-               }
-
-       } else {
-               struct rsnd_mod *src = rsnd_io_to_mod_src(io);
-
-               static const u8 cmd_case[] = {
-                       [0] = 0x3,
-                       [1] = 0x3,
-                       [2] = 0x4,
-                       [3] = 0x1,
-                       [4] = 0x2,
-                       [5] = 0x4,
-                       [6] = 0x1,
-                       [9] = 0x2,
-               };
-
-               if (unlikely(!src))
-                       return -EIO;
-
-               data = path[rsnd_mod_id(src)] |
-                       cmd_case[rsnd_mod_id(src)] << 16;
-       }
-
-       dev_dbg(dev, "ctu/mix path = 0x%08x\n", data);
-
-       rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
-       rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1);
-       rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
-
-       rsnd_adg_set_cmd_timsel_gen2(mod, io);
-
-       return 0;
-}
-
-static int rsnd_cmd_start(struct rsnd_mod *mod,
-                         struct rsnd_dai_stream *io,
-                         struct rsnd_priv *priv)
-{
-       rsnd_mod_write(mod, CMD_CTRL, 0x10);
-
-       return 0;
-}
-
-static int rsnd_cmd_stop(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       rsnd_mod_write(mod, CMD_CTRL, 0);
-
-       return 0;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void rsnd_cmd_debug_info(struct seq_file *m,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_mod *mod)
-{
-       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
-                                 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30);
-}
-#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info
-#else
-#define DEBUG_INFO
-#endif
-
-static struct rsnd_mod_ops rsnd_cmd_ops = {
-       .name           = CMD_NAME,
-       .init           = rsnd_cmd_init,
-       .start          = rsnd_cmd_start,
-       .stop           = rsnd_cmd_stop,
-       .get_status     = rsnd_mod_get_status,
-       DEBUG_INFO
-};
-
-static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
-{
-       if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
-               id = 0;
-
-       return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
-}
-int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
-{
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
-
-       return rsnd_dai_connect(mod, io, mod->type);
-}
-
-int rsnd_cmd_probe(struct rsnd_priv *priv)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_cmd *cmd;
-       int i, nr;
-
-       /* same number as DVC */
-       nr = priv->dvc_nr;
-       if (!nr)
-               return 0;
-
-       cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL);
-       if (!cmd)
-               return -ENOMEM;
-
-       priv->cmd_nr    = nr;
-       priv->cmd       = cmd;
-
-       for_each_rsnd_cmd(cmd, priv, i) {
-               int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
-                                       &rsnd_cmd_ops, NULL,
-                                       RSND_MOD_CMD, i);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-void rsnd_cmd_remove(struct rsnd_priv *priv)
-{
-       struct rsnd_cmd *cmd;
-       int i;
-
-       for_each_rsnd_cmd(cmd, priv, i) {
-               rsnd_mod_quit(rsnd_mod_get(cmd));
-       }
-}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
deleted file mode 100644 (file)
index c32e88d..0000000
+++ /dev/null
@@ -1,2112 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car SRU/SCU/SSIU/SSI support
-//
-// Copyright (C) 2013 Renesas Solutions Corp.
-// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-//
-// Based on fsi.c
-// Kuninori Morimoto <morimoto.kuninori@renesas.com>
-
-/*
- * Renesas R-Car sound device structure
- *
- * Gen1
- *
- * SRU         : Sound Routing Unit
- *  - SRC      : Sampling Rate Converter
- *  - CMD
- *    - CTU    : Channel Count Conversion Unit
- *    - MIX    : Mixer
- *    - DVC    : Digital Volume and Mute Function
- *  - SSI      : Serial Sound Interface
- *
- * Gen2
- *
- * SCU         : Sampling Rate Converter Unit
- *  - SRC      : Sampling Rate Converter
- *  - CMD
- *   - CTU     : Channel Count Conversion Unit
- *   - MIX     : Mixer
- *   - DVC     : Digital Volume and Mute Function
- * SSIU                : Serial Sound Interface Unit
- *  - SSI      : Serial Sound Interface
- */
-
-/*
- *     driver data Image
- *
- * rsnd_priv
- *   |
- *   | ** this depends on Gen1/Gen2
- *   |
- *   +- gen
- *   |
- *   | ** these depend on data path
- *   | ** gen and platform data control it
- *   |
- *   +- rdai[0]
- *   |   |              sru     ssiu      ssi
- *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
- *   |   |
- *   |   |              sru     ssiu      ssi
- *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
- *   |
- *   +- rdai[1]
- *   |   |              sru     ssiu      ssi
- *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
- *   |   |
- *   |   |              sru     ssiu      ssi
- *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
- *   ...
- *   |
- *   | ** these control ssi
- *   |
- *   +- ssi
- *   |  |
- *   |  +- ssi[0]
- *   |  +- ssi[1]
- *   |  +- ssi[2]
- *   |  ...
- *   |
- *   | ** these control src
- *   |
- *   +- src
- *      |
- *      +- src[0]
- *      +- src[1]
- *      +- src[2]
- *      ...
- *
- *
- * for_each_rsnd_dai(xx, priv, xx)
- *  rdai[0] => rdai[1] => rdai[2] => ...
- *
- * for_each_rsnd_mod(xx, rdai, xx)
- *  [mod] => [mod] => [mod] => ...
- *
- * rsnd_dai_call(xxx, fn )
- *  [mod]->fn() -> [mod]->fn() -> [mod]->fn()...
- *
- */
-
-#include <linux/pm_runtime.h>
-#include <linux/of_graph.h>
-#include "rsnd.h"
-
-#define RSND_RATES SNDRV_PCM_RATE_8000_192000
-#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\
-                  SNDRV_PCM_FMTBIT_S16_LE |\
-                  SNDRV_PCM_FMTBIT_S24_LE)
-
-static const struct of_device_id rsnd_of_match[] = {
-       { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
-       { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
-       { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 },
-       { .compatible = "renesas,rcar_sound-gen4", .data = (void *)RSND_GEN4 },
-       /* Special Handling */
-       { .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) },
-       {},
-};
-MODULE_DEVICE_TABLE(of, rsnd_of_match);
-
-/*
- *     rsnd_mod functions
- */
-void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
-{
-       if (mod->type != type) {
-               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-               struct device *dev = rsnd_priv_to_dev(priv);
-
-               dev_warn(dev, "%s is not your expected module\n",
-                        rsnd_mod_name(mod));
-       }
-}
-
-struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
-                                 struct rsnd_mod *mod)
-{
-       if (!mod || !mod->ops || !mod->ops->dma_req)
-               return NULL;
-
-       return mod->ops->dma_req(io, mod);
-}
-
-#define MOD_NAME_NUM   5
-#define MOD_NAME_SIZE 16
-char *rsnd_mod_name(struct rsnd_mod *mod)
-{
-       static char names[MOD_NAME_NUM][MOD_NAME_SIZE];
-       static int num;
-       char *name = names[num];
-
-       num++;
-       if (num >= MOD_NAME_NUM)
-               num = 0;
-
-       /*
-        * Let's use same char to avoid pointlessness memory
-        * Thus, rsnd_mod_name() should be used immediately
-        * Don't keep pointer
-        */
-       if ((mod)->ops->id_sub) {
-               snprintf(name, MOD_NAME_SIZE, "%s[%d%d]",
-                        mod->ops->name,
-                        rsnd_mod_id(mod),
-                        rsnd_mod_id_sub(mod));
-       } else {
-               snprintf(name, MOD_NAME_SIZE, "%s[%d]",
-                        mod->ops->name,
-                        rsnd_mod_id(mod));
-       }
-
-       return name;
-}
-
-u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        enum rsnd_mod_type type)
-{
-       return &mod->status;
-}
-
-int rsnd_mod_id_raw(struct rsnd_mod *mod)
-{
-       return mod->id;
-}
-
-int rsnd_mod_id(struct rsnd_mod *mod)
-{
-       if ((mod)->ops->id)
-               return (mod)->ops->id(mod);
-
-       return rsnd_mod_id_raw(mod);
-}
-
-int rsnd_mod_id_sub(struct rsnd_mod *mod)
-{
-       if ((mod)->ops->id_sub)
-               return (mod)->ops->id_sub(mod);
-
-       return 0;
-}
-
-int rsnd_mod_init(struct rsnd_priv *priv,
-                 struct rsnd_mod *mod,
-                 struct rsnd_mod_ops *ops,
-                 struct clk *clk,
-                 enum rsnd_mod_type type,
-                 int id)
-{
-       int ret = clk_prepare(clk);
-
-       if (ret)
-               return ret;
-
-       mod->id         = id;
-       mod->ops        = ops;
-       mod->type       = type;
-       mod->clk        = clk;
-       mod->priv       = priv;
-
-       return 0;
-}
-
-void rsnd_mod_quit(struct rsnd_mod *mod)
-{
-       clk_unprepare(mod->clk);
-       mod->clk = NULL;
-}
-
-void rsnd_mod_interrupt(struct rsnd_mod *mod,
-                       void (*callback)(struct rsnd_mod *mod,
-                                        struct rsnd_dai_stream *io))
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dai *rdai;
-       int i;
-
-       for_each_rsnd_dai(rdai, priv, i) {
-               struct rsnd_dai_stream *io = &rdai->playback;
-
-               if (mod == io->mod[mod->type])
-                       callback(mod, io);
-
-               io = &rdai->capture;
-               if (mod == io->mod[mod->type])
-                       callback(mod, io);
-       }
-}
-
-int rsnd_io_is_working(struct rsnd_dai_stream *io)
-{
-       /* see rsnd_dai_stream_init/quit() */
-       if (io->substream)
-               return snd_pcm_running(io->substream);
-
-       return 0;
-}
-
-int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
-                                             struct snd_pcm_hw_params *params)
-{
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-
-       /*
-        * params will be added when refine
-        * see
-        *      __rsnd_soc_hw_rule_rate()
-        *      __rsnd_soc_hw_rule_channels()
-        */
-       if (params)
-               return params_channels(params);
-       else if (runtime)
-               return runtime->channels;
-       return 0;
-}
-
-int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
-                                              struct snd_pcm_hw_params *params)
-{
-       int chan = rsnd_runtime_channel_original_with_params(io, params);
-       struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
-
-       if (ctu_mod) {
-               u32 converted_chan = rsnd_io_converted_chan(io);
-
-               /*
-                * !! Note !!
-                *
-                * converted_chan will be used for CTU,
-                * or TDM Split mode.
-                * User shouldn't use CTU with TDM Split mode.
-                */
-               if (rsnd_runtime_is_tdm_split(io)) {
-                       struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
-
-                       dev_err(dev, "CTU and TDM Split should be used\n");
-               }
-
-               if (converted_chan)
-                       return converted_chan;
-       }
-
-       return chan;
-}
-
-int rsnd_channel_normalization(int chan)
-{
-       if (WARN_ON((chan > 8) || (chan < 0)))
-               return 0;
-
-       /* TDM Extend Mode needs 8ch */
-       if (chan == 6)
-               chan = 8;
-
-       return chan;
-}
-
-int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
-                                            struct snd_pcm_hw_params *params)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       int chan = rsnd_io_is_play(io) ?
-               rsnd_runtime_channel_after_ctu_with_params(io, params) :
-               rsnd_runtime_channel_original_with_params(io, params);
-
-       /* Use Multi SSI */
-       if (rsnd_runtime_is_multi_ssi(io))
-               chan /= rsnd_rdai_ssi_lane_get(rdai);
-
-       return rsnd_channel_normalization(chan);
-}
-
-int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       int lane = rsnd_rdai_ssi_lane_get(rdai);
-       int chan = rsnd_io_is_play(io) ?
-               rsnd_runtime_channel_after_ctu(io) :
-               rsnd_runtime_channel_original(io);
-
-       return (chan > 2) && (lane > 1);
-}
-
-int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io)
-{
-       return rsnd_runtime_channel_for_ssi(io) >= 6;
-}
-
-int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io)
-{
-       return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT);
-}
-
-/*
- *     ADINR function
- */
-u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       switch (snd_pcm_format_width(runtime->format)) {
-       case 8:
-               return 16 << 16;
-       case 16:
-               return 8 << 16;
-       case 24:
-               return 0 << 16;
-       }
-
-       dev_warn(dev, "not supported sample bits\n");
-
-       return 0;
-}
-
-/*
- *     DALIGN function
- */
-u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
-{
-       static const u32 dalign_values[8] = {
-               0x76543210, 0x00000032, 0x00007654, 0x00000076,
-               0xfedcba98, 0x000000ba, 0x0000fedc, 0x000000fe,
-       };
-       int id = 0;
-       struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
-       struct rsnd_mod *target;
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       u32 dalign;
-
-       /*
-        * *Hardware* L/R and *Software* L/R are inverted for 16bit data.
-        *          31..16 15...0
-        *      HW: [L ch] [R ch]
-        *      SW: [R ch] [L ch]
-        * We need to care about inversion timing to control
-        * Playback/Capture correctly.
-        * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R
-        *
-        * sL/R : software L/R
-        * hL/R : hardware L/R
-        * (*)  : conversion timing
-        *
-        * Playback
-        *           sL/R (*) hL/R     hL/R     hL/R      hL/R     hL/R
-        *      [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec
-        *
-        * Capture
-        *           hL/R     hL/R      hL/R     hL/R     hL/R (*) sL/R
-        *      codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM]
-        */
-       if (rsnd_io_is_play(io)) {
-               struct rsnd_mod *src = rsnd_io_to_mod_src(io);
-
-               target = src ? src : ssiu;
-       } else {
-               struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io);
-
-               target = cmd ? cmd : ssiu;
-       }
-
-       if (mod == ssiu)
-               id = rsnd_mod_id_sub(mod);
-
-       dalign = dalign_values[id];
-
-       if (mod == target && snd_pcm_format_width(runtime->format) == 16) {
-               /* Target mod needs inverted DALIGN when 16bit */
-               dalign = (dalign & 0xf0f0f0f0) >> 4 |
-                        (dalign & 0x0f0f0f0f) << 4;
-       }
-
-       return dalign;
-}
-
-u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
-{
-       static const enum rsnd_mod_type playback_mods[] = {
-               RSND_MOD_SRC,
-               RSND_MOD_CMD,
-               RSND_MOD_SSIU,
-       };
-       static const enum rsnd_mod_type capture_mods[] = {
-               RSND_MOD_CMD,
-               RSND_MOD_SRC,
-               RSND_MOD_SSIU,
-       };
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_mod *tmod = NULL;
-       const enum rsnd_mod_type *mods =
-               rsnd_io_is_play(io) ?
-               playback_mods : capture_mods;
-       int i;
-
-       /*
-        * This is needed for 24bit data
-        * We need to shift 8bit
-        *
-        * Linux 24bit data is located as 0x00******
-        * HW    24bit data is located as 0x******00
-        *
-        */
-       if (snd_pcm_format_width(runtime->format) != 24)
-               return 0;
-
-       for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
-               tmod = rsnd_io_to_mod(io, mods[i]);
-               if (tmod)
-                       break;
-       }
-
-       if (tmod != mod)
-               return 0;
-
-       if (rsnd_io_is_play(io))
-               return  (0 << 20) | /* shift to Left */
-                       (8 << 16);  /* 8bit */
-       else
-               return  (1 << 20) | /* shift to Right */
-                       (8 << 16);  /* 8bit */
-}
-
-/*
- *     rsnd_dai functions
- */
-struct rsnd_mod *rsnd_mod_next(int *iterator,
-                              struct rsnd_dai_stream *io,
-                              enum rsnd_mod_type *array,
-                              int array_size)
-{
-       int max = array ? array_size : RSND_MOD_MAX;
-
-       for (; *iterator < max; (*iterator)++) {
-               enum rsnd_mod_type type = (array) ? array[*iterator] : *iterator;
-               struct rsnd_mod *mod = rsnd_io_to_mod(io, type);
-
-               if (mod)
-                       return mod;
-       }
-
-       return NULL;
-}
-
-static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = {
-       {
-               /* CAPTURE */
-               RSND_MOD_AUDMAPP,
-               RSND_MOD_AUDMA,
-               RSND_MOD_DVC,
-               RSND_MOD_MIX,
-               RSND_MOD_CTU,
-               RSND_MOD_CMD,
-               RSND_MOD_SRC,
-               RSND_MOD_SSIU,
-               RSND_MOD_SSIM3,
-               RSND_MOD_SSIM2,
-               RSND_MOD_SSIM1,
-               RSND_MOD_SSIP,
-               RSND_MOD_SSI,
-       }, {
-               /* PLAYBACK */
-               RSND_MOD_AUDMAPP,
-               RSND_MOD_AUDMA,
-               RSND_MOD_SSIM3,
-               RSND_MOD_SSIM2,
-               RSND_MOD_SSIM1,
-               RSND_MOD_SSIP,
-               RSND_MOD_SSI,
-               RSND_MOD_SSIU,
-               RSND_MOD_DVC,
-               RSND_MOD_MIX,
-               RSND_MOD_CTU,
-               RSND_MOD_CMD,
-               RSND_MOD_SRC,
-       },
-};
-
-static int rsnd_status_update(struct rsnd_dai_stream *io,
-                             struct rsnd_mod *mod, enum rsnd_mod_type type,
-                             int shift, int add, int timing)
-{
-       u32 *status     = mod->ops->get_status(mod, io, type);
-       u32 mask        = 0xF << shift;
-       u8 val          = (*status >> shift) & 0xF;
-       u8 next_val     = (val + add) & 0xF;
-       int func_call   = (val == timing);
-
-       /* no status update */
-       if (add == 0 || shift == 28)
-               return 1;
-
-       if (next_val == 0xF) /* underflow case */
-               func_call = -1;
-       else
-               *status = (*status & ~mask) + (next_val << shift);
-
-       return func_call;
-}
-
-#define rsnd_dai_call(fn, io, param...)                                        \
-({                                                                     \
-       struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));     \
-       struct rsnd_mod *mod;                                           \
-       int is_play = rsnd_io_is_play(io);                              \
-       int ret = 0, i;                                                 \
-       enum rsnd_mod_type *types = rsnd_mod_sequence[is_play];         \
-       for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) {     \
-               int tmp = 0;                                            \
-               int func_call = rsnd_status_update(io, mod, types[i],   \
-                                               __rsnd_mod_shift_##fn,  \
-                                               __rsnd_mod_add_##fn,    \
-                                               __rsnd_mod_call_##fn);  \
-               if (func_call > 0 && (mod)->ops->fn)                    \
-                       tmp = (mod)->ops->fn(mod, io, param);           \
-               if (unlikely(func_call < 0) ||                          \
-                   unlikely(tmp && (tmp != -EPROBE_DEFER)))            \
-                       dev_err(dev, "%s : %s error (%d, %d)\n",        \
-                               rsnd_mod_name(mod), #fn, tmp, func_call);\
-               ret |= tmp;                                             \
-       }                                                               \
-       ret;                                                            \
-})
-
-int rsnd_dai_connect(struct rsnd_mod *mod,
-                    struct rsnd_dai_stream *io,
-                    enum rsnd_mod_type type)
-{
-       struct rsnd_priv *priv;
-       struct device *dev;
-
-       if (!mod)
-               return -EIO;
-
-       if (io->mod[type] == mod)
-               return 0;
-
-       if (io->mod[type])
-               return -EINVAL;
-
-       priv = rsnd_mod_to_priv(mod);
-       dev = rsnd_priv_to_dev(priv);
-
-       io->mod[type] = mod;
-
-       dev_dbg(dev, "%s is connected to io (%s)\n",
-               rsnd_mod_name(mod),
-               rsnd_io_is_play(io) ? "Playback" : "Capture");
-
-       return 0;
-}
-
-static void rsnd_dai_disconnect(struct rsnd_mod *mod,
-                               struct rsnd_dai_stream *io,
-                               enum rsnd_mod_type type)
-{
-       io->mod[type] = NULL;
-}
-
-int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai,
-                           int max_channels)
-{
-       if (max_channels > 0)
-               rdai->max_channels = max_channels;
-
-       return rdai->max_channels;
-}
-
-int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
-                           int ssi_lane)
-{
-       if (ssi_lane > 0)
-               rdai->ssi_lane = ssi_lane;
-
-       return rdai->ssi_lane;
-}
-
-int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width)
-{
-       if (width > 0)
-               rdai->chan_width = width;
-
-       return rdai->chan_width;
-}
-
-struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
-{
-       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
-               return NULL;
-
-       return priv->rdai + id;
-}
-
-static struct snd_soc_dai_driver
-*rsnd_daidrv_get(struct rsnd_priv *priv, int id)
-{
-       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
-               return NULL;
-
-       return priv->daidrv + id;
-}
-
-#define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai)
-static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
-{
-       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
-
-       return rsnd_rdai_get(priv, dai->id);
-}
-
-static void rsnd_dai_stream_init(struct rsnd_dai_stream *io,
-                               struct snd_pcm_substream *substream)
-{
-       io->substream           = substream;
-}
-
-static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io)
-{
-       io->substream           = NULL;
-}
-
-static
-struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-
-       return snd_soc_rtd_to_cpu(rtd, 0);
-}
-
-static
-struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai,
-                                       struct snd_pcm_substream *substream)
-{
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               return &rdai->playback;
-       else
-               return &rdai->capture;
-}
-
-static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
-                           struct snd_soc_dai *dai)
-{
-       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-               ret = rsnd_dai_call(init, io, priv);
-               if (ret < 0)
-                       goto dai_trigger_end;
-
-               ret = rsnd_dai_call(start, io, priv);
-               if (ret < 0)
-                       goto dai_trigger_end;
-
-               ret = rsnd_dai_call(irq, io, priv, 1);
-               if (ret < 0)
-                       goto dai_trigger_end;
-
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-               ret = rsnd_dai_call(irq, io, priv, 0);
-
-               ret |= rsnd_dai_call(stop, io, priv);
-
-               ret |= rsnd_dai_call(quit, io, priv);
-
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-dai_trigger_end:
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return ret;
-}
-
-static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-
-       /* set clock master for audio interface */
-       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_BC_FC:
-               rdai->clk_master = 0;
-               break;
-       case SND_SOC_DAIFMT_BP_FP:
-               rdai->clk_master = 1; /* cpu is master */
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* set format */
-       rdai->bit_clk_inv = 0;
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               rdai->sys_delay = 0;
-               rdai->data_alignment = 0;
-               rdai->frm_clk_inv = 0;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-       case SND_SOC_DAIFMT_DSP_B:
-               rdai->sys_delay = 1;
-               rdai->data_alignment = 0;
-               rdai->frm_clk_inv = 1;
-               break;
-       case SND_SOC_DAIFMT_RIGHT_J:
-               rdai->sys_delay = 1;
-               rdai->data_alignment = 1;
-               rdai->frm_clk_inv = 1;
-               break;
-       case SND_SOC_DAIFMT_DSP_A:
-               rdai->sys_delay = 0;
-               rdai->data_alignment = 0;
-               rdai->frm_clk_inv = 1;
-               break;
-       }
-
-       /* set clock inversion */
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_IF:
-               rdai->frm_clk_inv = !rdai->frm_clk_inv;
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               rdai->bit_clk_inv = !rdai->bit_clk_inv;
-               break;
-       case SND_SOC_DAIFMT_IB_IF:
-               rdai->bit_clk_inv = !rdai->bit_clk_inv;
-               rdai->frm_clk_inv = !rdai->frm_clk_inv;
-               break;
-       case SND_SOC_DAIFMT_NB_NF:
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
-                                    u32 tx_mask, u32 rx_mask,
-                                    int slots, int slot_width)
-{
-       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       switch (slot_width) {
-       case 16:
-       case 24:
-       case 32:
-               break;
-       default:
-               /* use default */
-               /*
-                * Indicate warning if DT has "dai-tdm-slot-width"
-                * but the value was not expected.
-                */
-               if (slot_width)
-                       dev_warn(dev, "unsupported TDM slot width (%d), force to use default 32\n",
-                                slot_width);
-               slot_width = 32;
-       }
-
-       switch (slots) {
-       case 2:
-               /* TDM Split Mode */
-       case 6:
-       case 8:
-               /* TDM Extend Mode */
-               rsnd_rdai_channels_set(rdai, slots);
-               rsnd_rdai_ssi_lane_set(rdai, 1);
-               rsnd_rdai_width_set(rdai, slot_width);
-               break;
-       default:
-               dev_err(dev, "unsupported TDM slots (%d)\n", slots);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static unsigned int rsnd_soc_hw_channels_list[] = {
-       2, 6, 8,
-};
-
-static unsigned int rsnd_soc_hw_rate_list[] = {
-         8000,
-        11025,
-        16000,
-        22050,
-        32000,
-        44100,
-        48000,
-        64000,
-        88200,
-        96000,
-       176400,
-       192000,
-};
-
-static int rsnd_soc_hw_rule(struct rsnd_dai *rdai,
-                           unsigned int *list, int list_num,
-                           struct snd_interval *baseline, struct snd_interval *iv,
-                           struct rsnd_dai_stream *io, char *unit)
-{
-       struct snd_interval p;
-       unsigned int rate;
-       int i;
-
-       snd_interval_any(&p);
-       p.min = UINT_MAX;
-       p.max = 0;
-
-       for (i = 0; i < list_num; i++) {
-
-               if (!snd_interval_test(iv, list[i]))
-                       continue;
-
-               rate = rsnd_ssi_clk_query(rdai,
-                                         baseline->min, list[i], NULL);
-               if (rate > 0) {
-                       p.min = min(p.min, list[i]);
-                       p.max = max(p.max, list[i]);
-               }
-
-               rate = rsnd_ssi_clk_query(rdai,
-                                         baseline->max, list[i], NULL);
-               if (rate > 0) {
-                       p.min = min(p.min, list[i]);
-                       p.max = max(p.max, list[i]);
-               }
-       }
-
-       /* Indicate error once if it can't handle */
-       if (!rsnd_flags_has(io, RSND_HW_RULE_ERR) && (p.min > p.max)) {
-               struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-               struct device *dev = rsnd_priv_to_dev(priv);
-
-               dev_warn(dev, "It can't handle %d %s <-> %d %s\n",
-                        baseline->min, unit, baseline->max, unit);
-               rsnd_flags_set(io, RSND_HW_RULE_ERR);
-       }
-
-       return snd_interval_refine(iv, &p);
-}
-
-static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
-                                struct snd_pcm_hw_rule *rule)
-{
-       struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-       struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval ic;
-       struct rsnd_dai_stream *io = rule->private;
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-
-       /*
-        * possible sampling rate limitation is same as
-        * 2ch if it supports multi ssi
-        * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
-        */
-       ic = *ic_;
-       ic.min =
-       ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
-
-       return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list,
-                               ARRAY_SIZE(rsnd_soc_hw_rate_list),
-                               &ic, ir, io, "ch");
-}
-
-static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
-                                    struct snd_pcm_hw_rule *rule)
-{
-       struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-       struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval ic;
-       struct rsnd_dai_stream *io = rule->private;
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-
-       /*
-        * possible sampling rate limitation is same as
-        * 2ch if it supports multi ssi
-        * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
-        */
-       ic = *ic_;
-       ic.min =
-       ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
-
-       return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list,
-                               ARRAY_SIZE(rsnd_soc_hw_channels_list),
-                               ir, &ic, io, "Hz");
-}
-
-static const struct snd_pcm_hardware rsnd_pcm_hardware = {
-       .info =         SNDRV_PCM_INFO_INTERLEAVED      |
-                       SNDRV_PCM_INFO_MMAP             |
-                       SNDRV_PCM_INFO_MMAP_VALID,
-       .buffer_bytes_max       = 64 * 1024,
-       .period_bytes_min       = 32,
-       .period_bytes_max       = 8192,
-       .periods_min            = 1,
-       .periods_max            = 32,
-       .fifo_size              = 256,
-};
-
-static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
-{
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-       struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int max_channels = rsnd_rdai_channels_get(rdai);
-       int i;
-
-       rsnd_flags_del(io, RSND_HW_RULE_ERR);
-
-       rsnd_dai_stream_init(io, substream);
-
-       /*
-        * Channel Limitation
-        * It depends on Platform design
-        */
-       constraint->list        = rsnd_soc_hw_channels_list;
-       constraint->count       = 0;
-       constraint->mask        = 0;
-
-       for (i = 0; i < ARRAY_SIZE(rsnd_soc_hw_channels_list); i++) {
-               if (rsnd_soc_hw_channels_list[i] > max_channels)
-                       break;
-               constraint->count = i + 1;
-       }
-
-       snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
-
-       snd_pcm_hw_constraint_list(runtime, 0,
-                                  SNDRV_PCM_HW_PARAM_CHANNELS, constraint);
-
-       snd_pcm_hw_constraint_integer(runtime,
-                                     SNDRV_PCM_HW_PARAM_PERIODS);
-
-       /*
-        * Sampling Rate / Channel Limitation
-        * It depends on Clock Master Mode
-        */
-       if (rsnd_rdai_is_clk_master(rdai)) {
-               int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-
-               snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                                   rsnd_soc_hw_rule_rate,
-                                   is_play ? &rdai->playback : &rdai->capture,
-                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
-               snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                                   rsnd_soc_hw_rule_channels,
-                                   is_play ? &rdai->playback : &rdai->capture,
-                                   SNDRV_PCM_HW_PARAM_RATE, -1);
-       }
-
-       return 0;
-}
-
-static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
-{
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-
-       /*
-        * call rsnd_dai_call without spinlock
-        */
-       rsnd_dai_call(cleanup, io, priv);
-
-       rsnd_dai_stream_quit(io);
-}
-
-static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
-{
-       struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-
-       return rsnd_dai_call(prepare, io, priv);
-}
-
-static const u64 rsnd_soc_dai_formats[] = {
-       /*
-        * 1st Priority
-        *
-        * Well tested formats.
-        * Select below from Sound Card, not auto
-        *      SND_SOC_DAIFMT_CBC_CFC
-        *      SND_SOC_DAIFMT_CBP_CFP
-        */
-       SND_SOC_POSSIBLE_DAIFMT_I2S     |
-       SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
-       SND_SOC_POSSIBLE_DAIFMT_LEFT_J  |
-       SND_SOC_POSSIBLE_DAIFMT_NB_NF   |
-       SND_SOC_POSSIBLE_DAIFMT_NB_IF   |
-       SND_SOC_POSSIBLE_DAIFMT_IB_NF   |
-       SND_SOC_POSSIBLE_DAIFMT_IB_IF,
-       /*
-        * 2nd Priority
-        *
-        * Supported, but not well tested
-        */
-       SND_SOC_POSSIBLE_DAIFMT_DSP_A   |
-       SND_SOC_POSSIBLE_DAIFMT_DSP_B,
-};
-
-static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
-                                     struct rsnd_dai_stream *io,
-                                     struct device_node *dai_np)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *ssiu_np = rsnd_ssiu_of_node(priv);
-       struct device_node *np;
-       int is_play = rsnd_io_is_play(io);
-       int i;
-
-       if (!ssiu_np)
-               return;
-
-       /*
-        * This driver assumes that it is TDM Split mode
-        * if it includes ssiu node
-        */
-       for (i = 0;; i++) {
-               struct device_node *node = is_play ?
-                       of_parse_phandle(dai_np, "playback", i) :
-                       of_parse_phandle(dai_np, "capture",  i);
-
-               if (!node)
-                       break;
-
-               for_each_child_of_node(ssiu_np, np) {
-                       if (np == node) {
-                               rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT);
-                               dev_dbg(dev, "%s is part of TDM Split\n", io->name);
-                       }
-               }
-
-               of_node_put(node);
-       }
-
-       of_node_put(ssiu_np);
-}
-
-static void rsnd_parse_connect_simple(struct rsnd_priv *priv,
-                                     struct rsnd_dai_stream *io,
-                                     struct device_node *dai_np)
-{
-       if (!rsnd_io_to_mod_ssi(io))
-               return;
-
-       rsnd_parse_tdm_split_mode(priv, io, dai_np);
-}
-
-static void rsnd_parse_connect_graph(struct rsnd_priv *priv,
-                                    struct rsnd_dai_stream *io,
-                                    struct device_node *endpoint)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *remote_node;
-
-       if (!rsnd_io_to_mod_ssi(io))
-               return;
-
-       remote_node = of_graph_get_remote_port_parent(endpoint);
-
-       /* HDMI0 */
-       if (strstr(remote_node->full_name, "hdmi@fead0000")) {
-               rsnd_flags_set(io, RSND_STREAM_HDMI0);
-               dev_dbg(dev, "%s connected to HDMI0\n", io->name);
-       }
-
-       /* HDMI1 */
-       if (strstr(remote_node->full_name, "hdmi@feae0000")) {
-               rsnd_flags_set(io, RSND_STREAM_HDMI1);
-               dev_dbg(dev, "%s connected to HDMI1\n", io->name);
-       }
-
-       rsnd_parse_tdm_split_mode(priv, io, endpoint);
-
-       of_node_put(remote_node);
-}
-
-void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
-               struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
-               struct device_node *node,
-               struct device_node *playback,
-               struct device_node *capture)
-{
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *np;
-       int i;
-
-       if (!node)
-               return;
-
-       i = 0;
-       for_each_child_of_node(node, np) {
-               struct rsnd_mod *mod;
-
-               i = rsnd_node_fixed_index(dev, np, name, i);
-               if (i < 0) {
-                       of_node_put(np);
-                       break;
-               }
-
-               mod = mod_get(priv, i);
-
-               if (np == playback)
-                       rsnd_dai_connect(mod, &rdai->playback, mod->type);
-               if (np == capture)
-                       rsnd_dai_connect(mod, &rdai->capture, mod->type);
-               i++;
-       }
-
-       of_node_put(node);
-}
-
-int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx)
-{
-       char node_name[16];
-
-       /*
-        * rsnd is assuming each device nodes are sequential numbering,
-        * but some of them are not.
-        * This function adjusts index for it.
-        *
-        * ex)
-        * Normal case,         special case
-        *      ssi-0
-        *      ssi-1
-        *      ssi-2
-        *      ssi-3           ssi-3
-        *      ssi-4           ssi-4
-        *      ...
-        *
-        * assume Max 64 node
-        */
-       for (; idx < 64; idx++) {
-               snprintf(node_name, sizeof(node_name), "%s-%d", name, idx);
-
-               if (strncmp(node_name, of_node_full_name(node), sizeof(node_name)) == 0)
-                       return idx;
-       }
-
-       dev_err(dev, "strange node numbering (%s)",
-               of_node_full_name(node));
-       return -EINVAL;
-}
-
-int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *np;
-       int i;
-
-       i = 0;
-       for_each_child_of_node(node, np) {
-               i = rsnd_node_fixed_index(dev, np, name, i);
-               if (i < 0) {
-                       of_node_put(np);
-                       return 0;
-               }
-               i++;
-       }
-
-       return i;
-}
-
-static struct device_node*
-       rsnd_pick_endpoint_node_for_ports(struct device_node *e_ports,
-                                         struct device_node *e_port)
-{
-       if (of_node_name_eq(e_ports, "ports"))
-               return e_ports;
-
-       if (of_node_name_eq(e_ports, "port"))
-               return e_port;
-
-       return NULL;
-}
-
-static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *np = dev->of_node;
-       struct device_node *ports, *node;
-       int nr = 0;
-       int i = 0;
-
-       *is_graph = 0;
-
-       /*
-        * parse both previous dai (= rcar_sound,dai), and
-        * graph dai (= ports/port)
-        */
-
-       /*
-        * Simple-Card
-        */
-       node = of_get_child_by_name(np, RSND_NODE_DAI);
-       if (!node)
-               goto audio_graph;
-
-       of_node_put(node);
-
-       for_each_child_of_node(np, node) {
-               if (!of_node_name_eq(node, RSND_NODE_DAI))
-                       continue;
-
-               priv->component_dais[i] = of_get_child_count(node);
-               nr += priv->component_dais[i];
-               i++;
-               if (i >= RSND_MAX_COMPONENT) {
-                       dev_info(dev, "reach to max component\n");
-                       of_node_put(node);
-                       break;
-               }
-       }
-
-       return nr;
-
-audio_graph:
-       /*
-        * Audio-Graph-Card
-        */
-       for_each_child_of_node(np, ports) {
-               node = rsnd_pick_endpoint_node_for_ports(ports, np);
-               if (!node)
-                       continue;
-               priv->component_dais[i] = of_graph_get_endpoint_count(node);
-               nr += priv->component_dais[i];
-               i++;
-               if (i >= RSND_MAX_COMPONENT) {
-                       dev_info(dev, "reach to max component\n");
-                       of_node_put(ports);
-                       break;
-               }
-       }
-
-       *is_graph = 1;
-
-       return nr;
-}
-
-
-#define PREALLOC_BUFFER                (32 * 1024)
-#define PREALLOC_BUFFER_MAX    (32 * 1024)
-
-static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd,
-                                 struct rsnd_dai_stream *io,
-                                 int stream)
-{
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct snd_pcm_substream *substream;
-
-       /*
-        * use Audio-DMAC dev if we can use IPMMU
-        * see
-        *      rsnd_dmaen_attach()
-        */
-       if (io->dmac_dev)
-               dev = io->dmac_dev;
-
-       for (substream = rtd->pcm->streams[stream].substream;
-            substream;
-            substream = substream->next) {
-               snd_pcm_set_managed_buffer(substream,
-                                          SNDRV_DMA_TYPE_DEV,
-                                          dev,
-                                          PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
-       }
-
-       return 0;
-}
-
-static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
-{
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       int ret;
-
-       ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd);
-       if (ret)
-               return ret;
-
-       ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd);
-       if (ret)
-               return ret;
-
-       ret = rsnd_preallocate_pages(rtd, &rdai->playback,
-                                    SNDRV_PCM_STREAM_PLAYBACK);
-       if (ret)
-               return ret;
-
-       ret = rsnd_preallocate_pages(rtd, &rdai->capture,
-                                    SNDRV_PCM_STREAM_CAPTURE);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
-       .pcm_new                        = rsnd_soc_dai_pcm_new,
-       .startup                        = rsnd_soc_dai_startup,
-       .shutdown                       = rsnd_soc_dai_shutdown,
-       .trigger                        = rsnd_soc_dai_trigger,
-       .set_fmt                        = rsnd_soc_dai_set_fmt,
-       .set_tdm_slot                   = rsnd_soc_set_dai_tdm_slot,
-       .prepare                        = rsnd_soc_dai_prepare,
-       .auto_selectable_formats        = rsnd_soc_dai_formats,
-       .num_auto_selectable_formats    = ARRAY_SIZE(rsnd_soc_dai_formats),
-};
-
-static void __rsnd_dai_probe(struct rsnd_priv *priv,
-                            struct device_node *dai_np,
-                            struct device_node *node_np,
-                            uint32_t node_arg,
-                            int dai_i)
-{
-       struct rsnd_dai_stream *io_playback;
-       struct rsnd_dai_stream *io_capture;
-       struct snd_soc_dai_driver *drv;
-       struct rsnd_dai *rdai;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int playback_exist = 0, capture_exist = 0;
-       int io_i;
-
-       rdai            = rsnd_rdai_get(priv, dai_i);
-       drv             = rsnd_daidrv_get(priv, dai_i);
-       io_playback     = &rdai->playback;
-       io_capture      = &rdai->capture;
-
-       snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
-
-       /* for multi Component */
-       rdai->dai_args.np               = node_np;
-       rdai->dai_args.args_count       = 1;
-       rdai->dai_args.args[0]          = node_arg;
-
-       rdai->priv      = priv;
-       drv->name       = rdai->name;
-       drv->ops        = &rsnd_soc_dai_ops;
-       drv->id         = dai_i;
-       drv->dai_args   = &rdai->dai_args;
-
-       io_playback->rdai               = rdai;
-       io_capture->rdai                = rdai;
-       rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
-       rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
-       rsnd_rdai_width_set(rdai, 32);   /* default 32bit width */
-
-       for (io_i = 0;; io_i++) {
-               struct device_node *playback = of_parse_phandle(dai_np, "playback", io_i);
-               struct device_node *capture  = of_parse_phandle(dai_np, "capture", io_i);
-
-               if (!playback && !capture)
-                       break;
-
-               if (io_i == 0) {
-                       /* check whether playback/capture property exists */
-                       if (playback)
-                               playback_exist = 1;
-                       if (capture)
-                               capture_exist = 1;
-               }
-
-               rsnd_parse_connect_ssi(rdai, playback, capture);
-               rsnd_parse_connect_ssiu(rdai, playback, capture);
-               rsnd_parse_connect_src(rdai, playback, capture);
-               rsnd_parse_connect_ctu(rdai, playback, capture);
-               rsnd_parse_connect_mix(rdai, playback, capture);
-               rsnd_parse_connect_dvc(rdai, playback, capture);
-
-               of_node_put(playback);
-               of_node_put(capture);
-       }
-
-       if (playback_exist) {
-               snprintf(io_playback->name, RSND_DAI_NAME_SIZE, "DAI%d Playback", dai_i);
-               drv->playback.rates             = RSND_RATES;
-               drv->playback.formats           = RSND_FMTS;
-               drv->playback.channels_min      = 2;
-               drv->playback.channels_max      = 8;
-               drv->playback.stream_name       = io_playback->name;
-       }
-       if (capture_exist) {
-               snprintf(io_capture->name, RSND_DAI_NAME_SIZE, "DAI%d Capture", dai_i);
-               drv->capture.rates              = RSND_RATES;
-               drv->capture.formats            = RSND_FMTS;
-               drv->capture.channels_min       = 2;
-               drv->capture.channels_max       = 8;
-               drv->capture.stream_name        = io_capture->name;
-       }
-
-       if (rsnd_ssi_is_pin_sharing(io_capture) ||
-           rsnd_ssi_is_pin_sharing(io_playback)) {
-               /* should have symmetric_rate if pin sharing */
-               drv->symmetric_rate = 1;
-       }
-
-       dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
-               rsnd_io_to_mod_ssi(io_playback) ? "play"    : " -- ",
-               rsnd_io_to_mod_ssi(io_capture) ? "capture" : "  --   ");
-}
-
-static int rsnd_dai_probe(struct rsnd_priv *priv)
-{
-       struct snd_soc_dai_driver *rdrv;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *np = dev->of_node;
-       struct rsnd_dai *rdai;
-       int nr = 0;
-       int is_graph;
-       int dai_i;
-
-       nr = rsnd_dai_of_node(priv, &is_graph);
-       if (!nr)
-               return -EINVAL;
-
-       rdrv = devm_kcalloc(dev, nr, sizeof(*rdrv), GFP_KERNEL);
-       rdai = devm_kcalloc(dev, nr, sizeof(*rdai), GFP_KERNEL);
-       if (!rdrv || !rdai)
-               return -ENOMEM;
-
-       priv->rdai_nr   = nr;
-       priv->daidrv    = rdrv;
-       priv->rdai      = rdai;
-
-       /*
-        * parse all dai
-        */
-       dai_i = 0;
-       if (is_graph) {
-               struct device_node *dai_np_port;
-               struct device_node *ports;
-               struct device_node *dai_np;
-
-               for_each_child_of_node(np, ports) {
-                       dai_np_port = rsnd_pick_endpoint_node_for_ports(ports, np);
-                       if (!dai_np_port)
-                               continue;
-
-                       for_each_endpoint_of_node(dai_np_port, dai_np) {
-                               __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i);
-                               if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) {
-                                       rdai = rsnd_rdai_get(priv, dai_i);
-
-                                       rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
-                                       rsnd_parse_connect_graph(priv, &rdai->capture,  dai_np);
-                               }
-                               dai_i++;
-                       }
-               }
-       } else {
-               struct device_node *node;
-               struct device_node *dai_np;
-
-               for_each_child_of_node(np, node) {
-                       if (!of_node_name_eq(node, RSND_NODE_DAI))
-                               continue;
-
-                       for_each_child_of_node(node, dai_np) {
-                               __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i);
-                               if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) {
-                                       rdai = rsnd_rdai_get(priv, dai_i);
-
-                                       rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
-                                       rsnd_parse_connect_simple(priv, &rdai->capture,  dai_np);
-                               }
-                               dai_i++;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/*
- *             pcm ops
- */
-static int rsnd_hw_update(struct snd_pcm_substream *substream,
-                         struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       if (hw_params)
-               ret = rsnd_dai_call(hw_params, io, substream, hw_params);
-       else
-               ret = rsnd_dai_call(hw_free, io, substream);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return ret;
-}
-
-static int rsnd_hw_params(struct snd_soc_component *component,
-                         struct snd_pcm_substream *substream,
-                         struct snd_pcm_hw_params *hw_params)
-{
-       struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-       struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
-
-       /*
-        * rsnd assumes that it might be used under DPCM if user want to use
-        * channel / rate convert. Then, rsnd should be FE.
-        * And then, this function will be called *after* BE settings.
-        * this means, each BE already has fixuped hw_params.
-        * see
-        *      dpcm_fe_dai_hw_params()
-        *      dpcm_be_dai_hw_params()
-        */
-       io->converted_rate = 0;
-       io->converted_chan = 0;
-       if (fe->dai_link->dynamic) {
-               struct rsnd_priv *priv = rsnd_io_to_priv(io);
-               struct device *dev = rsnd_priv_to_dev(priv);
-               struct snd_soc_dpcm *dpcm;
-               int stream = substream->stream;
-
-               for_each_dpcm_be(fe, stream, dpcm) {
-                       struct snd_soc_pcm_runtime *be = dpcm->be;
-                       struct snd_pcm_hw_params *be_params = &be->dpcm[stream].hw_params;
-
-                       if (params_channels(hw_params) != params_channels(be_params))
-                               io->converted_chan = params_channels(be_params);
-                       if (params_rate(hw_params) != params_rate(be_params))
-                               io->converted_rate = params_rate(be_params);
-               }
-               if (io->converted_chan)
-                       dev_dbg(dev, "convert channels = %d\n", io->converted_chan);
-               if (io->converted_rate) {
-                       /*
-                        * SRC supports convert rates from params_rate(hw_params)/k_down
-                        * to params_rate(hw_params)*k_up, where k_up is always 6, and
-                        * k_down depends on number of channels and SRC unit.
-                        * So all SRC units can upsample audio up to 6 times regardless
-                        * its number of channels. And all SRC units can downsample
-                        * 2 channel audio up to 6 times too.
-                        */
-                       int k_up = 6;
-                       int k_down = 6;
-                       int channel;
-                       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
-
-                       dev_dbg(dev, "convert rate     = %d\n", io->converted_rate);
-
-                       channel = io->converted_chan ? io->converted_chan :
-                                 params_channels(hw_params);
-
-                       switch (rsnd_mod_id(src_mod)) {
-                       /*
-                        * SRC0 can downsample 4, 6 and 8 channel audio up to 4 times.
-                        * SRC1, SRC3 and SRC4 can downsample 4 channel audio
-                        * up to 4 times.
-                        * SRC1, SRC3 and SRC4 can downsample 6 and 8 channel audio
-                        * no more than twice.
-                        */
-                       case 1:
-                       case 3:
-                       case 4:
-                               if (channel > 4) {
-                                       k_down = 2;
-                                       break;
-                               }
-                               fallthrough;
-                       case 0:
-                               if (channel > 2)
-                                       k_down = 4;
-                               break;
-
-                       /* Other SRC units do not support more than 2 channels */
-                       default:
-                               if (channel > 2)
-                                       return -EINVAL;
-                       }
-
-                       if (params_rate(hw_params) > io->converted_rate * k_down) {
-                               hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
-                                       io->converted_rate * k_down;
-                               hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
-                                       io->converted_rate * k_down;
-                               hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
-                       } else if (params_rate(hw_params) * k_up < io->converted_rate) {
-                               hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
-                                       DIV_ROUND_UP(io->converted_rate, k_up);
-                               hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
-                                       DIV_ROUND_UP(io->converted_rate, k_up);
-                               hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
-                       }
-
-                       /*
-                        * TBD: Max SRC input and output rates also depend on number
-                        * of channels and SRC unit:
-                        * SRC1, SRC3 and SRC4 do not support more than 128kHz
-                        * for 6 channel and 96kHz for 8 channel audio.
-                        * Perhaps this function should return EINVAL if the input or
-                        * the output rate exceeds the limitation.
-                        */
-               }
-       }
-
-       return rsnd_hw_update(substream, hw_params);
-}
-
-static int rsnd_hw_free(struct snd_soc_component *component,
-                       struct snd_pcm_substream *substream)
-{
-       return rsnd_hw_update(substream, NULL);
-}
-
-static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component,
-                                     struct snd_pcm_substream *substream)
-{
-       struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-       snd_pcm_uframes_t pointer = 0;
-
-       rsnd_dai_call(pointer, io, &pointer);
-
-       return pointer;
-}
-
-/*
- *             snd_kcontrol
- */
-static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
-                          struct snd_ctl_elem_info *uinfo)
-{
-       struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
-
-       if (cfg->texts) {
-               uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-               uinfo->count = cfg->size;
-               uinfo->value.enumerated.items = cfg->max;
-               if (uinfo->value.enumerated.item >= cfg->max)
-                       uinfo->value.enumerated.item = cfg->max - 1;
-               strscpy(uinfo->value.enumerated.name,
-                       cfg->texts[uinfo->value.enumerated.item],
-                       sizeof(uinfo->value.enumerated.name));
-       } else {
-               uinfo->count = cfg->size;
-               uinfo->value.integer.min = 0;
-               uinfo->value.integer.max = cfg->max;
-               uinfo->type = (cfg->max == 1) ?
-                       SNDRV_CTL_ELEM_TYPE_BOOLEAN :
-                       SNDRV_CTL_ELEM_TYPE_INTEGER;
-       }
-
-       return 0;
-}
-
-static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
-                         struct snd_ctl_elem_value *uc)
-{
-       struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
-       int i;
-
-       for (i = 0; i < cfg->size; i++)
-               if (cfg->texts)
-                       uc->value.enumerated.item[i] = cfg->val[i];
-               else
-                       uc->value.integer.value[i] = cfg->val[i];
-
-       return 0;
-}
-
-static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
-                         struct snd_ctl_elem_value *uc)
-{
-       struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
-       int i, change = 0;
-
-       if (!cfg->accept(cfg->io))
-               return 0;
-
-       for (i = 0; i < cfg->size; i++) {
-               if (cfg->texts) {
-                       change |= (uc->value.enumerated.item[i] != cfg->val[i]);
-                       cfg->val[i] = uc->value.enumerated.item[i];
-               } else {
-                       change |= (uc->value.integer.value[i] != cfg->val[i]);
-                       cfg->val[i] = uc->value.integer.value[i];
-               }
-       }
-
-       if (change && cfg->update)
-               cfg->update(cfg->io, cfg->mod);
-
-       return change;
-}
-
-int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io)
-{
-       return 1;
-}
-
-int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io)
-{
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       if (!runtime) {
-               dev_warn(dev, "Can't update kctrl when idle\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)
-{
-       cfg->cfg.val = cfg->val;
-
-       return &cfg->cfg;
-}
-
-struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg)
-{
-       cfg->cfg.val = &cfg->val;
-
-       return &cfg->cfg;
-}
-
-const char * const volume_ramp_rate[] = {
-       "128 dB/1 step",         /* 00000 */
-       "64 dB/1 step",          /* 00001 */
-       "32 dB/1 step",          /* 00010 */
-       "16 dB/1 step",          /* 00011 */
-       "8 dB/1 step",           /* 00100 */
-       "4 dB/1 step",           /* 00101 */
-       "2 dB/1 step",           /* 00110 */
-       "1 dB/1 step",           /* 00111 */
-       "0.5 dB/1 step",         /* 01000 */
-       "0.25 dB/1 step",        /* 01001 */
-       "0.125 dB/1 step",       /* 01010 = VOLUME_RAMP_MAX_MIX */
-       "0.125 dB/2 steps",      /* 01011 */
-       "0.125 dB/4 steps",      /* 01100 */
-       "0.125 dB/8 steps",      /* 01101 */
-       "0.125 dB/16 steps",     /* 01110 */
-       "0.125 dB/32 steps",     /* 01111 */
-       "0.125 dB/64 steps",     /* 10000 */
-       "0.125 dB/128 steps",    /* 10001 */
-       "0.125 dB/256 steps",    /* 10010 */
-       "0.125 dB/512 steps",    /* 10011 */
-       "0.125 dB/1024 steps",   /* 10100 */
-       "0.125 dB/2048 steps",   /* 10101 */
-       "0.125 dB/4096 steps",   /* 10110 */
-       "0.125 dB/8192 steps",   /* 10111 = VOLUME_RAMP_MAX_DVC */
-};
-
-int rsnd_kctrl_new(struct rsnd_mod *mod,
-                  struct rsnd_dai_stream *io,
-                  struct snd_soc_pcm_runtime *rtd,
-                  const unsigned char *name,
-                  int (*accept)(struct rsnd_dai_stream *io),
-                  void (*update)(struct rsnd_dai_stream *io,
-                                 struct rsnd_mod *mod),
-                  struct rsnd_kctrl_cfg *cfg,
-                  const char * const *texts,
-                  int size,
-                  u32 max)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_kcontrol *kctrl;
-       struct snd_kcontrol_new knew = {
-               .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name           = name,
-               .info           = rsnd_kctrl_info,
-               .index          = rtd->num,
-               .get            = rsnd_kctrl_get,
-               .put            = rsnd_kctrl_put,
-       };
-       int ret;
-
-       /*
-        * 1) Avoid duplicate register for DVC with MIX case
-        * 2) Allow duplicate register for MIX
-        * 3) re-register if card was rebinded
-        */
-       list_for_each_entry(kctrl, &card->controls, list) {
-               struct rsnd_kctrl_cfg *c = kctrl->private_data;
-
-               if (c == cfg)
-                       return 0;
-       }
-
-       if (size > RSND_MAX_CHANNELS)
-               return -EINVAL;
-
-       kctrl = snd_ctl_new1(&knew, cfg);
-       if (!kctrl)
-               return -ENOMEM;
-
-       ret = snd_ctl_add(card, kctrl);
-       if (ret < 0)
-               return ret;
-
-       cfg->texts      = texts;
-       cfg->max        = max;
-       cfg->size       = size;
-       cfg->accept     = accept;
-       cfg->update     = update;
-       cfg->card       = card;
-       cfg->kctrl      = kctrl;
-       cfg->io         = io;
-       cfg->mod        = mod;
-
-       return 0;
-}
-
-/*
- *             snd_soc_component
- */
-static const struct snd_soc_component_driver rsnd_soc_component = {
-       .name                   = "rsnd",
-       .probe                  = rsnd_debugfs_probe,
-       .hw_params              = rsnd_hw_params,
-       .hw_free                = rsnd_hw_free,
-       .pointer                = rsnd_pointer,
-       .legacy_dai_naming      = 1,
-};
-
-static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
-                                      struct rsnd_dai_stream *io)
-{
-       int ret;
-
-       ret = rsnd_dai_call(probe, io, priv);
-       if (ret == -EAGAIN) {
-               struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
-               struct rsnd_mod *mod;
-               int i;
-
-               /*
-                * Fallback to PIO mode
-                */
-
-               /*
-                * call "remove" for SSI/SRC/DVC
-                * SSI will be switch to PIO mode if it was DMA mode
-                * see
-                *      rsnd_dma_init()
-                *      rsnd_ssi_fallback()
-                */
-               rsnd_dai_call(remove, io, priv);
-
-               /*
-                * remove all mod from io
-                * and, re connect ssi
-                */
-               for_each_rsnd_mod(i, mod, io)
-                       rsnd_dai_disconnect(mod, io, i);
-               rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
-
-               /*
-                * fallback
-                */
-               rsnd_dai_call(fallback, io, priv);
-
-               /*
-                * retry to "probe".
-                * DAI has SSI which is PIO mode only now.
-                */
-               ret = rsnd_dai_call(probe, io, priv);
-       }
-
-       return ret;
-}
-
-/*
- *     rsnd probe
- */
-static int rsnd_probe(struct platform_device *pdev)
-{
-       struct rsnd_priv *priv;
-       struct device *dev = &pdev->dev;
-       struct rsnd_dai *rdai;
-       int (*probe_func[])(struct rsnd_priv *priv) = {
-               rsnd_gen_probe,
-               rsnd_dma_probe,
-               rsnd_ssi_probe,
-               rsnd_ssiu_probe,
-               rsnd_src_probe,
-               rsnd_ctu_probe,
-               rsnd_mix_probe,
-               rsnd_dvc_probe,
-               rsnd_cmd_probe,
-               rsnd_adg_probe,
-               rsnd_dai_probe,
-       };
-       int ret, i;
-       int ci;
-
-       /*
-        *      init priv data
-        */
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENODEV;
-
-       priv->pdev      = pdev;
-       priv->flags     = (unsigned long)of_device_get_match_data(dev);
-       spin_lock_init(&priv->lock);
-
-       /*
-        *      init each module
-        */
-       for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
-               ret = probe_func[i](priv);
-               if (ret)
-                       return ret;
-       }
-
-       for_each_rsnd_dai(rdai, priv, i) {
-               ret = rsnd_rdai_continuance_probe(priv, &rdai->playback);
-               if (ret)
-                       goto exit_snd_probe;
-
-               ret = rsnd_rdai_continuance_probe(priv, &rdai->capture);
-               if (ret)
-                       goto exit_snd_probe;
-       }
-
-       dev_set_drvdata(dev, priv);
-
-       /*
-        *      asoc register
-        */
-       ci = 0;
-       for (i = 0; priv->component_dais[i] > 0; i++) {
-               int nr = priv->component_dais[i];
-
-               ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
-                                                     priv->daidrv + ci, nr);
-               if (ret < 0) {
-                       dev_err(dev, "cannot snd component register\n");
-                       goto exit_snd_probe;
-               }
-
-               ci += nr;
-       }
-
-       pm_runtime_enable(dev);
-
-       dev_info(dev, "probed\n");
-       return ret;
-
-exit_snd_probe:
-       for_each_rsnd_dai(rdai, priv, i) {
-               rsnd_dai_call(remove, &rdai->playback, priv);
-               rsnd_dai_call(remove, &rdai->capture, priv);
-       }
-
-       /*
-        * adg is very special mod which can't use rsnd_dai_call(remove),
-        * and it registers ADG clock on probe.
-        * It should be unregister if probe failed.
-        * Mainly it is assuming -EPROBE_DEFER case
-        */
-       rsnd_adg_remove(priv);
-
-       return ret;
-}
-
-static void rsnd_remove(struct platform_device *pdev)
-{
-       struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
-       struct rsnd_dai *rdai;
-       void (*remove_func[])(struct rsnd_priv *priv) = {
-               rsnd_ssi_remove,
-               rsnd_ssiu_remove,
-               rsnd_src_remove,
-               rsnd_ctu_remove,
-               rsnd_mix_remove,
-               rsnd_dvc_remove,
-               rsnd_cmd_remove,
-               rsnd_adg_remove,
-       };
-       int i;
-
-       pm_runtime_disable(&pdev->dev);
-
-       for_each_rsnd_dai(rdai, priv, i) {
-               int ret;
-
-               ret = rsnd_dai_call(remove, &rdai->playback, priv);
-               if (ret)
-                       dev_warn(&pdev->dev, "Failed to remove playback dai #%d\n", i);
-
-               ret = rsnd_dai_call(remove, &rdai->capture, priv);
-               if (ret)
-                       dev_warn(&pdev->dev, "Failed to remove capture dai #%d\n", i);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(remove_func); i++)
-               remove_func[i](priv);
-}
-
-static int __maybe_unused rsnd_suspend(struct device *dev)
-{
-       struct rsnd_priv *priv = dev_get_drvdata(dev);
-
-       rsnd_adg_clk_disable(priv);
-
-       return 0;
-}
-
-static int __maybe_unused rsnd_resume(struct device *dev)
-{
-       struct rsnd_priv *priv = dev_get_drvdata(dev);
-
-       rsnd_adg_clk_enable(priv);
-
-       return 0;
-}
-
-static const struct dev_pm_ops rsnd_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume)
-};
-
-static struct platform_driver rsnd_driver = {
-       .driver = {
-               .name   = "rcar_sound",
-               .pm     = &rsnd_pm_ops,
-               .of_match_table = rsnd_of_match,
-       },
-       .probe          = rsnd_probe,
-       .remove         = rsnd_remove,
-};
-module_platform_driver(rsnd_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Renesas R-Car audio driver");
-MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
-MODULE_ALIAS("platform:rcar-pcm-audio");
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
deleted file mode 100644 (file)
index a26ec7b..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// ctu.c
-//
-// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-#include "rsnd.h"
-
-#define CTU_NAME_SIZE  16
-#define CTU_NAME "ctu"
-
-/*
- * User needs to setup CTU by amixer, and its settings are
- * based on below registers
- *
- * CTUn_CPMDR : amixser set "CTU Pass"
- * CTUn_SV0xR : amixser set "CTU SV0"
- * CTUn_SV1xR : amixser set "CTU SV1"
- * CTUn_SV2xR : amixser set "CTU SV2"
- * CTUn_SV3xR : amixser set "CTU SV3"
- *
- * [CTU Pass]
- * 0000: default
- * 0001: Connect input data of channel 0
- * 0010: Connect input data of channel 1
- * 0011: Connect input data of channel 2
- * 0100: Connect input data of channel 3
- * 0101: Connect input data of channel 4
- * 0110: Connect input data of channel 5
- * 0111: Connect input data of channel 6
- * 1000: Connect input data of channel 7
- * 1001: Connect calculated data by scale values of matrix row 0
- * 1010: Connect calculated data by scale values of matrix row 1
- * 1011: Connect calculated data by scale values of matrix row 2
- * 1100: Connect calculated data by scale values of matrix row 3
- *
- * [CTU SVx]
- * [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07]
- * [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17]
- * [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27]
- * [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37]
- * [Output4] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
- * [Output5] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
- * [Output6] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
- * [Output7] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
- *
- * [SVxx]
- * Plus                                        Minus
- * value       time            dB      value           time            dB
- * -----------------------------------------------------------------------
- * H'7F_FFFF   2               6       H'80_0000       2               6
- * ...
- * H'40_0000   1               0       H'C0_0000       1               0
- * ...
- * H'00_0001   2.38 x 10^-7    -132
- * H'00_0000   0               Mute    H'FF_FFFF       2.38 x 10^-7    -132
- *
- *
- * Ex) Input ch -> Output ch
- *     1ch     ->  0ch
- *     0ch     ->  1ch
- *
- *     amixer set "CTU Reset" on
- *     amixer set "CTU Pass" 9,10
- *     amixer set "CTU SV0" 0,4194304
- *     amixer set "CTU SV1" 4194304,0
- * or
- *     amixer set "CTU Reset" on
- *     amixer set "CTU Pass" 2,1
- */
-
-struct rsnd_ctu {
-       struct rsnd_mod mod;
-       struct rsnd_kctrl_cfg_m pass;
-       struct rsnd_kctrl_cfg_m sv[4];
-       struct rsnd_kctrl_cfg_s reset;
-       int channels;
-       u32 flags;
-};
-
-#define KCTRL_INITIALIZED      (1 << 0)
-
-#define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
-#define for_each_rsnd_ctu(pos, priv, i)                                        \
-       for ((i) = 0;                                                   \
-            ((i) < rsnd_ctu_nr(priv)) &&                               \
-                    ((pos) = (struct rsnd_ctu *)(priv)->ctu + i);      \
-            i++)
-
-#define rsnd_mod_to_ctu(_mod)  \
-       container_of((_mod), struct rsnd_ctu, mod)
-
-#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
-
-static void rsnd_ctu_activation(struct rsnd_mod *mod)
-{
-       rsnd_mod_write(mod, CTU_SWRSR, 0);
-       rsnd_mod_write(mod, CTU_SWRSR, 1);
-}
-
-static void rsnd_ctu_halt(struct rsnd_mod *mod)
-{
-       rsnd_mod_write(mod, CTU_CTUIR, 1);
-       rsnd_mod_write(mod, CTU_SWRSR, 0);
-}
-
-static int rsnd_ctu_probe_(struct rsnd_mod *mod,
-                          struct rsnd_dai_stream *io,
-                          struct rsnd_priv *priv)
-{
-       return rsnd_cmd_attach(io, rsnd_mod_id(mod));
-}
-
-static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
-                              struct rsnd_mod *mod)
-{
-       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
-       u32 cpmdr = 0;
-       u32 scmdr = 0;
-       int i, j;
-
-       for (i = 0; i < RSND_MAX_CHANNELS; i++) {
-               u32 val = rsnd_kctrl_valm(ctu->pass, i);
-
-               cpmdr |= val << (28 - (i * 4));
-
-               if ((val > 0x8) && (scmdr < (val - 0x8)))
-                       scmdr = val - 0x8;
-       }
-
-       rsnd_mod_write(mod, CTU_CTUIR, 1);
-
-       rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io));
-
-       rsnd_mod_write(mod, CTU_CPMDR, cpmdr);
-
-       rsnd_mod_write(mod, CTU_SCMDR, scmdr);
-
-       for (i = 0; i < 4; i++) {
-
-               if (i >= scmdr)
-                       break;
-
-               for (j = 0; j < RSND_MAX_CHANNELS; j++)
-                       rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j));
-       }
-
-       rsnd_mod_write(mod, CTU_CTUIR, 0);
-}
-
-static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
-                                struct rsnd_mod *mod)
-{
-       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
-       int i;
-
-       if (!rsnd_kctrl_vals(ctu->reset))
-               return;
-
-       for (i = 0; i < RSND_MAX_CHANNELS; i++) {
-               rsnd_kctrl_valm(ctu->pass, i) = 0;
-               rsnd_kctrl_valm(ctu->sv[0],  i) = 0;
-               rsnd_kctrl_valm(ctu->sv[1],  i) = 0;
-               rsnd_kctrl_valm(ctu->sv[2],  i) = 0;
-               rsnd_kctrl_valm(ctu->sv[3],  i) = 0;
-       }
-       rsnd_kctrl_vals(ctu->reset) = 0;
-}
-
-static int rsnd_ctu_init(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       int ret;
-
-       ret = rsnd_mod_power_on(mod);
-       if (ret < 0)
-               return ret;
-
-       rsnd_ctu_activation(mod);
-
-       rsnd_ctu_value_init(io, mod);
-
-       return 0;
-}
-
-static int rsnd_ctu_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       rsnd_ctu_halt(mod);
-
-       rsnd_mod_power_off(mod);
-
-       return 0;
-}
-
-static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
-                           struct rsnd_dai_stream *io,
-                           struct snd_soc_pcm_runtime *rtd)
-{
-       struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
-       int ret;
-
-       if (rsnd_flags_has(ctu, KCTRL_INITIALIZED))
-               return 0;
-
-       /* CTU Pass */
-       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass",
-                              rsnd_kctrl_accept_anytime,
-                              NULL,
-                              &ctu->pass, RSND_MAX_CHANNELS,
-                              0xC);
-       if (ret < 0)
-               return ret;
-
-       /* ROW0 */
-       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
-                              rsnd_kctrl_accept_anytime,
-                              NULL,
-                              &ctu->sv[0], RSND_MAX_CHANNELS,
-                              0x00FFFFFF);
-       if (ret < 0)
-               return ret;
-
-       /* ROW1 */
-       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1",
-                              rsnd_kctrl_accept_anytime,
-                              NULL,
-                              &ctu->sv[1], RSND_MAX_CHANNELS,
-                              0x00FFFFFF);
-       if (ret < 0)
-               return ret;
-
-       /* ROW2 */
-       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2",
-                              rsnd_kctrl_accept_anytime,
-                              NULL,
-                              &ctu->sv[2], RSND_MAX_CHANNELS,
-                              0x00FFFFFF);
-       if (ret < 0)
-               return ret;
-
-       /* ROW3 */
-       ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3",
-                              rsnd_kctrl_accept_anytime,
-                              NULL,
-                              &ctu->sv[3], RSND_MAX_CHANNELS,
-                              0x00FFFFFF);
-       if (ret < 0)
-               return ret;
-
-       /* Reset */
-       ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset",
-                              rsnd_kctrl_accept_anytime,
-                              rsnd_ctu_value_reset,
-                              &ctu->reset, 1);
-
-       rsnd_flags_set(ctu, KCTRL_INITIALIZED);
-
-       return ret;
-}
-
-static int rsnd_ctu_id(struct rsnd_mod *mod)
-{
-       /*
-        * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0
-        * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1
-        */
-       return mod->id / 4;
-}
-
-static int rsnd_ctu_id_sub(struct rsnd_mod *mod)
-{
-       /*
-        * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3
-        * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3
-        */
-       return mod->id % 4;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void rsnd_ctu_debug_info(struct seq_file *m,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_mod *mod)
-{
-       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
-                                 0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100);
-}
-#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info
-#else
-#define DEBUG_INFO
-#endif
-
-static struct rsnd_mod_ops rsnd_ctu_ops = {
-       .name           = CTU_NAME,
-       .probe          = rsnd_ctu_probe_,
-       .init           = rsnd_ctu_init,
-       .quit           = rsnd_ctu_quit,
-       .pcm_new        = rsnd_ctu_pcm_new,
-       .get_status     = rsnd_mod_get_status,
-       .id             = rsnd_ctu_id,
-       .id_sub         = rsnd_ctu_id_sub,
-       .id_cmd         = rsnd_mod_id_raw,
-       DEBUG_INFO
-};
-
-struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
-{
-       if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
-               id = 0;
-
-       return rsnd_mod_get(rsnd_ctu_get(priv, id));
-}
-
-int rsnd_ctu_probe(struct rsnd_priv *priv)
-{
-       struct device_node *node;
-       struct device_node *np;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_ctu *ctu;
-       struct clk *clk;
-       char name[CTU_NAME_SIZE];
-       int i, nr, ret;
-
-       node = rsnd_ctu_of_node(priv);
-       if (!node)
-               return 0; /* not used is not error */
-
-       nr = of_get_child_count(node);
-       if (!nr) {
-               ret = -EINVAL;
-               goto rsnd_ctu_probe_done;
-       }
-
-       ctu = devm_kcalloc(dev, nr, sizeof(*ctu), GFP_KERNEL);
-       if (!ctu) {
-               ret = -ENOMEM;
-               goto rsnd_ctu_probe_done;
-       }
-
-       priv->ctu_nr    = nr;
-       priv->ctu       = ctu;
-
-       i = 0;
-       ret = 0;
-       for_each_child_of_node(node, np) {
-               ctu = rsnd_ctu_get(priv, i);
-
-               /*
-                * CTU00, CTU01, CTU02, CTU03 => CTU0
-                * CTU10, CTU11, CTU12, CTU13 => CTU1
-                */
-               snprintf(name, CTU_NAME_SIZE, "%s.%d",
-                        CTU_NAME, i / 4);
-
-               clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk)) {
-                       ret = PTR_ERR(clk);
-                       of_node_put(np);
-                       goto rsnd_ctu_probe_done;
-               }
-
-               ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
-                                   clk, RSND_MOD_CTU, i);
-               if (ret) {
-                       of_node_put(np);
-                       goto rsnd_ctu_probe_done;
-               }
-
-               i++;
-       }
-
-
-rsnd_ctu_probe_done:
-       of_node_put(node);
-
-       return ret;
-}
-
-void rsnd_ctu_remove(struct rsnd_priv *priv)
-{
-       struct rsnd_ctu *ctu;
-       int i;
-
-       for_each_rsnd_ctu(ctu, priv, i) {
-               rsnd_mod_quit(rsnd_mod_get(ctu));
-       }
-}
diff --git a/sound/soc/sh/rcar/debugfs.c b/sound/soc/sh/rcar/debugfs.c
deleted file mode 100644 (file)
index 26d3b31..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// // Renesas R-Car debugfs support
-//
-// Copyright (c) 2021 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-//
-//     > mount -t debugfs none /sys/kernel/debug
-//     > cd /sys/kernel/debug/asoc/rcar-sound/ec500000.sound/rdai{N}/
-//     > cat playback/xxx
-//     > cat capture/xxx
-//
-#ifdef CONFIG_DEBUG_FS
-
-#include <linux/debugfs.h>
-#include "rsnd.h"
-
-static int rsnd_debugfs_show(struct seq_file *m, void *v)
-{
-       struct rsnd_dai_stream *io = m->private;
-       struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       int i;
-
-       /* adg is out of mods */
-       rsnd_adg_clk_dbg_info(priv, m);
-
-       for_each_rsnd_mod(i, mod, io) {
-               u32 *status = mod->ops->get_status(mod, io, mod->type);
-
-               seq_printf(m, "name: %s\n", rsnd_mod_name(mod));
-               seq_printf(m, "status: %08x\n", *status);
-
-               if (mod->ops->debug_info)
-                       mod->ops->debug_info(m, io, mod);
-       }
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(rsnd_debugfs);
-
-void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr,
-                          void __iomem *base, int offset, int size)
-{
-       int i, j;
-
-       for (i = 0; i < size; i += 0x10) {
-               phys_addr_t addr = _addr + offset + i;
-
-               seq_printf(m, "%pa:", &addr);
-               for (j = 0; j < 0x10; j += 0x4)
-                       seq_printf(m, " %08x", __raw_readl(base + offset + i + j));
-               seq_puts(m, "\n");
-       }
-}
-
-void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod,
-                              int reg_id, int offset, int size)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-
-       rsnd_debugfs_reg_show(m,
-                             rsnd_gen_get_phy_addr(priv, reg_id),
-                             rsnd_gen_get_base_addr(priv, reg_id),
-                             offset, size);
-}
-
-int rsnd_debugfs_probe(struct snd_soc_component *component)
-{
-       struct rsnd_priv *priv = dev_get_drvdata(component->dev);
-       struct rsnd_dai *rdai;
-       struct dentry *dir;
-       char name[64];
-       int i;
-
-       /* Gen1 is not supported */
-       if (rsnd_is_gen1(priv))
-               return 0;
-
-       for_each_rsnd_dai(rdai, priv, i) {
-               /*
-                * created debugfs will be automatically
-                * removed, nothing to do for _remove.
-                * see
-                *      soc_cleanup_component_debugfs()
-                */
-               snprintf(name, sizeof(name), "rdai%d", i);
-               dir = debugfs_create_dir(name, component->debugfs_root);
-
-               debugfs_create_file("playback", 0444, dir, &rdai->playback, &rsnd_debugfs_fops);
-               debugfs_create_file("capture",  0444, dir, &rdai->capture,  &rsnd_debugfs_fops);
-       }
-
-       return 0;
-}
-
-#endif /* CONFIG_DEBUG_FS */
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
deleted file mode 100644 (file)
index 2342bbb..0000000
+++ /dev/null
@@ -1,885 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car Audio DMAC support
-//
-// Copyright (C) 2015 Renesas Electronics Corp.
-// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-#include <linux/delay.h>
-#include <linux/of_dma.h>
-#include <sound/dmaengine_pcm.h>
-#include "rsnd.h"
-
-/*
- * Audio DMAC peri peri register
- */
-#define PDMASAR                0x00
-#define PDMADAR                0x04
-#define PDMACHCR       0x0c
-
-/* PDMACHCR */
-#define PDMACHCR_DE            (1 << 0)
-
-
-struct rsnd_dmaen {
-       struct dma_chan         *chan;
-};
-
-struct rsnd_dmapp {
-       int                     dmapp_id;
-       u32                     chcr;
-};
-
-struct rsnd_dma {
-       struct rsnd_mod         mod;
-       struct rsnd_mod         *mod_from;
-       struct rsnd_mod         *mod_to;
-       dma_addr_t              src_addr;
-       dma_addr_t              dst_addr;
-       union {
-               struct rsnd_dmaen en;
-               struct rsnd_dmapp pp;
-       } dma;
-};
-
-struct rsnd_dma_ctrl {
-       void __iomem *ppbase;
-       phys_addr_t ppres;
-       int dmaen_num;
-       int dmapp_num;
-};
-
-#define rsnd_priv_to_dmac(p)   ((struct rsnd_dma_ctrl *)(p)->dma)
-#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod)
-#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en)
-#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp)
-
-/* for DEBUG */
-static struct rsnd_mod_ops mem_ops = {
-       .name = "mem",
-};
-
-static struct rsnd_mod mem = {
-};
-
-/*
- *             Audio DMAC
- */
-static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
-                                                  struct rsnd_mod *mod_from,
-                                                  struct rsnd_mod *mod_to)
-{
-       if ((!mod_from && !mod_to) ||
-           (mod_from && mod_to))
-               return NULL;
-
-       if (mod_from)
-               return rsnd_mod_dma_req(io, mod_from);
-       else
-               return rsnd_mod_dma_req(io, mod_to);
-}
-
-static int rsnd_dmaen_stop(struct rsnd_mod *mod,
-                          struct rsnd_dai_stream *io,
-                          struct rsnd_priv *priv)
-{
-       return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_STOP);
-}
-
-static int rsnd_dmaen_cleanup(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
-{
-       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-
-       /*
-        * DMAEngine release uses mutex lock.
-        * Thus, it shouldn't be called under spinlock.
-        * Let's call it under prepare
-        */
-       if (dmaen->chan)
-               snd_dmaengine_pcm_close_release_chan(io->substream);
-
-       dmaen->chan = NULL;
-
-       return 0;
-}
-
-static int rsnd_dmaen_prepare(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
-{
-       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       /* maybe suspended */
-       if (dmaen->chan)
-               return 0;
-
-       /*
-        * DMAEngine request uses mutex lock.
-        * Thus, it shouldn't be called under spinlock.
-        * Let's call it under prepare
-        */
-       dmaen->chan = rsnd_dmaen_request_channel(io,
-                                                dma->mod_from,
-                                                dma->mod_to);
-       if (IS_ERR_OR_NULL(dmaen->chan)) {
-               dmaen->chan = NULL;
-               dev_err(dev, "can't get dma channel\n");
-               return -EIO;
-       }
-
-       return snd_dmaengine_pcm_open(io->substream, dmaen->chan);
-}
-
-static int rsnd_dmaen_start(struct rsnd_mod *mod,
-                           struct rsnd_dai_stream *io,
-                           struct rsnd_priv *priv)
-{
-       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-       struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct dma_slave_config cfg = {};
-       enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       int ret;
-
-       /*
-        * in case of monaural data writing or reading through Audio-DMAC
-        * data is always in Left Justified format, so both src and dst
-        * DMA Bus width need to be set equal to physical data width.
-        */
-       if (rsnd_runtime_channel_original(io) == 1) {
-               struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-               int bits = snd_pcm_format_physical_width(runtime->format);
-
-               switch (bits) {
-               case 8:
-                       buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
-                       break;
-               case 16:
-                       buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
-                       break;
-               case 32:
-                       buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
-                       break;
-               default:
-                       dev_err(dev, "invalid format width %d\n", bits);
-                       return -EINVAL;
-               }
-       }
-
-       cfg.direction   = snd_pcm_substream_to_dma_direction(io->substream);
-       cfg.src_addr    = dma->src_addr;
-       cfg.dst_addr    = dma->dst_addr;
-       cfg.src_addr_width = buswidth;
-       cfg.dst_addr_width = buswidth;
-
-       dev_dbg(dev, "%s %pad -> %pad\n",
-               rsnd_mod_name(mod),
-               &cfg.src_addr, &cfg.dst_addr);
-
-       ret = dmaengine_slave_config(dmaen->chan, &cfg);
-       if (ret < 0)
-               return ret;
-
-       return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_START);
-}
-
-struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
-                                         struct rsnd_mod *mod, char *x)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct dma_chan *chan = NULL;
-       struct device_node *np;
-       int i = 0;
-
-       for_each_child_of_node(of_node, np) {
-               i = rsnd_node_fixed_index(dev, np, name, i);
-               if (i < 0) {
-                       chan = NULL;
-                       of_node_put(np);
-                       break;
-               }
-
-               if (i == rsnd_mod_id_raw(mod) && (!chan))
-                       chan = of_dma_request_slave_channel(np, x);
-               i++;
-       }
-
-       /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */
-       of_node_put(of_node);
-
-       return chan;
-}
-
-static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
-                          struct rsnd_dma *dma,
-                          struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
-{
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-       struct dma_chan *chan;
-
-       /* try to get DMAEngine channel */
-       chan = rsnd_dmaen_request_channel(io, mod_from, mod_to);
-       if (IS_ERR_OR_NULL(chan)) {
-               /* Let's follow when -EPROBE_DEFER case */
-               if (PTR_ERR(chan) == -EPROBE_DEFER)
-                       return PTR_ERR(chan);
-
-               /*
-                * DMA failed. try to PIO mode
-                * see
-                *      rsnd_ssi_fallback()
-                *      rsnd_rdai_continuance_probe()
-                */
-               return -EAGAIN;
-       }
-
-       /*
-        * use it for IPMMU if needed
-        * see
-        *      rsnd_preallocate_pages()
-        */
-       io->dmac_dev = chan->device->dev;
-
-       dma_release_channel(chan);
-
-       dmac->dmaen_num++;
-
-       return 0;
-}
-
-static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             snd_pcm_uframes_t *pointer)
-{
-       *pointer = snd_dmaengine_pcm_pointer(io->substream);
-
-       return 0;
-}
-
-static struct rsnd_mod_ops rsnd_dmaen_ops = {
-       .name           = "audmac",
-       .prepare        = rsnd_dmaen_prepare,
-       .cleanup        = rsnd_dmaen_cleanup,
-       .start          = rsnd_dmaen_start,
-       .stop           = rsnd_dmaen_stop,
-       .pointer        = rsnd_dmaen_pointer,
-       .get_status     = rsnd_mod_get_status,
-};
-
-/*
- *             Audio DMAC peri peri
- */
-static const u8 gen2_id_table_ssiu[] = {
-       /* SSI00 ~ SSI07 */
-       0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c,
-       /* SSI10 ~ SSI17 */
-       0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40,
-       /* SSI20 ~ SSI27 */
-       0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44,
-       /* SSI30 ~ SSI37 */
-       0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
-       /* SSI40 ~ SSI47 */
-       0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52,
-       /* SSI5 */
-       0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* SSI6 */
-       0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* SSI7 */
-       0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* SSI8 */
-       0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* SSI90 ~ SSI97 */
-       0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56,
-};
-static const u8 gen2_id_table_scu[] = {
-       0x2d, /* SCU_SRCI0 */
-       0x2e, /* SCU_SRCI1 */
-       0x2f, /* SCU_SRCI2 */
-       0x30, /* SCU_SRCI3 */
-       0x31, /* SCU_SRCI4 */
-       0x32, /* SCU_SRCI5 */
-       0x33, /* SCU_SRCI6 */
-       0x34, /* SCU_SRCI7 */
-       0x35, /* SCU_SRCI8 */
-       0x36, /* SCU_SRCI9 */
-};
-static const u8 gen2_id_table_cmd[] = {
-       0x37, /* SCU_CMD0 */
-       0x38, /* SCU_CMD1 */
-};
-
-static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io,
-                            struct rsnd_mod *mod)
-{
-       struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
-       struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
-       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
-       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
-       const u8 *entry = NULL;
-       int id = 255;
-       int size = 0;
-
-       if ((mod == ssi) ||
-           (mod == ssiu)) {
-               int busif = rsnd_mod_id_sub(ssiu);
-
-               entry = gen2_id_table_ssiu;
-               size = ARRAY_SIZE(gen2_id_table_ssiu);
-               id = (rsnd_mod_id(mod) * 8) + busif;
-       } else if (mod == src) {
-               entry = gen2_id_table_scu;
-               size = ARRAY_SIZE(gen2_id_table_scu);
-               id = rsnd_mod_id(mod);
-       } else if (mod == dvc) {
-               entry = gen2_id_table_cmd;
-               size = ARRAY_SIZE(gen2_id_table_cmd);
-               id = rsnd_mod_id(mod);
-       }
-
-       if ((!entry) || (size <= id)) {
-               struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io));
-
-               dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod));
-
-               /* use non-prohibited SRS number as error */
-               return 0x00; /* SSI00 */
-       }
-
-       return entry[id];
-}
-
-static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io,
-                              struct rsnd_mod *mod_from,
-                              struct rsnd_mod *mod_to)
-{
-       return  (rsnd_dmapp_get_id(io, mod_from) << 24) +
-               (rsnd_dmapp_get_id(io, mod_to) << 16);
-}
-
-#define rsnd_dmapp_addr(dmac, dma, reg) \
-       (dmac->ppbase + 0x20 + reg + \
-        (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id))
-static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg)
-{
-       struct rsnd_mod *mod = rsnd_mod_get(dma);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data);
-
-       iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg));
-}
-
-static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
-{
-       struct rsnd_mod *mod = rsnd_mod_get(dma);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-
-       return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
-}
-
-static void rsnd_dmapp_bset(struct rsnd_dma *dma, u32 data, u32 mask, u32 reg)
-{
-       struct rsnd_mod *mod = rsnd_mod_get(dma);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-       void __iomem *addr = rsnd_dmapp_addr(dmac, dma, reg);
-       u32 val = ioread32(addr);
-
-       val &= ~mask;
-       val |= (data & mask);
-
-       iowrite32(val, addr);
-}
-
-static int rsnd_dmapp_stop(struct rsnd_mod *mod,
-                          struct rsnd_dai_stream *io,
-                          struct rsnd_priv *priv)
-{
-       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-       int i;
-
-       rsnd_dmapp_bset(dma, 0,  PDMACHCR_DE, PDMACHCR);
-
-       for (i = 0; i < 1024; i++) {
-               if (0 == (rsnd_dmapp_read(dma, PDMACHCR) & PDMACHCR_DE))
-                       return 0;
-               udelay(1);
-       }
-
-       return -EIO;
-}
-
-static int rsnd_dmapp_start(struct rsnd_mod *mod,
-                           struct rsnd_dai_stream *io,
-                           struct rsnd_priv *priv)
-{
-       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-       struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
-
-       rsnd_dmapp_write(dma, dma->src_addr,    PDMASAR);
-       rsnd_dmapp_write(dma, dma->dst_addr,    PDMADAR);
-       rsnd_dmapp_write(dma, dmapp->chcr,      PDMACHCR);
-
-       return 0;
-}
-
-static int rsnd_dmapp_attach(struct rsnd_dai_stream *io,
-                            struct rsnd_dma *dma,
-                            struct rsnd_mod *mod_from, struct rsnd_mod *mod_to)
-{
-       struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       dmapp->dmapp_id = dmac->dmapp_num;
-       dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE;
-
-       dmac->dmapp_num++;
-
-       dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n",
-               dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr);
-
-       return 0;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void rsnd_dmapp_debug_info(struct seq_file *m,
-                                 struct rsnd_dai_stream *io,
-                                 struct rsnd_mod *mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-       struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
-       struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma);
-
-       rsnd_debugfs_reg_show(m, dmac->ppres, dmac->ppbase,
-                             0x20 + 0x10 * dmapp->dmapp_id, 0x10);
-}
-#define DEBUG_INFO .debug_info = rsnd_dmapp_debug_info
-#else
-#define DEBUG_INFO
-#endif
-
-static struct rsnd_mod_ops rsnd_dmapp_ops = {
-       .name           = "audmac-pp",
-       .start          = rsnd_dmapp_start,
-       .stop           = rsnd_dmapp_stop,
-       .quit           = rsnd_dmapp_stop,
-       .get_status     = rsnd_mod_get_status,
-       DEBUG_INFO
-};
-
-/*
- *             Common DMAC Interface
- */
-
-/*
- *     DMA read/write register offset
- *
- *     RSND_xxx_I_N    for Audio DMAC input
- *     RSND_xxx_O_N    for Audio DMAC output
- *     RSND_xxx_I_P    for Audio DMAC peri peri input
- *     RSND_xxx_O_P    for Audio DMAC peri peri output
- *
- *     ex) R-Car H2 case
- *           mod        / DMAC in    / DMAC out   / DMAC PP in / DMAC pp out
- *     SSI : 0xec541000 / 0xec241008 / 0xec24100c
- *     SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000
- *     SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000
- *     CMD : 0xec500000 /            / 0xec008000                0xec308000
- */
-#define RDMA_SSI_I_N(addr, i)  (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8)
-#define RDMA_SSI_O_N(addr, i)  (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
-
-#define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
-#define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j)
-
-#define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4)))
-#define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j)
-
-#define RDMA_SRC_I_N(addr, i)  (addr ##_reg - 0x00500000 + (0x400 * i))
-#define RDMA_SRC_O_N(addr, i)  (addr ##_reg - 0x004fc000 + (0x400 * i))
-
-#define RDMA_SRC_I_P(addr, i)  (addr ##_reg - 0x00200000 + (0x400 * i))
-#define RDMA_SRC_O_P(addr, i)  (addr ##_reg - 0x001fc000 + (0x400 * i))
-
-#define RDMA_CMD_O_N(addr, i)  (addr ##_reg - 0x004f8000 + (0x400 * i))
-#define RDMA_CMD_O_P(addr, i)  (addr ##_reg - 0x001f8000 + (0x400 * i))
-
-static dma_addr_t
-rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
-                  struct rsnd_mod *mod,
-                  int is_play, int is_from)
-{
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI);
-       phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU);
-       int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) ||
-                    !!(rsnd_io_to_mod_ssiu(io) == mod);
-       int use_src = !!rsnd_io_to_mod_src(io);
-       int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
-                     !!rsnd_io_to_mod_mix(io) ||
-                     !!rsnd_io_to_mod_ctu(io);
-       int id = rsnd_mod_id(mod);
-       int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io));
-       struct dma_addr {
-               dma_addr_t out_addr;
-               dma_addr_t in_addr;
-       } dma_addrs[3][2][3] = {
-               /* SRC */
-               /* Capture */
-               {{{ 0,                          0 },
-                 { RDMA_SRC_O_N(src, id),      RDMA_SRC_I_P(src, id) },
-                 { RDMA_CMD_O_N(src, id),      RDMA_SRC_I_P(src, id) } },
-                /* Playback */
-                {{ 0,                          0, },
-                 { RDMA_SRC_O_P(src, id),      RDMA_SRC_I_N(src, id) },
-                 { RDMA_CMD_O_P(src, id),      RDMA_SRC_I_N(src, id) } }
-               },
-               /* SSI */
-               /* Capture */
-               {{{ RDMA_SSI_O_N(ssi, id),              0 },
-                 { RDMA_SSIU_O_P(ssi, id, busif),      0 },
-                 { RDMA_SSIU_O_P(ssi, id, busif),      0 } },
-                /* Playback */
-                {{ 0,                  RDMA_SSI_I_N(ssi, id) },
-                 { 0,                  RDMA_SSIU_I_P(ssi, id, busif) },
-                 { 0,                  RDMA_SSIU_I_P(ssi, id, busif) } }
-               },
-               /* SSIU */
-               /* Capture */
-               {{{ RDMA_SSIU_O_N(ssi, id, busif),      0 },
-                 { RDMA_SSIU_O_P(ssi, id, busif),      0 },
-                 { RDMA_SSIU_O_P(ssi, id, busif),      0 } },
-                /* Playback */
-                {{ 0,                  RDMA_SSIU_I_N(ssi, id, busif) },
-                 { 0,                  RDMA_SSIU_I_P(ssi, id, busif) },
-                 { 0,                  RDMA_SSIU_I_P(ssi, id, busif) } } },
-       };
-
-       /*
-        * FIXME
-        *
-        * We can't support SSI9-4/5/6/7, because its address is
-        * out of calculation rule
-        */
-       if ((id == 9) && (busif >= 4))
-               dev_err(dev, "This driver doesn't support SSI%d-%d, so far",
-                       id, busif);
-
-       /* it shouldn't happen */
-       if (use_cmd && !use_src)
-               dev_err(dev, "DVC is selected without SRC\n");
-
-       /* use SSIU or SSI ? */
-       if (is_ssi && rsnd_ssi_use_busif(io))
-               is_ssi++;
-
-       return (is_from) ?
-               dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr :
-               dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr;
-}
-
-/*
- *     Gen4 DMA read/write register offset
- *
- *     ex) R-Car V4H case
- *               mod           / SYS-DMAC in   / SYS-DMAC out
- *     SSI_SDMC: 0xec400000    / 0xec400000    / 0xec400000
- */
-#define RDMA_SSI_SDMC(addr, i) (addr + (0x8000 * i))
-static dma_addr_t
-rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
-                  int is_play, int is_from)
-{
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_BASE_SDMC);
-       int id = rsnd_mod_id(mod);
-       int busif = rsnd_mod_id_sub(mod);
-
-       /*
-        * SSI0 only is supported
-        */
-       if (id != 0) {
-               struct device *dev = rsnd_priv_to_dev(priv);
-
-               dev_err(dev, "This driver doesn't support non SSI0");
-               return -EINVAL;
-       }
-
-       return RDMA_SSI_SDMC(addr, busif);
-}
-
-static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
-                               struct rsnd_mod *mod,
-                               int is_play, int is_from)
-{
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-
-       if (!mod)
-               return 0;
-
-       /*
-        * gen1 uses default DMA addr
-        */
-       if (rsnd_is_gen1(priv))
-               return 0;
-       else if (rsnd_is_gen4(priv))
-               return rsnd_gen4_dma_addr(io, mod, is_play, is_from);
-       else
-               return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
-}
-
-#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
-static void rsnd_dma_of_path(struct rsnd_mod *this,
-                            struct rsnd_dai_stream *io,
-                            int is_play,
-                            struct rsnd_mod **mod_from,
-                            struct rsnd_mod **mod_to)
-{
-       struct rsnd_mod *ssi;
-       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
-       struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
-       struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
-       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
-       struct rsnd_mod *mod[MOD_MAX];
-       struct rsnd_mod *mod_start, *mod_end;
-       struct rsnd_priv *priv = rsnd_mod_to_priv(this);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int nr, i, idx;
-
-       /*
-        * It should use "rcar_sound,ssiu" on DT.
-        * But, we need to keep compatibility for old version.
-        *
-        * If it has "rcar_sound.ssiu", it will be used.
-        * If not, "rcar_sound.ssi" will be used.
-        * see
-        *      rsnd_ssiu_dma_req()
-        *      rsnd_ssi_dma_req()
-        */
-       if (rsnd_ssiu_of_node(priv)) {
-               struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
-
-               /* use SSIU */
-               ssi = ssiu;
-               if (this == rsnd_io_to_mod_ssi(io))
-                       this = ssiu;
-       } else {
-               /* keep compatible, use SSI */
-               ssi = rsnd_io_to_mod_ssi(io);
-       }
-
-       if (!ssi)
-               return;
-
-       nr = 0;
-       for (i = 0; i < MOD_MAX; i++) {
-               mod[i] = NULL;
-               nr += !!rsnd_io_to_mod(io, i);
-       }
-
-       /*
-        * [S] -*-> [E]
-        * [S] -*-> SRC -o-> [E]
-        * [S] -*-> SRC -> DVC -o-> [E]
-        * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E]
-        *
-        * playback     [S] = mem
-        *              [E] = SSI
-        *
-        * capture      [S] = SSI
-        *              [E] = mem
-        *
-        * -*->         Audio DMAC
-        * -o->         Audio DMAC peri peri
-        */
-       mod_start       = (is_play) ? NULL : ssi;
-       mod_end         = (is_play) ? ssi  : NULL;
-
-       idx = 0;
-       mod[idx++] = mod_start;
-       for (i = 1; i < nr; i++) {
-               if (src) {
-                       mod[idx++] = src;
-                       src = NULL;
-               } else if (ctu) {
-                       mod[idx++] = ctu;
-                       ctu = NULL;
-               } else if (mix) {
-                       mod[idx++] = mix;
-                       mix = NULL;
-               } else if (dvc) {
-                       mod[idx++] = dvc;
-                       dvc = NULL;
-               }
-       }
-       mod[idx] = mod_end;
-
-       /*
-        *              | SSI | SRC |
-        * -------------+-----+-----+
-        *  is_play     |  o  |  *  |
-        * !is_play     |  *  |  o  |
-        */
-       if ((this == ssi) == (is_play)) {
-               *mod_from       = mod[idx - 1];
-               *mod_to         = mod[idx];
-       } else {
-               *mod_from       = mod[0];
-               *mod_to         = mod[1];
-       }
-
-       dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this));
-       for (i = 0; i <= idx; i++) {
-               dev_dbg(dev, "  %s%s\n",
-                       rsnd_mod_name(mod[i] ? mod[i] : &mem),
-                       (mod[i] == *mod_from) ? " from" :
-                       (mod[i] == *mod_to)   ? " to" : "");
-       }
-}
-
-static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
-                         struct rsnd_mod **dma_mod)
-{
-       struct rsnd_mod *mod_from = NULL;
-       struct rsnd_mod *mod_to = NULL;
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_dma *dma;
-       struct rsnd_mod_ops *ops;
-       enum rsnd_mod_type type;
-       int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma,
-                     struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
-       int is_play = rsnd_io_is_play(io);
-       int ret, dma_id;
-
-       /*
-        * DMA failed. try to PIO mode
-        * see
-        *      rsnd_ssi_fallback()
-        *      rsnd_rdai_continuance_probe()
-        */
-       if (!dmac)
-               return -EAGAIN;
-
-       rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to);
-
-       /* for Gen2 or later */
-       if (mod_from && mod_to) {
-               ops     = &rsnd_dmapp_ops;
-               attach  = rsnd_dmapp_attach;
-               dma_id  = dmac->dmapp_num;
-               type    = RSND_MOD_AUDMAPP;
-       } else {
-               ops     = &rsnd_dmaen_ops;
-               attach  = rsnd_dmaen_attach;
-               dma_id  = dmac->dmaen_num;
-               type    = RSND_MOD_AUDMA;
-       }
-
-       /* for Gen1, overwrite */
-       if (rsnd_is_gen1(priv)) {
-               ops     = &rsnd_dmaen_ops;
-               attach  = rsnd_dmaen_attach;
-               dma_id  = dmac->dmaen_num;
-               type    = RSND_MOD_AUDMA;
-       }
-
-       dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
-       if (!dma)
-               return -ENOMEM;
-
-       *dma_mod = rsnd_mod_get(dma);
-
-       ret = rsnd_mod_init(priv, *dma_mod, ops, NULL,
-                           type, dma_id);
-       if (ret < 0)
-               return ret;
-
-       dev_dbg(dev, "%s %s -> %s\n",
-               rsnd_mod_name(*dma_mod),
-               rsnd_mod_name(mod_from ? mod_from : &mem),
-               rsnd_mod_name(mod_to   ? mod_to   : &mem));
-
-       ret = attach(io, dma, mod_from, mod_to);
-       if (ret < 0)
-               return ret;
-
-       dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1);
-       dma->dst_addr = rsnd_dma_addr(io, mod_to,   is_play, 0);
-       dma->mod_from = mod_from;
-       dma->mod_to   = mod_to;
-
-       return 0;
-}
-
-int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
-                   struct rsnd_mod **dma_mod)
-{
-       if (!(*dma_mod)) {
-               int ret = rsnd_dma_alloc(io, mod, dma_mod);
-
-               if (ret < 0)
-                       return ret;
-       }
-
-       return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type);
-}
-
-int rsnd_dma_probe(struct rsnd_priv *priv)
-{
-       struct platform_device *pdev = rsnd_priv_to_pdev(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_dma_ctrl *dmac;
-       struct resource *res;
-
-       /*
-        * for Gen1
-        */
-       if (rsnd_is_gen1(priv))
-               return 0;
-
-       /*
-        * for Gen2 or later
-        */
-       dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL);
-       if (!dmac) {
-               dev_err(dev, "dma allocate failed\n");
-               return 0; /* it will be PIO mode */
-       }
-
-       /* for Gen4 doesn't have DMA-pp */
-       if (rsnd_is_gen4(priv))
-               goto audmapp_end;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp");
-       if (!res) {
-               dev_err(dev, "lack of audmapp in DT\n");
-               return 0; /* it will be PIO mode */
-       }
-
-       dmac->dmapp_num = 0;
-       dmac->ppres  = res->start;
-       dmac->ppbase = devm_ioremap_resource(dev, res);
-       if (IS_ERR(dmac->ppbase))
-               return PTR_ERR(dmac->ppbase);
-audmapp_end:
-       priv->dma = dmac;
-
-       /* dummy mem mod for debug */
-       return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0);
-}
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
deleted file mode 100644 (file)
index da91dd3..0000000
+++ /dev/null
@@ -1,392 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car DVC support
-//
-// Copyright (C) 2014 Renesas Solutions Corp.
-// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-/*
- * Playback Volume
- *     amixer set "DVC Out" 100%
- *
- * Capture Volume
- *     amixer set "DVC In" 100%
- *
- * Playback Mute
- *     amixer set "DVC Out Mute" on
- *
- * Capture Mute
- *     amixer set "DVC In Mute" on
- *
- * Volume Ramp
- *     amixer set "DVC Out Ramp Up Rate"   "0.125 dB/64 steps"
- *     amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
- *     amixer set "DVC Out Ramp" on
- *     aplay xxx.wav &
- *     amixer set "DVC Out"  80%  // Volume Down
- *     amixer set "DVC Out" 100%  // Volume Up
- */
-
-#include "rsnd.h"
-
-#define RSND_DVC_NAME_SIZE     16
-
-#define DVC_NAME "dvc"
-
-struct rsnd_dvc {
-       struct rsnd_mod mod;
-       struct rsnd_kctrl_cfg_m volume;
-       struct rsnd_kctrl_cfg_m mute;
-       struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
-       struct rsnd_kctrl_cfg_s rup;    /* Ramp Rate Up */
-       struct rsnd_kctrl_cfg_s rdown;  /* Ramp Rate Down */
-};
-
-#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
-#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
-
-#define rsnd_mod_to_dvc(_mod)  \
-       container_of((_mod), struct rsnd_dvc, mod)
-
-#define for_each_rsnd_dvc(pos, priv, i)                                \
-       for ((i) = 0;                                           \
-            ((i) < rsnd_dvc_nr(priv)) &&                       \
-            ((pos) = (struct rsnd_dvc *)(priv)->dvc + i);      \
-            i++)
-
-static void rsnd_dvc_activation(struct rsnd_mod *mod)
-{
-       rsnd_mod_write(mod, DVC_SWRSR, 0);
-       rsnd_mod_write(mod, DVC_SWRSR, 1);
-}
-
-static void rsnd_dvc_halt(struct rsnd_mod *mod)
-{
-       rsnd_mod_write(mod, DVC_DVUIR, 1);
-       rsnd_mod_write(mod, DVC_SWRSR, 0);
-}
-
-#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \
-                                rsnd_kctrl_vals(dvc->rdown))
-#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13))
-
-static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
-                                             struct rsnd_mod *mod)
-{
-       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
-       u32 val[RSND_MAX_CHANNELS];
-       int i;
-
-       /* Enable Ramp */
-       if (rsnd_kctrl_vals(dvc->ren))
-               for (i = 0; i < RSND_MAX_CHANNELS; i++)
-                       val[i] = rsnd_kctrl_max(dvc->volume);
-       else
-               for (i = 0; i < RSND_MAX_CHANNELS; i++)
-                       val[i] = rsnd_kctrl_valm(dvc->volume, i);
-
-       /* Enable Digital Volume */
-       for (i = 0; i < RSND_MAX_CHANNELS; i++)
-               rsnd_mod_write(mod, DVC_VOLxR(i), val[i]);
-}
-
-static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
-                                struct rsnd_mod *mod)
-{
-       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
-       u32 adinr = 0;
-       u32 dvucr = 0;
-       u32 vrctr = 0;
-       u32 vrpdr = 0;
-       u32 vrdbr = 0;
-
-       adinr = rsnd_get_adinr_bit(mod, io) |
-               rsnd_runtime_channel_after_ctu(io);
-
-       /* Enable Digital Volume, Zero Cross Mute Mode */
-       dvucr |= 0x101;
-
-       /* Enable Ramp */
-       if (rsnd_kctrl_vals(dvc->ren)) {
-               dvucr |= 0x10;
-
-               /*
-                * FIXME !!
-                * use scale-downed Digital Volume
-                * as Volume Ramp
-                * 7F FFFF -> 3FF
-                */
-               vrctr = 0xff;
-               vrpdr = rsnd_dvc_get_vrpdr(dvc);
-               vrdbr = rsnd_dvc_get_vrdbr(dvc);
-       }
-
-       /* Initialize operation */
-       rsnd_mod_write(mod, DVC_DVUIR, 1);
-
-       /* General Information */
-       rsnd_mod_write(mod, DVC_ADINR, adinr);
-       rsnd_mod_write(mod, DVC_DVUCR, dvucr);
-
-       /* Volume Ramp Parameter */
-       rsnd_mod_write(mod, DVC_VRCTR, vrctr);
-       rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
-       rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
-
-       /* Digital Volume Function Parameter */
-       rsnd_dvc_volume_parameter(io, mod);
-
-       /* cancel operation */
-       rsnd_mod_write(mod, DVC_DVUIR, 0);
-}
-
-static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
-                                  struct rsnd_mod *mod)
-{
-       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
-       u32 zcmcr = 0;
-       u32 vrpdr = 0;
-       u32 vrdbr = 0;
-       int i;
-
-       for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++)
-               zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i;
-
-       if (rsnd_kctrl_vals(dvc->ren)) {
-               vrpdr = rsnd_dvc_get_vrpdr(dvc);
-               vrdbr = rsnd_dvc_get_vrdbr(dvc);
-       }
-
-       /* Disable DVC Register access */
-       rsnd_mod_write(mod, DVC_DVUER, 0);
-
-       /* Zero Cross Mute Function */
-       rsnd_mod_write(mod, DVC_ZCMCR, zcmcr);
-
-       /* Volume Ramp Function */
-       rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
-       rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
-       /* add DVC_VRWTR here */
-
-       /* Digital Volume Function Parameter */
-       rsnd_dvc_volume_parameter(io, mod);
-
-       /* Enable DVC Register access */
-       rsnd_mod_write(mod, DVC_DVUER, 1);
-}
-
-static int rsnd_dvc_probe_(struct rsnd_mod *mod,
-                          struct rsnd_dai_stream *io,
-                          struct rsnd_priv *priv)
-{
-       return rsnd_cmd_attach(io, rsnd_mod_id(mod));
-}
-
-static int rsnd_dvc_init(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       int ret;
-
-       ret = rsnd_mod_power_on(mod);
-       if (ret < 0)
-               return ret;
-
-       rsnd_dvc_activation(mod);
-
-       rsnd_dvc_volume_init(io, mod);
-
-       rsnd_dvc_volume_update(io, mod);
-
-       return 0;
-}
-
-static int rsnd_dvc_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       rsnd_dvc_halt(mod);
-
-       rsnd_mod_power_off(mod);
-
-       return 0;
-}
-
-static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
-                           struct rsnd_dai_stream *io,
-                           struct snd_soc_pcm_runtime *rtd)
-{
-       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       int is_play = rsnd_io_is_play(io);
-       int channels = rsnd_rdai_channels_get(rdai);
-       int ret;
-
-       /* Volume */
-       ret = rsnd_kctrl_new_m(mod, io, rtd,
-                       is_play ?
-                       "DVC Out Playback Volume" : "DVC In Capture Volume",
-                       rsnd_kctrl_accept_anytime,
-                       rsnd_dvc_volume_update,
-                       &dvc->volume, channels,
-                       0x00800000 - 1);
-       if (ret < 0)
-               return ret;
-
-       /* Mute */
-       ret = rsnd_kctrl_new_m(mod, io, rtd,
-                       is_play ?
-                       "DVC Out Mute Switch" : "DVC In Mute Switch",
-                       rsnd_kctrl_accept_anytime,
-                       rsnd_dvc_volume_update,
-                       &dvc->mute, channels,
-                       1);
-       if (ret < 0)
-               return ret;
-
-       /* Ramp */
-       ret = rsnd_kctrl_new_s(mod, io, rtd,
-                       is_play ?
-                       "DVC Out Ramp Switch" : "DVC In Ramp Switch",
-                       rsnd_kctrl_accept_anytime,
-                       rsnd_dvc_volume_update,
-                       &dvc->ren, 1);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_kctrl_new_e(mod, io, rtd,
-                       is_play ?
-                       "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
-                       rsnd_kctrl_accept_anytime,
-                       rsnd_dvc_volume_update,
-                       &dvc->rup,
-                       volume_ramp_rate,
-                       VOLUME_RAMP_MAX_DVC);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_kctrl_new_e(mod, io, rtd,
-                       is_play ?
-                       "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
-                       rsnd_kctrl_accept_anytime,
-                       rsnd_dvc_volume_update,
-                       &dvc->rdown,
-                       volume_ramp_rate,
-                       VOLUME_RAMP_MAX_DVC);
-
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
-                                        struct rsnd_mod *mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-
-       return rsnd_dma_request_channel(rsnd_dvc_of_node(priv),
-                                       DVC_NAME, mod, "tx");
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void rsnd_dvc_debug_info(struct seq_file *m,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_mod *mod)
-{
-       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
-                                 0xe00 + rsnd_mod_id(mod) * 0x100, 0x60);
-}
-#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info
-#else
-#define DEBUG_INFO
-#endif
-
-static struct rsnd_mod_ops rsnd_dvc_ops = {
-       .name           = DVC_NAME,
-       .dma_req        = rsnd_dvc_dma_req,
-       .probe          = rsnd_dvc_probe_,
-       .init           = rsnd_dvc_init,
-       .quit           = rsnd_dvc_quit,
-       .pcm_new        = rsnd_dvc_pcm_new,
-       .get_status     = rsnd_mod_get_status,
-       DEBUG_INFO
-};
-
-struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
-{
-       if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
-               id = 0;
-
-       return rsnd_mod_get(rsnd_dvc_get(priv, id));
-}
-
-int rsnd_dvc_probe(struct rsnd_priv *priv)
-{
-       struct device_node *node;
-       struct device_node *np;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_dvc *dvc;
-       struct clk *clk;
-       char name[RSND_DVC_NAME_SIZE];
-       int i, nr, ret;
-
-       node = rsnd_dvc_of_node(priv);
-       if (!node)
-               return 0; /* not used is not error */
-
-       nr = of_get_child_count(node);
-       if (!nr) {
-               ret = -EINVAL;
-               goto rsnd_dvc_probe_done;
-       }
-
-       dvc     = devm_kcalloc(dev, nr, sizeof(*dvc), GFP_KERNEL);
-       if (!dvc) {
-               ret = -ENOMEM;
-               goto rsnd_dvc_probe_done;
-       }
-
-       priv->dvc_nr    = nr;
-       priv->dvc       = dvc;
-
-       i = 0;
-       ret = 0;
-       for_each_child_of_node(node, np) {
-               dvc = rsnd_dvc_get(priv, i);
-
-               snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
-                        DVC_NAME, i);
-
-               clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk)) {
-                       ret = PTR_ERR(clk);
-                       of_node_put(np);
-                       goto rsnd_dvc_probe_done;
-               }
-
-               ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
-                                   clk, RSND_MOD_DVC, i);
-               if (ret) {
-                       of_node_put(np);
-                       goto rsnd_dvc_probe_done;
-               }
-
-               i++;
-       }
-
-rsnd_dvc_probe_done:
-       of_node_put(node);
-
-       return ret;
-}
-
-void rsnd_dvc_remove(struct rsnd_priv *priv)
-{
-       struct rsnd_dvc *dvc;
-       int i;
-
-       for_each_rsnd_dvc(dvc, priv, i) {
-               rsnd_mod_quit(rsnd_mod_get(dvc));
-       }
-}
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
deleted file mode 100644 (file)
index d1f20cd..0000000
+++ /dev/null
@@ -1,495 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car Gen1 SRU/SSI support
-//
-// Copyright (C) 2013 Renesas Solutions Corp.
-// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-/*
- * #define DEBUG
- *
- * you can also add below in
- * ${LINUX}/drivers/base/regmap/regmap.c
- * for regmap debug
- *
- * #define LOG_DEVICE "xxxx.rcar_sound"
- */
-
-#include "rsnd.h"
-
-struct rsnd_gen {
-       struct rsnd_gen_ops *ops;
-
-       /* RSND_BASE_MAX base */
-       void __iomem *base[RSND_BASE_MAX];
-       phys_addr_t res[RSND_BASE_MAX];
-       struct regmap *regmap[RSND_BASE_MAX];
-
-       /* RSND_REG_MAX base */
-       struct regmap_field *regs[REG_MAX];
-       const char *reg_name[REG_MAX];
-};
-
-#define rsnd_priv_to_gen(p)    ((struct rsnd_gen *)(p)->gen)
-#define rsnd_reg_name(gen, id) ((gen)->reg_name[id])
-
-struct rsnd_regmap_field_conf {
-       int idx;
-       unsigned int reg_offset;
-       unsigned int id_offset;
-       const char *reg_name;
-};
-
-#define RSND_REG_SET(id, offset, _id_offset, n)        \
-{                                              \
-       .idx = id,                              \
-       .reg_offset = offset,                   \
-       .id_offset = _id_offset,                \
-       .reg_name = n,                          \
-}
-/* single address mapping */
-#define RSND_GEN_S_REG(id, offset)     \
-       RSND_REG_SET(id, offset, 0, #id)
-
-/* multi address mapping */
-#define RSND_GEN_M_REG(id, offset, _id_offset) \
-       RSND_REG_SET(id, offset, _id_offset, #id)
-
-/*
- *             basic function
- */
-static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
-                                 struct rsnd_gen *gen, enum rsnd_reg reg)
-{
-       if (!gen->regs[reg]) {
-               struct device *dev = rsnd_priv_to_dev(priv);
-
-               dev_err(dev, "unsupported register access %x\n", reg);
-               return 0;
-       }
-
-       return 1;
-}
-
-static int rsnd_mod_id_cmd(struct rsnd_mod *mod)
-{
-       if (mod->ops->id_cmd)
-               return mod->ops->id_cmd(mod);
-
-       return rsnd_mod_id(mod);
-}
-
-u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-       u32 val;
-
-       if (!rsnd_is_accessible_reg(priv, gen, reg))
-               return 0;
-
-       regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val);
-
-       dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n",
-               rsnd_mod_name(mod),
-               rsnd_reg_name(gen, reg), reg, val);
-
-       return val;
-}
-
-void rsnd_mod_write(struct rsnd_mod *mod,
-                   enum rsnd_reg reg, u32 data)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
-       if (!rsnd_is_accessible_reg(priv, gen, reg))
-               return;
-
-       regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data);
-
-       dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n",
-               rsnd_mod_name(mod),
-               rsnd_reg_name(gen, reg), reg, data);
-}
-
-void rsnd_mod_bset(struct rsnd_mod *mod,
-                  enum rsnd_reg reg, u32 mask, u32 data)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
-       if (!rsnd_is_accessible_reg(priv, gen, reg))
-               return;
-
-       regmap_fields_force_update_bits(gen->regs[reg],
-                                       rsnd_mod_id_cmd(mod), mask, data);
-
-       dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n",
-               rsnd_mod_name(mod),
-               rsnd_reg_name(gen, reg), reg, data, mask);
-
-}
-
-phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id)
-{
-       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
-       return  gen->res[reg_id];
-}
-
-#ifdef CONFIG_DEBUG_FS
-void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id)
-{
-       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
-       return  gen->base[reg_id];
-}
-#endif
-
-#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf)                \
-       _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf))
-static int _rsnd_gen_regmap_init(struct rsnd_priv *priv,
-                                int id_size,
-                                int reg_id,
-                                const char *name,
-                                const struct rsnd_regmap_field_conf *conf,
-                                int conf_size)
-{
-       struct platform_device *pdev = rsnd_priv_to_pdev(priv);
-       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct resource *res;
-       struct regmap_config regc;
-       struct regmap_field *regs;
-       struct regmap *regmap;
-       struct reg_field regf;
-       void __iomem *base;
-       int i;
-
-       memset(&regc, 0, sizeof(regc));
-       regc.reg_bits = 32;
-       regc.val_bits = 32;
-       regc.reg_stride = 4;
-       regc.name = name;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
-       if (!res)
-               return -ENODEV;
-
-       base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
-
-       regmap = devm_regmap_init_mmio(dev, base, &regc);
-       if (IS_ERR(regmap))
-               return PTR_ERR(regmap);
-
-       /* RSND_BASE_MAX base */
-       gen->base[reg_id] = base;
-       gen->regmap[reg_id] = regmap;
-       gen->res[reg_id] = res->start;
-
-       for (i = 0; i < conf_size; i++) {
-
-               regf.reg        = conf[i].reg_offset;
-               regf.id_offset  = conf[i].id_offset;
-               regf.lsb        = 0;
-               regf.msb        = 31;
-               regf.id_size    = id_size;
-
-               regs = devm_regmap_field_alloc(dev, regmap, regf);
-               if (IS_ERR(regs))
-                       return PTR_ERR(regs);
-
-               /* RSND_REG_MAX base */
-               gen->regs[conf[i].idx] = regs;
-               gen->reg_name[conf[i].idx] = conf[i].reg_name;
-       }
-
-       return 0;
-}
-
-/*
- * (A) : Gen4 is 0xa0c, but it is not used.
- *     see
- *             rsnd_ssiu_init()
- */
-static const struct rsnd_regmap_field_conf conf_common_ssiu[] = {
-       RSND_GEN_S_REG(SSI_MODE0,               0x800),
-       RSND_GEN_S_REG(SSI_MODE1,               0x804),
-       RSND_GEN_S_REG(SSI_MODE2,               0x808), // (A)
-       RSND_GEN_S_REG(SSI_CONTROL,             0x810),
-       RSND_GEN_S_REG(SSI_SYS_STATUS0,         0x840),
-       RSND_GEN_S_REG(SSI_SYS_STATUS1,         0x844),
-       RSND_GEN_S_REG(SSI_SYS_STATUS2,         0x848),
-       RSND_GEN_S_REG(SSI_SYS_STATUS3,         0x84c),
-       RSND_GEN_S_REG(SSI_SYS_STATUS4,         0x880),
-       RSND_GEN_S_REG(SSI_SYS_STATUS5,         0x884),
-       RSND_GEN_S_REG(SSI_SYS_STATUS6,         0x888),
-       RSND_GEN_S_REG(SSI_SYS_STATUS7,         0x88c),
-       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0,     0x850),
-       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1,     0x854),
-       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2,     0x858),
-       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3,     0x85c),
-       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4,     0x890),
-       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5,     0x894),
-       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6,     0x898),
-       RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7,     0x89c),
-       RSND_GEN_S_REG(HDMI0_SEL,               0x9e0),
-       RSND_GEN_S_REG(HDMI1_SEL,               0x9e4),
-       RSND_GEN_M_REG(SSI_BUSIF0_MODE,         0x0,    0x80),
-       RSND_GEN_M_REG(SSI_BUSIF0_ADINR,        0x4,    0x80),
-       RSND_GEN_M_REG(SSI_BUSIF0_DALIGN,       0x8,    0x80),
-       RSND_GEN_M_REG(SSI_BUSIF1_MODE,         0x20,   0x80),
-       RSND_GEN_M_REG(SSI_BUSIF1_ADINR,        0x24,   0x80),
-       RSND_GEN_M_REG(SSI_BUSIF1_DALIGN,       0x28,   0x80),
-       RSND_GEN_M_REG(SSI_BUSIF2_MODE,         0x40,   0x80),
-       RSND_GEN_M_REG(SSI_BUSIF2_ADINR,        0x44,   0x80),
-       RSND_GEN_M_REG(SSI_BUSIF2_DALIGN,       0x48,   0x80),
-       RSND_GEN_M_REG(SSI_BUSIF3_MODE,         0x60,   0x80),
-       RSND_GEN_M_REG(SSI_BUSIF3_ADINR,        0x64,   0x80),
-       RSND_GEN_M_REG(SSI_BUSIF3_DALIGN,       0x68,   0x80),
-       RSND_GEN_M_REG(SSI_BUSIF4_MODE,         0x500,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF4_ADINR,        0x504,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF4_DALIGN,       0x508,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF5_MODE,         0x520,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF5_ADINR,        0x524,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF5_DALIGN,       0x528,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF6_MODE,         0x540,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF6_ADINR,        0x544,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF6_DALIGN,       0x548,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF7_MODE,         0x560,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF7_ADINR,        0x564,  0x80),
-       RSND_GEN_M_REG(SSI_BUSIF7_DALIGN,       0x568,  0x80),
-       RSND_GEN_M_REG(SSI_MODE,                0xc,    0x80),
-       RSND_GEN_M_REG(SSI_CTRL,                0x10,   0x80),
-       RSND_GEN_M_REG(SSI_INT_ENABLE,          0x18,   0x80),
-       RSND_GEN_S_REG(SSI9_BUSIF0_MODE,        0x48c),
-       RSND_GEN_S_REG(SSI9_BUSIF0_ADINR,       0x484),
-       RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN,      0x488),
-       RSND_GEN_S_REG(SSI9_BUSIF1_MODE,        0x4a0),
-       RSND_GEN_S_REG(SSI9_BUSIF1_ADINR,       0x4a4),
-       RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN,      0x4a8),
-       RSND_GEN_S_REG(SSI9_BUSIF2_MODE,        0x4c0),
-       RSND_GEN_S_REG(SSI9_BUSIF2_ADINR,       0x4c4),
-       RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN,      0x4c8),
-       RSND_GEN_S_REG(SSI9_BUSIF3_MODE,        0x4e0),
-       RSND_GEN_S_REG(SSI9_BUSIF3_ADINR,       0x4e4),
-       RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN,      0x4e8),
-       RSND_GEN_S_REG(SSI9_BUSIF4_MODE,        0xd80),
-       RSND_GEN_S_REG(SSI9_BUSIF4_ADINR,       0xd84),
-       RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN,      0xd88),
-       RSND_GEN_S_REG(SSI9_BUSIF5_MODE,        0xda0),
-       RSND_GEN_S_REG(SSI9_BUSIF5_ADINR,       0xda4),
-       RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN,      0xda8),
-       RSND_GEN_S_REG(SSI9_BUSIF6_MODE,        0xdc0),
-       RSND_GEN_S_REG(SSI9_BUSIF6_ADINR,       0xdc4),
-       RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN,      0xdc8),
-       RSND_GEN_S_REG(SSI9_BUSIF7_MODE,        0xde0),
-       RSND_GEN_S_REG(SSI9_BUSIF7_ADINR,       0xde4),
-       RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN,      0xde8),
-};
-
-static const struct rsnd_regmap_field_conf conf_common_scu[] = {
-       RSND_GEN_M_REG(SRC_I_BUSIF_MODE,        0x0,    0x20),
-       RSND_GEN_M_REG(SRC_O_BUSIF_MODE,        0x4,    0x20),
-       RSND_GEN_M_REG(SRC_BUSIF_DALIGN,        0x8,    0x20),
-       RSND_GEN_M_REG(SRC_ROUTE_MODE0,         0xc,    0x20),
-       RSND_GEN_M_REG(SRC_CTRL,                0x10,   0x20),
-       RSND_GEN_M_REG(SRC_INT_ENABLE0,         0x18,   0x20),
-       RSND_GEN_M_REG(CMD_BUSIF_MODE,          0x184,  0x20),
-       RSND_GEN_M_REG(CMD_BUSIF_DALIGN,        0x188,  0x20),
-       RSND_GEN_M_REG(CMD_ROUTE_SLCT,          0x18c,  0x20),
-       RSND_GEN_M_REG(CMD_CTRL,                0x190,  0x20),
-       RSND_GEN_S_REG(SCU_SYS_STATUS0,         0x1c8),
-       RSND_GEN_S_REG(SCU_SYS_INT_EN0,         0x1cc),
-       RSND_GEN_S_REG(SCU_SYS_STATUS1,         0x1d0),
-       RSND_GEN_S_REG(SCU_SYS_INT_EN1,         0x1d4),
-       RSND_GEN_M_REG(SRC_SWRSR,               0x200,  0x40),
-       RSND_GEN_M_REG(SRC_SRCIR,               0x204,  0x40),
-       RSND_GEN_M_REG(SRC_ADINR,               0x214,  0x40),
-       RSND_GEN_M_REG(SRC_IFSCR,               0x21c,  0x40),
-       RSND_GEN_M_REG(SRC_IFSVR,               0x220,  0x40),
-       RSND_GEN_M_REG(SRC_SRCCR,               0x224,  0x40),
-       RSND_GEN_M_REG(SRC_BSDSR,               0x22c,  0x40),
-       RSND_GEN_M_REG(SRC_BSISR,               0x238,  0x40),
-       RSND_GEN_M_REG(CTU_SWRSR,               0x500,  0x100),
-       RSND_GEN_M_REG(CTU_CTUIR,               0x504,  0x100),
-       RSND_GEN_M_REG(CTU_ADINR,               0x508,  0x100),
-       RSND_GEN_M_REG(CTU_CPMDR,               0x510,  0x100),
-       RSND_GEN_M_REG(CTU_SCMDR,               0x514,  0x100),
-       RSND_GEN_M_REG(CTU_SV00R,               0x518,  0x100),
-       RSND_GEN_M_REG(CTU_SV01R,               0x51c,  0x100),
-       RSND_GEN_M_REG(CTU_SV02R,               0x520,  0x100),
-       RSND_GEN_M_REG(CTU_SV03R,               0x524,  0x100),
-       RSND_GEN_M_REG(CTU_SV04R,               0x528,  0x100),
-       RSND_GEN_M_REG(CTU_SV05R,               0x52c,  0x100),
-       RSND_GEN_M_REG(CTU_SV06R,               0x530,  0x100),
-       RSND_GEN_M_REG(CTU_SV07R,               0x534,  0x100),
-       RSND_GEN_M_REG(CTU_SV10R,               0x538,  0x100),
-       RSND_GEN_M_REG(CTU_SV11R,               0x53c,  0x100),
-       RSND_GEN_M_REG(CTU_SV12R,               0x540,  0x100),
-       RSND_GEN_M_REG(CTU_SV13R,               0x544,  0x100),
-       RSND_GEN_M_REG(CTU_SV14R,               0x548,  0x100),
-       RSND_GEN_M_REG(CTU_SV15R,               0x54c,  0x100),
-       RSND_GEN_M_REG(CTU_SV16R,               0x550,  0x100),
-       RSND_GEN_M_REG(CTU_SV17R,               0x554,  0x100),
-       RSND_GEN_M_REG(CTU_SV20R,               0x558,  0x100),
-       RSND_GEN_M_REG(CTU_SV21R,               0x55c,  0x100),
-       RSND_GEN_M_REG(CTU_SV22R,               0x560,  0x100),
-       RSND_GEN_M_REG(CTU_SV23R,               0x564,  0x100),
-       RSND_GEN_M_REG(CTU_SV24R,               0x568,  0x100),
-       RSND_GEN_M_REG(CTU_SV25R,               0x56c,  0x100),
-       RSND_GEN_M_REG(CTU_SV26R,               0x570,  0x100),
-       RSND_GEN_M_REG(CTU_SV27R,               0x574,  0x100),
-       RSND_GEN_M_REG(CTU_SV30R,               0x578,  0x100),
-       RSND_GEN_M_REG(CTU_SV31R,               0x57c,  0x100),
-       RSND_GEN_M_REG(CTU_SV32R,               0x580,  0x100),
-       RSND_GEN_M_REG(CTU_SV33R,               0x584,  0x100),
-       RSND_GEN_M_REG(CTU_SV34R,               0x588,  0x100),
-       RSND_GEN_M_REG(CTU_SV35R,               0x58c,  0x100),
-       RSND_GEN_M_REG(CTU_SV36R,               0x590,  0x100),
-       RSND_GEN_M_REG(CTU_SV37R,               0x594,  0x100),
-       RSND_GEN_M_REG(MIX_SWRSR,               0xd00,  0x40),
-       RSND_GEN_M_REG(MIX_MIXIR,               0xd04,  0x40),
-       RSND_GEN_M_REG(MIX_ADINR,               0xd08,  0x40),
-       RSND_GEN_M_REG(MIX_MIXMR,               0xd10,  0x40),
-       RSND_GEN_M_REG(MIX_MVPDR,               0xd14,  0x40),
-       RSND_GEN_M_REG(MIX_MDBAR,               0xd18,  0x40),
-       RSND_GEN_M_REG(MIX_MDBBR,               0xd1c,  0x40),
-       RSND_GEN_M_REG(MIX_MDBCR,               0xd20,  0x40),
-       RSND_GEN_M_REG(MIX_MDBDR,               0xd24,  0x40),
-       RSND_GEN_M_REG(MIX_MDBER,               0xd28,  0x40),
-       RSND_GEN_M_REG(DVC_SWRSR,               0xe00,  0x100),
-       RSND_GEN_M_REG(DVC_DVUIR,               0xe04,  0x100),
-       RSND_GEN_M_REG(DVC_ADINR,               0xe08,  0x100),
-       RSND_GEN_M_REG(DVC_DVUCR,               0xe10,  0x100),
-       RSND_GEN_M_REG(DVC_ZCMCR,               0xe14,  0x100),
-       RSND_GEN_M_REG(DVC_VRCTR,               0xe18,  0x100),
-       RSND_GEN_M_REG(DVC_VRPDR,               0xe1c,  0x100),
-       RSND_GEN_M_REG(DVC_VRDBR,               0xe20,  0x100),
-       RSND_GEN_M_REG(DVC_VOL0R,               0xe28,  0x100),
-       RSND_GEN_M_REG(DVC_VOL1R,               0xe2c,  0x100),
-       RSND_GEN_M_REG(DVC_VOL2R,               0xe30,  0x100),
-       RSND_GEN_M_REG(DVC_VOL3R,               0xe34,  0x100),
-       RSND_GEN_M_REG(DVC_VOL4R,               0xe38,  0x100),
-       RSND_GEN_M_REG(DVC_VOL5R,               0xe3c,  0x100),
-       RSND_GEN_M_REG(DVC_VOL6R,               0xe40,  0x100),
-       RSND_GEN_M_REG(DVC_VOL7R,               0xe44,  0x100),
-       RSND_GEN_M_REG(DVC_DVUER,               0xe48,  0x100),
-};
-
-static const struct rsnd_regmap_field_conf conf_common_adg[] = {
-       RSND_GEN_S_REG(BRRA,                    0x00),
-       RSND_GEN_S_REG(BRRB,                    0x04),
-       RSND_GEN_S_REG(BRGCKR,                  0x08),
-       RSND_GEN_S_REG(AUDIO_CLK_SEL0,          0x0c),
-       RSND_GEN_S_REG(AUDIO_CLK_SEL1,          0x10),
-       RSND_GEN_S_REG(AUDIO_CLK_SEL2,          0x14),
-       RSND_GEN_S_REG(DIV_EN,                  0x30),
-       RSND_GEN_S_REG(SRCIN_TIMSEL0,           0x34),
-       RSND_GEN_S_REG(SRCIN_TIMSEL1,           0x38),
-       RSND_GEN_S_REG(SRCIN_TIMSEL2,           0x3c),
-       RSND_GEN_S_REG(SRCIN_TIMSEL3,           0x40),
-       RSND_GEN_S_REG(SRCIN_TIMSEL4,           0x44),
-       RSND_GEN_S_REG(SRCOUT_TIMSEL0,          0x48),
-       RSND_GEN_S_REG(SRCOUT_TIMSEL1,          0x4c),
-       RSND_GEN_S_REG(SRCOUT_TIMSEL2,          0x50),
-       RSND_GEN_S_REG(SRCOUT_TIMSEL3,          0x54),
-       RSND_GEN_S_REG(SRCOUT_TIMSEL4,          0x58),
-       RSND_GEN_S_REG(CMDOUT_TIMSEL,           0x5c),
-};
-
-static const struct rsnd_regmap_field_conf conf_common_ssi[] = {
-       RSND_GEN_M_REG(SSICR,                   0x00,   0x40),
-       RSND_GEN_M_REG(SSISR,                   0x04,   0x40),
-       RSND_GEN_M_REG(SSITDR,                  0x08,   0x40),
-       RSND_GEN_M_REG(SSIRDR,                  0x0c,   0x40),
-       RSND_GEN_M_REG(SSIWSR,                  0x20,   0x40),
-};
-
-/*
- *             Gen4
- */
-static int rsnd_gen4_probe(struct rsnd_priv *priv)
-{
-       struct rsnd_regmap_field_conf conf_null[] = { };
-
-       /*
-        * ssiu: SSIU0
-        * ssi : SSI0
-        */
-       int ret_ssiu = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSIU, "ssiu", conf_common_ssiu);
-       int ret_ssi  = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSI,  "ssi",  conf_common_ssi);
-       int ret_adg  = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG,  "adg",  conf_common_adg);
-       int ret_sdmc = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SDMC, "sdmc", conf_null);
-
-       return ret_adg | ret_ssiu | ret_ssi | ret_sdmc;
-}
-
-/*
- *             Gen2
- */
-static int rsnd_gen2_probe(struct rsnd_priv *priv)
-{
-       /*
-        * ssi : SSI0  - SSI9
-        * ssiu: SSIU0 - SSIU9
-        * scu : SRC0  - SRC9 etc
-        */
-       int ret_ssi  = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSI,  "ssi",  conf_common_ssi);
-       int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSIU, "ssiu", conf_common_ssiu);
-       int ret_scu  = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SCU,  "scu",  conf_common_scu);
-       int ret_adg  = rsnd_gen_regmap_init(priv,  1, RSND_BASE_ADG,  "adg",  conf_common_adg);
-
-       return ret_ssi | ret_ssiu | ret_scu | ret_adg;
-}
-
-/*
- *             Gen1
- */
-
-static int rsnd_gen1_probe(struct rsnd_priv *priv)
-{
-       /*
-        * ssi : SSI0 - SSI8
-        */
-       int ret_ssi  = rsnd_gen_regmap_init(priv, 9, RSND_BASE_SSI, "ssi", conf_common_ssi);
-       int ret_adg  = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg);
-
-       return ret_adg | ret_ssi;
-}
-
-/*
- *             Gen
- */
-int rsnd_gen_probe(struct rsnd_priv *priv)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_gen *gen;
-       int ret;
-
-       gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
-       if (!gen)
-               return -ENOMEM;
-
-       priv->gen = gen;
-
-       ret = -ENODEV;
-       if (rsnd_is_gen1(priv))
-               ret = rsnd_gen1_probe(priv);
-       else if (rsnd_is_gen2(priv) ||
-                rsnd_is_gen3(priv))
-               ret = rsnd_gen2_probe(priv);
-       else if (rsnd_is_gen4(priv))
-               ret = rsnd_gen4_probe(priv);
-
-       if (ret < 0)
-               dev_err(dev, "unknown generation R-Car sound device\n");
-
-       return ret;
-}
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
deleted file mode 100644 (file)
index 024d91c..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// mix.c
-//
-// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-/*
- *                 CTUn        MIXn
- *                 +------+    +------+
- * [SRC3 / SRC6] -> |CTU n0| ->        [MIX n0| ->
- * [SRC4 / SRC9] -> |CTU n1| ->        [MIX n1| ->
- * [SRC0 / SRC1] -> |CTU n2| ->        [MIX n2| ->
- * [SRC2 / SRC5] -> |CTU n3| ->        [MIX n3| ->
- *                 +------+    +------+
- *
- * ex)
- *     DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>;
- *     DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
- *
- * MIX Volume
- *     amixer set "MIX",0  100%  // DAI0 Volume
- *     amixer set "MIX",1  100%  // DAI1 Volume
- *
- * Volume Ramp
- *     amixer set "MIX Ramp Up Rate"   "0.125 dB/1 step"
- *     amixer set "MIX Ramp Down Rate" "4 dB/1 step"
- *     amixer set "MIX Ramp" on
- *     aplay xxx.wav &
- *     amixer set "MIX",0  80%  // DAI0 Volume Down
- *     amixer set "MIX",1 100%  // DAI1 Volume Up
- */
-
-#include "rsnd.h"
-
-#define MIX_NAME_SIZE  16
-#define MIX_NAME "mix"
-
-struct rsnd_mix {
-       struct rsnd_mod mod;
-       struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */
-       struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */
-       struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */
-       struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */
-       struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
-       struct rsnd_kctrl_cfg_s rup;    /* Ramp Rate Up */
-       struct rsnd_kctrl_cfg_s rdw;    /* Ramp Rate Down */
-       u32 flags;
-};
-
-#define ONCE_KCTRL_INITIALIZED         (1 << 0)
-#define HAS_VOLA                       (1 << 1)
-#define HAS_VOLB                       (1 << 2)
-#define HAS_VOLC                       (1 << 3)
-#define HAS_VOLD                       (1 << 4)
-
-#define VOL_MAX                                0x3ff
-
-#define rsnd_mod_to_mix(_mod)  \
-       container_of((_mod), struct rsnd_mix, mod)
-
-#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
-#define rsnd_mix_nr(priv) ((priv)->mix_nr)
-#define for_each_rsnd_mix(pos, priv, i)                                        \
-       for ((i) = 0;                                                   \
-            ((i) < rsnd_mix_nr(priv)) &&                               \
-                    ((pos) = (struct rsnd_mix *)(priv)->mix + i);      \
-            i++)
-
-static void rsnd_mix_activation(struct rsnd_mod *mod)
-{
-       rsnd_mod_write(mod, MIX_SWRSR, 0);
-       rsnd_mod_write(mod, MIX_SWRSR, 1);
-}
-
-static void rsnd_mix_halt(struct rsnd_mod *mod)
-{
-       rsnd_mod_write(mod, MIX_MIXIR, 1);
-       rsnd_mod_write(mod, MIX_SWRSR, 0);
-}
-
-#define rsnd_mix_get_vol(mix, X) \
-       rsnd_flags_has(mix, HAS_VOL##X) ? \
-               (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
-static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
-                                     struct rsnd_mod *mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
-       u32 volA = rsnd_mix_get_vol(mix, A);
-       u32 volB = rsnd_mix_get_vol(mix, B);
-       u32 volC = rsnd_mix_get_vol(mix, C);
-       u32 volD = rsnd_mix_get_vol(mix, D);
-
-       dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n",
-               volA, volB, volC, volD);
-
-       rsnd_mod_write(mod, MIX_MDBAR, volA);
-       rsnd_mod_write(mod, MIX_MDBBR, volB);
-       rsnd_mod_write(mod, MIX_MDBCR, volC);
-       rsnd_mod_write(mod, MIX_MDBDR, volD);
-}
-
-static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
-                                struct rsnd_mod *mod)
-{
-       struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
-
-       rsnd_mod_write(mod, MIX_MIXIR, 1);
-
-       /* General Information */
-       rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
-
-       /* volume step */
-       rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren));
-       rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 |
-                                      rsnd_kctrl_vals(mix->rdw));
-
-       /* common volume parameter */
-       rsnd_mix_volume_parameter(io, mod);
-
-       rsnd_mod_write(mod, MIX_MIXIR, 0);
-}
-
-static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
-                                 struct rsnd_mod *mod)
-{
-       /* Disable MIX dB setting */
-       rsnd_mod_write(mod, MIX_MDBER, 0);
-
-       /* common volume parameter */
-       rsnd_mix_volume_parameter(io, mod);
-
-       /* Enable MIX dB setting */
-       rsnd_mod_write(mod, MIX_MDBER, 1);
-}
-
-static int rsnd_mix_probe_(struct rsnd_mod *mod,
-                          struct rsnd_dai_stream *io,
-                          struct rsnd_priv *priv)
-{
-       return rsnd_cmd_attach(io, rsnd_mod_id(mod));
-}
-
-static int rsnd_mix_init(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       int ret;
-
-       ret = rsnd_mod_power_on(mod);
-       if (ret < 0)
-               return ret;
-
-       rsnd_mix_activation(mod);
-
-       rsnd_mix_volume_init(io, mod);
-
-       rsnd_mix_volume_update(io, mod);
-
-       return 0;
-}
-
-static int rsnd_mix_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       rsnd_mix_halt(mod);
-
-       rsnd_mod_power_off(mod);
-
-       return 0;
-}
-
-static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
-                           struct rsnd_dai_stream *io,
-                           struct snd_soc_pcm_runtime *rtd)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
-       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
-       struct rsnd_kctrl_cfg_s *volume;
-       int ret;
-
-       switch (rsnd_mod_id(src_mod)) {
-       case 3:
-       case 6: /* MDBAR */
-               volume = &mix->volumeA;
-               rsnd_flags_set(mix, HAS_VOLA);
-               break;
-       case 4:
-       case 9: /* MDBBR */
-               volume = &mix->volumeB;
-               rsnd_flags_set(mix, HAS_VOLB);
-               break;
-       case 0:
-       case 1: /* MDBCR */
-               volume = &mix->volumeC;
-               rsnd_flags_set(mix, HAS_VOLC);
-               break;
-       case 2:
-       case 5: /* MDBDR */
-               volume = &mix->volumeD;
-               rsnd_flags_set(mix, HAS_VOLD);
-               break;
-       default:
-               dev_err(dev, "unknown SRC is connected\n");
-               return -EINVAL;
-       }
-
-       /* Volume */
-       ret = rsnd_kctrl_new_s(mod, io, rtd,
-                              "MIX Playback Volume",
-                              rsnd_kctrl_accept_anytime,
-                              rsnd_mix_volume_update,
-                              volume, VOL_MAX);
-       if (ret < 0)
-               return ret;
-       rsnd_kctrl_vals(*volume) = VOL_MAX;
-
-       if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
-               return ret;
-
-       /* Ramp */
-       ret = rsnd_kctrl_new_s(mod, io, rtd,
-                              "MIX Ramp Switch",
-                              rsnd_kctrl_accept_anytime,
-                              rsnd_mix_volume_update,
-                              &mix->ren, 1);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_kctrl_new_e(mod, io, rtd,
-                              "MIX Ramp Up Rate",
-                              rsnd_kctrl_accept_anytime,
-                              rsnd_mix_volume_update,
-                              &mix->rup,
-                              volume_ramp_rate,
-                              VOLUME_RAMP_MAX_MIX);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_kctrl_new_e(mod, io, rtd,
-                              "MIX Ramp Down Rate",
-                              rsnd_kctrl_accept_anytime,
-                              rsnd_mix_volume_update,
-                              &mix->rdw,
-                              volume_ramp_rate,
-                              VOLUME_RAMP_MAX_MIX);
-
-       rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED);
-
-       return ret;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void rsnd_mix_debug_info(struct seq_file *m,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_mod *mod)
-{
-       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
-                                 0xd00 + rsnd_mod_id(mod) * 0x40, 0x30);
-}
-#define DEBUG_INFO .debug_info = rsnd_mix_debug_info
-#else
-#define DEBUG_INFO
-#endif
-
-static struct rsnd_mod_ops rsnd_mix_ops = {
-       .name           = MIX_NAME,
-       .probe          = rsnd_mix_probe_,
-       .init           = rsnd_mix_init,
-       .quit           = rsnd_mix_quit,
-       .pcm_new        = rsnd_mix_pcm_new,
-       .get_status     = rsnd_mod_get_status,
-       DEBUG_INFO
-};
-
-struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
-{
-       if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
-               id = 0;
-
-       return rsnd_mod_get(rsnd_mix_get(priv, id));
-}
-
-int rsnd_mix_probe(struct rsnd_priv *priv)
-{
-       struct device_node *node;
-       struct device_node *np;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_mix *mix;
-       struct clk *clk;
-       char name[MIX_NAME_SIZE];
-       int i, nr, ret;
-
-       node = rsnd_mix_of_node(priv);
-       if (!node)
-               return 0; /* not used is not error */
-
-       nr = of_get_child_count(node);
-       if (!nr) {
-               ret = -EINVAL;
-               goto rsnd_mix_probe_done;
-       }
-
-       mix     = devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL);
-       if (!mix) {
-               ret = -ENOMEM;
-               goto rsnd_mix_probe_done;
-       }
-
-       priv->mix_nr    = nr;
-       priv->mix       = mix;
-
-       i = 0;
-       ret = 0;
-       for_each_child_of_node(node, np) {
-               mix = rsnd_mix_get(priv, i);
-
-               snprintf(name, MIX_NAME_SIZE, "%s.%d",
-                        MIX_NAME, i);
-
-               clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk)) {
-                       ret = PTR_ERR(clk);
-                       of_node_put(np);
-                       goto rsnd_mix_probe_done;
-               }
-
-               ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
-                                   clk, RSND_MOD_MIX, i);
-               if (ret) {
-                       of_node_put(np);
-                       goto rsnd_mix_probe_done;
-               }
-
-               i++;
-       }
-
-rsnd_mix_probe_done:
-       of_node_put(node);
-
-       return ret;
-}
-
-void rsnd_mix_remove(struct rsnd_priv *priv)
-{
-       struct rsnd_mix *mix;
-       int i;
-
-       for_each_rsnd_mix(mix, priv, i) {
-               rsnd_mod_quit(rsnd_mod_get(mix));
-       }
-}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
deleted file mode 100644 (file)
index 3c164d8..0000000
+++ /dev/null
@@ -1,896 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car
-//
-// Copyright (C) 2013 Renesas Solutions Corp.
-// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-#ifndef RSND_H
-#define RSND_H
-
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/sh_dma.h>
-#include <linux/workqueue.h>
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-
-#define RSND_BASE_ADG  0
-#define RSND_BASE_SSI  1
-#define RSND_BASE_SSIU 2
-#define RSND_BASE_SCU  3       // for Gen2/Gen3
-#define RSND_BASE_SDMC 3       // for Gen4     reuse
-#define RSND_BASE_MAX  4
-
-/*
- *     pseudo register
- *
- * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different.
- * This driver uses pseudo register in order to hide it.
- * see gen1/gen2 for detail
- */
-enum rsnd_reg {
-       /* SCU (MIX/CTU/DVC) */
-       SRC_I_BUSIF_MODE,
-       SRC_O_BUSIF_MODE,
-       SRC_ROUTE_MODE0,
-       SRC_SWRSR,
-       SRC_SRCIR,
-       SRC_ADINR,
-       SRC_IFSCR,
-       SRC_IFSVR,
-       SRC_SRCCR,
-       SRC_CTRL,
-       SRC_BSDSR,
-       SRC_BSISR,
-       SRC_INT_ENABLE0,
-       SRC_BUSIF_DALIGN,
-       SRCIN_TIMSEL0,
-       SRCIN_TIMSEL1,
-       SRCIN_TIMSEL2,
-       SRCIN_TIMSEL3,
-       SRCIN_TIMSEL4,
-       SRCOUT_TIMSEL0,
-       SRCOUT_TIMSEL1,
-       SRCOUT_TIMSEL2,
-       SRCOUT_TIMSEL3,
-       SRCOUT_TIMSEL4,
-       SCU_SYS_STATUS0,
-       SCU_SYS_STATUS1,
-       SCU_SYS_INT_EN0,
-       SCU_SYS_INT_EN1,
-       CMD_CTRL,
-       CMD_BUSIF_MODE,
-       CMD_BUSIF_DALIGN,
-       CMD_ROUTE_SLCT,
-       CMDOUT_TIMSEL,
-       CTU_SWRSR,
-       CTU_CTUIR,
-       CTU_ADINR,
-       CTU_CPMDR,
-       CTU_SCMDR,
-       CTU_SV00R,
-       CTU_SV01R,
-       CTU_SV02R,
-       CTU_SV03R,
-       CTU_SV04R,
-       CTU_SV05R,
-       CTU_SV06R,
-       CTU_SV07R,
-       CTU_SV10R,
-       CTU_SV11R,
-       CTU_SV12R,
-       CTU_SV13R,
-       CTU_SV14R,
-       CTU_SV15R,
-       CTU_SV16R,
-       CTU_SV17R,
-       CTU_SV20R,
-       CTU_SV21R,
-       CTU_SV22R,
-       CTU_SV23R,
-       CTU_SV24R,
-       CTU_SV25R,
-       CTU_SV26R,
-       CTU_SV27R,
-       CTU_SV30R,
-       CTU_SV31R,
-       CTU_SV32R,
-       CTU_SV33R,
-       CTU_SV34R,
-       CTU_SV35R,
-       CTU_SV36R,
-       CTU_SV37R,
-       MIX_SWRSR,
-       MIX_MIXIR,
-       MIX_ADINR,
-       MIX_MIXMR,
-       MIX_MVPDR,
-       MIX_MDBAR,
-       MIX_MDBBR,
-       MIX_MDBCR,
-       MIX_MDBDR,
-       MIX_MDBER,
-       DVC_SWRSR,
-       DVC_DVUIR,
-       DVC_ADINR,
-       DVC_DVUCR,
-       DVC_ZCMCR,
-       DVC_VOL0R,
-       DVC_VOL1R,
-       DVC_VOL2R,
-       DVC_VOL3R,
-       DVC_VOL4R,
-       DVC_VOL5R,
-       DVC_VOL6R,
-       DVC_VOL7R,
-       DVC_DVUER,
-       DVC_VRCTR,
-       DVC_VRPDR,
-       DVC_VRDBR,
-
-       /* ADG */
-       BRRA,
-       BRRB,
-       BRGCKR,
-       DIV_EN,
-       AUDIO_CLK_SEL0,
-       AUDIO_CLK_SEL1,
-       AUDIO_CLK_SEL2,
-
-       /* SSIU */
-       SSI_MODE,
-       SSI_MODE0,
-       SSI_MODE1,
-       SSI_MODE2,
-       SSI_CONTROL,
-       SSI_CTRL,
-       SSI_BUSIF0_MODE,
-       SSI_BUSIF1_MODE,
-       SSI_BUSIF2_MODE,
-       SSI_BUSIF3_MODE,
-       SSI_BUSIF4_MODE,
-       SSI_BUSIF5_MODE,
-       SSI_BUSIF6_MODE,
-       SSI_BUSIF7_MODE,
-       SSI_BUSIF0_ADINR,
-       SSI_BUSIF1_ADINR,
-       SSI_BUSIF2_ADINR,
-       SSI_BUSIF3_ADINR,
-       SSI_BUSIF4_ADINR,
-       SSI_BUSIF5_ADINR,
-       SSI_BUSIF6_ADINR,
-       SSI_BUSIF7_ADINR,
-       SSI_BUSIF0_DALIGN,
-       SSI_BUSIF1_DALIGN,
-       SSI_BUSIF2_DALIGN,
-       SSI_BUSIF3_DALIGN,
-       SSI_BUSIF4_DALIGN,
-       SSI_BUSIF5_DALIGN,
-       SSI_BUSIF6_DALIGN,
-       SSI_BUSIF7_DALIGN,
-       SSI_INT_ENABLE,
-       SSI_SYS_STATUS0,
-       SSI_SYS_STATUS1,
-       SSI_SYS_STATUS2,
-       SSI_SYS_STATUS3,
-       SSI_SYS_STATUS4,
-       SSI_SYS_STATUS5,
-       SSI_SYS_STATUS6,
-       SSI_SYS_STATUS7,
-       SSI_SYS_INT_ENABLE0,
-       SSI_SYS_INT_ENABLE1,
-       SSI_SYS_INT_ENABLE2,
-       SSI_SYS_INT_ENABLE3,
-       SSI_SYS_INT_ENABLE4,
-       SSI_SYS_INT_ENABLE5,
-       SSI_SYS_INT_ENABLE6,
-       SSI_SYS_INT_ENABLE7,
-       HDMI0_SEL,
-       HDMI1_SEL,
-       SSI9_BUSIF0_MODE,
-       SSI9_BUSIF1_MODE,
-       SSI9_BUSIF2_MODE,
-       SSI9_BUSIF3_MODE,
-       SSI9_BUSIF4_MODE,
-       SSI9_BUSIF5_MODE,
-       SSI9_BUSIF6_MODE,
-       SSI9_BUSIF7_MODE,
-       SSI9_BUSIF0_ADINR,
-       SSI9_BUSIF1_ADINR,
-       SSI9_BUSIF2_ADINR,
-       SSI9_BUSIF3_ADINR,
-       SSI9_BUSIF4_ADINR,
-       SSI9_BUSIF5_ADINR,
-       SSI9_BUSIF6_ADINR,
-       SSI9_BUSIF7_ADINR,
-       SSI9_BUSIF0_DALIGN,
-       SSI9_BUSIF1_DALIGN,
-       SSI9_BUSIF2_DALIGN,
-       SSI9_BUSIF3_DALIGN,
-       SSI9_BUSIF4_DALIGN,
-       SSI9_BUSIF5_DALIGN,
-       SSI9_BUSIF6_DALIGN,
-       SSI9_BUSIF7_DALIGN,
-
-       /* SSI */
-       SSICR,
-       SSISR,
-       SSITDR,
-       SSIRDR,
-       SSIWSR,
-
-       REG_MAX,
-};
-#define SRCIN_TIMSEL(i)                (SRCIN_TIMSEL0 + (i))
-#define SRCOUT_TIMSEL(i)       (SRCOUT_TIMSEL0 + (i))
-#define CTU_SVxxR(i, j)                (CTU_SV00R + (i * 8) + (j))
-#define DVC_VOLxR(i)           (DVC_VOL0R + (i))
-#define AUDIO_CLK_SEL(i)       (AUDIO_CLK_SEL0 + (i))
-#define SSI_BUSIF_MODE(i)      (SSI_BUSIF0_MODE + (i))
-#define SSI_BUSIF_ADINR(i)     (SSI_BUSIF0_ADINR + (i))
-#define SSI_BUSIF_DALIGN(i)    (SSI_BUSIF0_DALIGN + (i))
-#define SSI9_BUSIF_MODE(i)     (SSI9_BUSIF0_MODE + (i))
-#define SSI9_BUSIF_ADINR(i)    (SSI9_BUSIF0_ADINR + (i))
-#define SSI9_BUSIF_DALIGN(i)   (SSI9_BUSIF0_DALIGN + (i))
-#define SSI_SYS_STATUS(i)      (SSI_SYS_STATUS0 + (i))
-#define SSI_SYS_INT_ENABLE(i) (SSI_SYS_INT_ENABLE0 + (i))
-
-
-struct rsnd_priv;
-struct rsnd_mod;
-struct rsnd_dai;
-struct rsnd_dai_stream;
-
-/*
- *     R-Car basic functions
- */
-u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg);
-void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data);
-void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data);
-u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
-u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
-u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
-
-/*
- *     R-Car DMA
- */
-int rsnd_dma_attach(struct rsnd_dai_stream *io,
-                   struct rsnd_mod *mod, struct rsnd_mod **dma_mod);
-int rsnd_dma_probe(struct rsnd_priv *priv);
-struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
-                                         struct rsnd_mod *mod, char *x);
-
-/*
- *     R-Car sound mod
- */
-enum rsnd_mod_type {
-       RSND_MOD_AUDMAPP,
-       RSND_MOD_AUDMA,
-       RSND_MOD_DVC,
-       RSND_MOD_MIX,
-       RSND_MOD_CTU,
-       RSND_MOD_CMD,
-       RSND_MOD_SRC,
-       RSND_MOD_SSIM3,         /* SSI multi 3 */
-       RSND_MOD_SSIM2,         /* SSI multi 2 */
-       RSND_MOD_SSIM1,         /* SSI multi 1 */
-       RSND_MOD_SSIP,          /* SSI parent */
-       RSND_MOD_SSI,
-       RSND_MOD_SSIU,
-       RSND_MOD_MAX,
-};
-
-struct rsnd_mod_ops {
-       char *name;
-       struct dma_chan* (*dma_req)(struct rsnd_dai_stream *io,
-                                   struct rsnd_mod *mod);
-       int (*probe)(struct rsnd_mod *mod,
-                    struct rsnd_dai_stream *io,
-                    struct rsnd_priv *priv);
-       int (*remove)(struct rsnd_mod *mod,
-                     struct rsnd_dai_stream *io,
-                     struct rsnd_priv *priv);
-       int (*init)(struct rsnd_mod *mod,
-                   struct rsnd_dai_stream *io,
-                   struct rsnd_priv *priv);
-       int (*quit)(struct rsnd_mod *mod,
-                   struct rsnd_dai_stream *io,
-                   struct rsnd_priv *priv);
-       int (*start)(struct rsnd_mod *mod,
-                    struct rsnd_dai_stream *io,
-                    struct rsnd_priv *priv);
-       int (*stop)(struct rsnd_mod *mod,
-                   struct rsnd_dai_stream *io,
-                   struct rsnd_priv *priv);
-       int (*irq)(struct rsnd_mod *mod,
-                  struct rsnd_dai_stream *io,
-                  struct rsnd_priv *priv, int enable);
-       int (*pcm_new)(struct rsnd_mod *mod,
-                      struct rsnd_dai_stream *io,
-                      struct snd_soc_pcm_runtime *rtd);
-       int (*hw_params)(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct snd_pcm_substream *substream,
-                        struct snd_pcm_hw_params *hw_params);
-       int (*pointer)(struct rsnd_mod *mod,
-                      struct rsnd_dai_stream *io,
-                      snd_pcm_uframes_t *pointer);
-       int (*fallback)(struct rsnd_mod *mod,
-                       struct rsnd_dai_stream *io,
-                       struct rsnd_priv *priv);
-       int (*prepare)(struct rsnd_mod *mod,
-                      struct rsnd_dai_stream *io,
-                      struct rsnd_priv *priv);
-       int (*cleanup)(struct rsnd_mod *mod,
-                      struct rsnd_dai_stream *io,
-                      struct rsnd_priv *priv);
-       int (*hw_free)(struct rsnd_mod *mod,
-                      struct rsnd_dai_stream *io,
-                      struct snd_pcm_substream *substream);
-       u32 *(*get_status)(struct rsnd_mod *mod,
-                          struct rsnd_dai_stream *io,
-                          enum rsnd_mod_type type);
-       int (*id)(struct rsnd_mod *mod);
-       int (*id_sub)(struct rsnd_mod *mod);
-       int (*id_cmd)(struct rsnd_mod *mod);
-
-#ifdef CONFIG_DEBUG_FS
-       void (*debug_info)(struct seq_file *m,
-                          struct rsnd_dai_stream *io, struct rsnd_mod *mod);
-#endif
-};
-
-struct rsnd_dai_stream;
-struct rsnd_mod {
-       int id;
-       enum rsnd_mod_type type;
-       struct rsnd_mod_ops *ops;
-       struct rsnd_priv *priv;
-       struct clk *clk;
-       u32 status;
-};
-/*
- * status
- *
- * 0xH000DCB0
- *
- * B   0: init         1: quit
- * C   0: start        1: stop
- * D   0: hw_params    1: hw_free
- *
- * H is always called (see __rsnd_mod_call)
- */
-#define __rsnd_mod_shift_init          4
-#define __rsnd_mod_shift_quit          4
-#define __rsnd_mod_shift_start         8
-#define __rsnd_mod_shift_stop          8
-#define __rsnd_mod_shift_hw_params     12
-#define __rsnd_mod_shift_hw_free       12
-#define __rsnd_mod_shift_probe         28 /* always called */
-#define __rsnd_mod_shift_remove                28 /* always called */
-#define __rsnd_mod_shift_irq           28 /* always called */
-#define __rsnd_mod_shift_pcm_new       28 /* always called */
-#define __rsnd_mod_shift_fallback      28 /* always called */
-#define __rsnd_mod_shift_pointer       28 /* always called */
-#define __rsnd_mod_shift_prepare       28 /* always called */
-#define __rsnd_mod_shift_cleanup       28 /* always called */
-
-#define __rsnd_mod_add_probe           0
-#define __rsnd_mod_add_remove          0
-#define __rsnd_mod_add_prepare         0
-#define __rsnd_mod_add_cleanup         0
-#define __rsnd_mod_add_init             1 /* needs protect */
-#define __rsnd_mod_add_quit            -1 /* needs protect */
-#define __rsnd_mod_add_start            1 /* needs protect */
-#define __rsnd_mod_add_stop            -1 /* needs protect */
-#define __rsnd_mod_add_hw_params        1 /* needs protect */
-#define __rsnd_mod_add_hw_free         -1 /* needs protect */
-#define __rsnd_mod_add_irq             0
-#define __rsnd_mod_add_pcm_new         0
-#define __rsnd_mod_add_fallback                0
-#define __rsnd_mod_add_pointer         0
-
-#define __rsnd_mod_call_probe          0
-#define __rsnd_mod_call_remove         0
-#define __rsnd_mod_call_prepare                0
-#define __rsnd_mod_call_cleanup                0
-#define __rsnd_mod_call_init           0 /* needs protect */
-#define __rsnd_mod_call_quit           1 /* needs protect */
-#define __rsnd_mod_call_start          0 /* needs protect */
-#define __rsnd_mod_call_stop           1 /* needs protect */
-#define __rsnd_mod_call_hw_params      0 /* needs protect */
-#define __rsnd_mod_call_hw_free                1 /* needs protect */
-#define __rsnd_mod_call_irq            0
-#define __rsnd_mod_call_pcm_new                0
-#define __rsnd_mod_call_fallback       0
-#define __rsnd_mod_call_pointer                0
-
-#define rsnd_mod_to_priv(mod)  ((mod)->priv)
-#define rsnd_mod_power_on(mod) clk_enable((mod)->clk)
-#define rsnd_mod_power_off(mod)        clk_disable((mod)->clk)
-#define rsnd_mod_get(ip)       (&(ip)->mod)
-
-int rsnd_mod_init(struct rsnd_priv *priv,
-                 struct rsnd_mod *mod,
-                 struct rsnd_mod_ops *ops,
-                 struct clk *clk,
-                 enum rsnd_mod_type type,
-                 int id);
-void rsnd_mod_quit(struct rsnd_mod *mod);
-struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io,
-                                 struct rsnd_mod *mod);
-void rsnd_mod_interrupt(struct rsnd_mod *mod,
-                       void (*callback)(struct rsnd_mod *mod,
-                                        struct rsnd_dai_stream *io));
-u32 *rsnd_mod_get_status(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        enum rsnd_mod_type type);
-int rsnd_mod_id(struct rsnd_mod *mod);
-int rsnd_mod_id_raw(struct rsnd_mod *mod);
-int rsnd_mod_id_sub(struct rsnd_mod *mod);
-char *rsnd_mod_name(struct rsnd_mod *mod);
-struct rsnd_mod *rsnd_mod_next(int *iterator,
-                              struct rsnd_dai_stream *io,
-                              enum rsnd_mod_type *array,
-                              int array_size);
-#define for_each_rsnd_mod(iterator, pos, io)                           \
-       for (iterator = 0;                                              \
-            (pos = rsnd_mod_next(&iterator, io, NULL, 0)); iterator++)
-#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size)       \
-       for (iterator = 0;                                              \
-            (pos = rsnd_mod_next(&iterator, io, array, size)); iterator++)
-#define for_each_rsnd_mod_array(iterator, pos, io, array)              \
-       for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array))
-
-void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
-               struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
-               struct device_node *node,
-               struct device_node *playback,
-               struct device_node *capture);
-int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name);
-int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx);
-
-int rsnd_channel_normalization(int chan);
-#define rsnd_runtime_channel_original(io) \
-       rsnd_runtime_channel_original_with_params(io, NULL)
-int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
-                               struct snd_pcm_hw_params *params);
-#define rsnd_runtime_channel_after_ctu(io)                     \
-       rsnd_runtime_channel_after_ctu_with_params(io, NULL)
-int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
-                               struct snd_pcm_hw_params *params);
-#define rsnd_runtime_channel_for_ssi(io) \
-       rsnd_runtime_channel_for_ssi_with_params(io, NULL)
-int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
-                                struct snd_pcm_hw_params *params);
-int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io);
-int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io);
-int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io);
-
-/*
- * DT
- */
-#define rsnd_parse_of_node(priv, node)                                 \
-       of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node)
-#define RSND_NODE_DAI  "rcar_sound,dai"
-#define RSND_NODE_SSI  "rcar_sound,ssi"
-#define RSND_NODE_SSIU "rcar_sound,ssiu"
-#define RSND_NODE_SRC  "rcar_sound,src"
-#define RSND_NODE_CTU  "rcar_sound,ctu"
-#define RSND_NODE_MIX  "rcar_sound,mix"
-#define RSND_NODE_DVC  "rcar_sound,dvc"
-
-/*
- *     R-Car sound DAI
- */
-#define RSND_DAI_NAME_SIZE     16
-struct rsnd_dai_stream {
-       char name[RSND_DAI_NAME_SIZE];
-       struct snd_pcm_substream *substream;
-       struct rsnd_mod *mod[RSND_MOD_MAX];
-       struct rsnd_mod *dma;
-       struct rsnd_dai *rdai;
-       struct device *dmac_dev; /* for IPMMU */
-       u32 converted_rate;      /* converted sampling rate */
-       int converted_chan;      /* converted channels */
-       u32 parent_ssi_status;
-       u32 flags;
-};
-
-/* flags */
-#define RSND_STREAM_HDMI0      (1 << 0) /* for HDMI0 */
-#define RSND_STREAM_HDMI1      (1 << 1) /* for HDMI1 */
-#define RSND_STREAM_TDM_SPLIT  (1 << 2) /* for TDM split mode */
-#define RSND_HW_RULE_ERR       (1 << 3) /* hw_rule error */
-
-#define rsnd_io_to_mod(io, i)  ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
-#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
-#define rsnd_io_to_mod_ssiu(io)        rsnd_io_to_mod((io), RSND_MOD_SSIU)
-#define rsnd_io_to_mod_ssip(io)        rsnd_io_to_mod((io), RSND_MOD_SSIP)
-#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
-#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
-#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX)
-#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC)
-#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD)
-#define rsnd_io_to_rdai(io)    ((io)->rdai)
-#define rsnd_io_to_priv(io)    (rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
-#define rsnd_io_is_play(io)    (&rsnd_io_to_rdai(io)->playback == io)
-#define rsnd_io_to_runtime(io) ((io)->substream ? \
-                               (io)->substream->runtime : NULL)
-#define rsnd_io_converted_rate(io)     ((io)->converted_rate)
-#define rsnd_io_converted_chan(io)     ((io)->converted_chan)
-int rsnd_io_is_working(struct rsnd_dai_stream *io);
-
-struct rsnd_dai {
-       char name[RSND_DAI_NAME_SIZE];
-       struct rsnd_dai_stream playback;
-       struct rsnd_dai_stream capture;
-       struct rsnd_priv *priv;
-       struct snd_pcm_hw_constraint_list constraint;
-       struct of_phandle_args dai_args;
-
-       int max_channels;       /* 2ch - 16ch */
-       int ssi_lane;           /* 1lane - 4lane */
-       int chan_width;         /* 16/24/32 bit width */
-
-       unsigned int clk_master:1;
-       unsigned int bit_clk_inv:1;
-       unsigned int frm_clk_inv:1;
-       unsigned int sys_delay:1;
-       unsigned int data_alignment:1;
-};
-
-#define rsnd_rdai_nr(priv) ((priv)->rdai_nr)
-#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
-#define rsnd_rdai_to_priv(rdai) ((rdai)->priv)
-#define for_each_rsnd_dai(rdai, priv, i)               \
-       for (i = 0;                                     \
-            (i < rsnd_rdai_nr(priv)) &&                \
-            ((rdai) = rsnd_rdai_get(priv, i));         \
-            i++)
-
-struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id);
-
-#define rsnd_rdai_channels_set(rdai, max_channels) \
-       rsnd_rdai_channels_ctrl(rdai, max_channels)
-#define rsnd_rdai_channels_get(rdai) \
-       rsnd_rdai_channels_ctrl(rdai, 0)
-int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai,
-                           int max_channels);
-
-#define rsnd_rdai_ssi_lane_set(rdai, ssi_lane) \
-       rsnd_rdai_ssi_lane_ctrl(rdai, ssi_lane)
-#define rsnd_rdai_ssi_lane_get(rdai) \
-       rsnd_rdai_ssi_lane_ctrl(rdai, 0)
-int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
-                           int ssi_lane);
-
-#define rsnd_rdai_width_set(rdai, width) \
-       rsnd_rdai_width_ctrl(rdai, width)
-#define rsnd_rdai_width_get(rdai) \
-       rsnd_rdai_width_ctrl(rdai, 0)
-int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width);
-int rsnd_dai_connect(struct rsnd_mod *mod,
-                    struct rsnd_dai_stream *io,
-                    enum rsnd_mod_type type);
-
-/*
- *     R-Car Gen1/Gen2
- */
-int rsnd_gen_probe(struct rsnd_priv *priv);
-void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
-                              struct rsnd_mod *mod,
-                              enum rsnd_reg reg);
-phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id);
-#ifdef CONFIG_DEBUG_FS
-void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id);
-#endif
-
-/*
- *     R-Car ADG
- */
-int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate);
-int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod);
-int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate);
-int rsnd_adg_probe(struct rsnd_priv *priv);
-void rsnd_adg_remove(struct rsnd_priv *priv);
-int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
-                                 struct rsnd_dai_stream *io,
-                                 unsigned int in_rate,
-                                 unsigned int out_rate);
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
-                                struct rsnd_dai_stream *io);
-#define rsnd_adg_clk_enable(priv)      rsnd_adg_clk_control(priv, 1)
-#define rsnd_adg_clk_disable(priv)     rsnd_adg_clk_control(priv, 0)
-void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);
-void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m);
-
-/*
- *     R-Car sound priv
- */
-struct rsnd_priv {
-
-       struct platform_device *pdev;
-       spinlock_t lock;
-       unsigned long flags;
-#define RSND_GEN_MASK  (0xF << 0)
-#define RSND_GEN1      (1 << 0)
-#define RSND_GEN2      (2 << 0)
-#define RSND_GEN3      (3 << 0)
-#define RSND_GEN4      (4 << 0)
-#define RSND_SOC_MASK  (0xFF << 4)
-#define RSND_SOC_E     (1 << 4) /* E1/E2/E3 */
-
-       /*
-        * below value will be filled on rsnd_gen_probe()
-        */
-       void *gen;
-
-       /*
-        * below value will be filled on rsnd_adg_probe()
-        */
-       void *adg;
-
-       /*
-        * below value will be filled on rsnd_dma_probe()
-        */
-       void *dma;
-
-       /*
-        * below value will be filled on rsnd_ssi_probe()
-        */
-       void *ssi;
-       int ssi_nr;
-
-       /*
-        * below value will be filled on rsnd_ssiu_probe()
-        */
-       void *ssiu;
-       int ssiu_nr;
-
-       /*
-        * below value will be filled on rsnd_src_probe()
-        */
-       void *src;
-       int src_nr;
-
-       /*
-        * below value will be filled on rsnd_ctu_probe()
-        */
-       void *ctu;
-       int ctu_nr;
-
-       /*
-        * below value will be filled on rsnd_mix_probe()
-        */
-       void *mix;
-       int mix_nr;
-
-       /*
-        * below value will be filled on rsnd_dvc_probe()
-        */
-       void *dvc;
-       int dvc_nr;
-
-       /*
-        * below value will be filled on rsnd_cmd_probe()
-        */
-       void *cmd;
-       int cmd_nr;
-
-       /*
-        * below value will be filled on rsnd_dai_probe()
-        */
-       struct snd_soc_dai_driver *daidrv;
-       struct rsnd_dai *rdai;
-       int rdai_nr;
-
-#define RSND_MAX_COMPONENT 3
-       int component_dais[RSND_MAX_COMPONENT];
-};
-
-#define rsnd_priv_to_pdev(priv)        ((priv)->pdev)
-#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev))
-
-#define rsnd_is_gen1(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1)
-#define rsnd_is_gen2(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2)
-#define rsnd_is_gen3(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3)
-#define rsnd_is_gen4(priv)     (((priv)->flags & RSND_GEN_MASK) == RSND_GEN4)
-#define rsnd_is_gen3_e3(priv)  (((priv)->flags & \
-                                       (RSND_GEN_MASK | RSND_SOC_MASK)) == \
-                                       (RSND_GEN3 | RSND_SOC_E))
-
-#define rsnd_flags_has(p, f) ((p)->flags & (f))
-#define rsnd_flags_set(p, f) ((p)->flags |= (f))
-#define rsnd_flags_del(p, f) ((p)->flags &= ~(f))
-
-/*
- *     rsnd_kctrl
- */
-struct rsnd_kctrl_cfg {
-       unsigned int max;
-       unsigned int size;
-       u32 *val;
-       const char * const *texts;
-       int (*accept)(struct rsnd_dai_stream *io);
-       void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
-       struct rsnd_dai_stream *io;
-       struct snd_card *card;
-       struct snd_kcontrol *kctrl;
-       struct rsnd_mod *mod;
-};
-
-#define RSND_MAX_CHANNELS      8
-struct rsnd_kctrl_cfg_m {
-       struct rsnd_kctrl_cfg cfg;
-       u32 val[RSND_MAX_CHANNELS];
-};
-
-struct rsnd_kctrl_cfg_s {
-       struct rsnd_kctrl_cfg cfg;
-       u32 val;
-};
-#define rsnd_kctrl_size(x)     ((x).cfg.size)
-#define rsnd_kctrl_max(x)      ((x).cfg.max)
-#define rsnd_kctrl_valm(x, i)  ((x).val[i])    /* = (x).cfg.val[i] */
-#define rsnd_kctrl_vals(x)     ((x).val)       /* = (x).cfg.val[0] */
-
-int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io);
-int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io);
-struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg);
-struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg);
-int rsnd_kctrl_new(struct rsnd_mod *mod,
-                  struct rsnd_dai_stream *io,
-                  struct snd_soc_pcm_runtime *rtd,
-                  const unsigned char *name,
-                  int (*accept)(struct rsnd_dai_stream *io),
-                  void (*update)(struct rsnd_dai_stream *io,
-                                 struct rsnd_mod *mod),
-                  struct rsnd_kctrl_cfg *cfg,
-                  const char * const *texts,
-                  int size,
-                  u32 max);
-
-#define rsnd_kctrl_new_m(mod, io, rtd, name, accept, update, cfg, size, max) \
-       rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_m(cfg), \
-                      NULL, size, max)
-
-#define rsnd_kctrl_new_s(mod, io, rtd, name, accept, update, cfg, max) \
-       rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
-                      NULL, 1, max)
-
-#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts, size) \
-       rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \
-                      texts, 1, size)
-
-extern const char * const volume_ramp_rate[];
-#define VOLUME_RAMP_MAX_DVC    (0x17 + 1)
-#define VOLUME_RAMP_MAX_MIX    (0x0a + 1)
-
-/*
- *     R-Car SSI
- */
-int rsnd_ssi_probe(struct rsnd_priv *priv);
-void rsnd_ssi_remove(struct rsnd_priv *priv);
-struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
-int rsnd_ssi_use_busif(struct rsnd_dai_stream *io);
-u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io);
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
-
-#define rsnd_ssi_is_pin_sharing(io)    \
-       __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io))
-int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
-
-#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI)
-void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
-                           struct device_node *playback,
-                           struct device_node *capture);
-unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
-                      int param1, int param2, int *idx);
-
-/*
- *     R-Car SSIU
- */
-int rsnd_ssiu_attach(struct rsnd_dai_stream *io,
-                    struct rsnd_mod *mod);
-int rsnd_ssiu_probe(struct rsnd_priv *priv);
-void rsnd_ssiu_remove(struct rsnd_priv *priv);
-void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
-                            struct device_node *playback,
-                            struct device_node *capture);
-#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU)
-bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod);
-
-/*
- *     R-Car SRC
- */
-int rsnd_src_probe(struct rsnd_priv *priv);
-void rsnd_src_remove(struct rsnd_priv *priv);
-struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
-
-#define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1)
-#define rsnd_src_get_out_rate(priv, io) rsnd_src_get_rate(priv, io, 0)
-unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
-                              struct rsnd_dai_stream *io,
-                              int is_in);
-
-#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC)
-#define rsnd_parse_connect_src(rdai, playback, capture)                        \
-       rsnd_parse_connect_common(rdai, "src", rsnd_src_mod_get,        \
-                                 rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \
-                                                  playback, capture)
-
-/*
- *     R-Car CTU
- */
-int rsnd_ctu_probe(struct rsnd_priv *priv);
-void rsnd_ctu_remove(struct rsnd_priv *priv);
-struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
-#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU)
-#define rsnd_parse_connect_ctu(rdai, playback, capture)                        \
-       rsnd_parse_connect_common(rdai, "ctu", rsnd_ctu_mod_get,        \
-                                 rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \
-                                                  playback, capture)
-
-/*
- *     R-Car MIX
- */
-int rsnd_mix_probe(struct rsnd_priv *priv);
-void rsnd_mix_remove(struct rsnd_priv *priv);
-struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
-#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX)
-#define rsnd_parse_connect_mix(rdai, playback, capture)                        \
-       rsnd_parse_connect_common(rdai, "mix", rsnd_mix_mod_get,        \
-                                 rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \
-                                                  playback, capture)
-
-/*
- *     R-Car DVC
- */
-int rsnd_dvc_probe(struct rsnd_priv *priv);
-void rsnd_dvc_remove(struct rsnd_priv *priv);
-struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
-#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC)
-#define rsnd_parse_connect_dvc(rdai, playback, capture)                        \
-       rsnd_parse_connect_common(rdai, "dvc", rsnd_dvc_mod_get,        \
-                                 rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \
-                                                  playback, capture)
-
-/*
- *     R-Car CMD
- */
-int rsnd_cmd_probe(struct rsnd_priv *priv);
-void rsnd_cmd_remove(struct rsnd_priv *priv);
-int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
-
-void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
-
-/*
- * If you don't need interrupt status debug message,
- * define RSND_DEBUG_NO_IRQ_STATUS as 1 on top of src.c/ssi.c
- *
- * #define RSND_DEBUG_NO_IRQ_STATUS 1
- */
-#define rsnd_print_irq_status(dev, param...) do {      \
-       if (!IS_BUILTIN(RSND_DEBUG_NO_IRQ_STATUS))      \
-               dev_info(dev, param);                   \
-} while (0)
-
-#ifdef CONFIG_DEBUG_FS
-int rsnd_debugfs_probe(struct snd_soc_component *component);
-void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr,
-                          void __iomem *base, int offset, int size);
-void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod,
-                              int reg_id, int offset, int size);
-
-#else
-#define rsnd_debugfs_probe  NULL
-#endif
-
-#endif /* RSND_H */
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
deleted file mode 100644 (file)
index e7f86db..0000000
+++ /dev/null
@@ -1,732 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car SRC support
-//
-// Copyright (C) 2013 Renesas Solutions Corp.
-// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-/*
- * You can use Synchronous Sampling Rate Convert (if no DVC)
- *
- *     amixer set "SRC Out Rate" on
- *     aplay xxx.wav &
- *     amixer set "SRC Out Rate" 96000 // convert rate to 96000Hz
- *     amixer set "SRC Out Rate" 22050 // convert rate to 22050Hz
- */
-
-/*
- * you can enable below define if you don't need
- * SSI interrupt status debug message when debugging
- * see rsnd_print_irq_status()
- *
- * #define RSND_DEBUG_NO_IRQ_STATUS 1
- */
-
-#include <linux/of_irq.h>
-#include "rsnd.h"
-
-#define SRC_NAME "src"
-
-/* SCU_SYSTEM_STATUS0/1 */
-#define OUF_SRC(id)    ((1 << (id + 16)) | (1 << id))
-
-struct rsnd_src {
-       struct rsnd_mod mod;
-       struct rsnd_mod *dma;
-       struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */
-       struct rsnd_kctrl_cfg_s sync; /* sync convert */
-       int irq;
-};
-
-#define RSND_SRC_NAME_SIZE 16
-
-#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)
-#define rsnd_src_nr(priv) ((priv)->src_nr)
-#define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val)
-
-#define rsnd_mod_to_src(_mod)                          \
-       container_of((_mod), struct rsnd_src, mod)
-
-#define for_each_rsnd_src(pos, priv, i)                                \
-       for ((i) = 0;                                           \
-            ((i) < rsnd_src_nr(priv)) &&                       \
-            ((pos) = (struct rsnd_src *)(priv)->src + i);      \
-            i++)
-
-
-/*
- *             image of SRC (Sampling Rate Converter)
- *
- * 96kHz   <-> +-----+ 48kHz   +-----+  48kHz  +-------+
- * 48kHz   <-> | SRC | <------>        | SSI | <-----> | codec |
- * 44.1kHz <-> +-----+         +-----+         +-------+
- * ...
- *
- */
-
-static void rsnd_src_activation(struct rsnd_mod *mod)
-{
-       rsnd_mod_write(mod, SRC_SWRSR, 0);
-       rsnd_mod_write(mod, SRC_SWRSR, 1);
-}
-
-static void rsnd_src_halt(struct rsnd_mod *mod)
-{
-       rsnd_mod_write(mod, SRC_SRCIR, 1);
-       rsnd_mod_write(mod, SRC_SWRSR, 0);
-}
-
-static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
-                                        struct rsnd_mod *mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       int is_play = rsnd_io_is_play(io);
-
-       return rsnd_dma_request_channel(rsnd_src_of_node(priv),
-                                       SRC_NAME, mod,
-                                       is_play ? "rx" : "tx");
-}
-
-static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
-                                struct rsnd_mod *mod)
-{
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 convert_rate;
-
-       if (!runtime)
-               return 0;
-
-       if (!rsnd_src_sync_is_enabled(mod))
-               return rsnd_io_converted_rate(io);
-
-       convert_rate = src->sync.val;
-
-       if (!convert_rate)
-               convert_rate = rsnd_io_converted_rate(io);
-
-       if (!convert_rate)
-               convert_rate = runtime->rate;
-
-       return convert_rate;
-}
-
-unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,
-                              struct rsnd_dai_stream *io,
-                              int is_in)
-{
-       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       unsigned int rate = 0;
-       int is_play = rsnd_io_is_play(io);
-
-       /*
-        * Playback
-        * runtime_rate -> [SRC] -> convert_rate
-        *
-        * Capture
-        * convert_rate -> [SRC] -> runtime_rate
-        */
-
-       if (is_play == is_in)
-               return runtime->rate;
-
-       /*
-        * return convert rate if SRC is used,
-        * otherwise, return runtime->rate as usual
-        */
-       if (src_mod)
-               rate = rsnd_src_convert_rate(io, src_mod);
-
-       if (!rate)
-               rate = runtime->rate;
-
-       return rate;
-}
-
-static const u32 bsdsr_table_pattern1[] = {
-       0x01800000, /* 6 - 1/6 */
-       0x01000000, /* 6 - 1/4 */
-       0x00c00000, /* 6 - 1/3 */
-       0x00800000, /* 6 - 1/2 */
-       0x00600000, /* 6 - 2/3 */
-       0x00400000, /* 6 - 1   */
-};
-
-static const u32 bsdsr_table_pattern2[] = {
-       0x02400000, /* 6 - 1/6 */
-       0x01800000, /* 6 - 1/4 */
-       0x01200000, /* 6 - 1/3 */
-       0x00c00000, /* 6 - 1/2 */
-       0x00900000, /* 6 - 2/3 */
-       0x00600000, /* 6 - 1   */
-};
-
-static const u32 bsisr_table[] = {
-       0x00100060, /* 6 - 1/6 */
-       0x00100040, /* 6 - 1/4 */
-       0x00100030, /* 6 - 1/3 */
-       0x00100020, /* 6 - 1/2 */
-       0x00100020, /* 6 - 2/3 */
-       0x00100020, /* 6 - 1   */
-};
-
-static const u32 chan288888[] = {
-       0x00000006, /* 1 to 2 */
-       0x000001fe, /* 1 to 8 */
-       0x000001fe, /* 1 to 8 */
-       0x000001fe, /* 1 to 8 */
-       0x000001fe, /* 1 to 8 */
-       0x000001fe, /* 1 to 8 */
-};
-
-static const u32 chan244888[] = {
-       0x00000006, /* 1 to 2 */
-       0x0000001e, /* 1 to 4 */
-       0x0000001e, /* 1 to 4 */
-       0x000001fe, /* 1 to 8 */
-       0x000001fe, /* 1 to 8 */
-       0x000001fe, /* 1 to 8 */
-};
-
-static const u32 chan222222[] = {
-       0x00000006, /* 1 to 2 */
-       0x00000006, /* 1 to 2 */
-       0x00000006, /* 1 to 2 */
-       0x00000006, /* 1 to 2 */
-       0x00000006, /* 1 to 2 */
-       0x00000006, /* 1 to 2 */
-};
-
-static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
-                                     struct rsnd_mod *mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       int is_play = rsnd_io_is_play(io);
-       int use_src = 0;
-       u32 fin, fout;
-       u32 ifscr, fsrate, adinr;
-       u32 cr, route;
-       u32 i_busif, o_busif, tmp;
-       const u32 *bsdsr_table;
-       const u32 *chptn;
-       uint ratio;
-       int chan;
-       int idx;
-
-       if (!runtime)
-               return;
-
-       fin  = rsnd_src_get_in_rate(priv, io);
-       fout = rsnd_src_get_out_rate(priv, io);
-
-       chan = rsnd_runtime_channel_original(io);
-
-       /* 6 - 1/6 are very enough ratio for SRC_BSDSR */
-       if (fin == fout)
-               ratio = 0;
-       else if (fin > fout)
-               ratio = 100 * fin / fout;
-       else
-               ratio = 100 * fout / fin;
-
-       if (ratio > 600) {
-               dev_err(dev, "FSO/FSI ratio error\n");
-               return;
-       }
-
-       use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod);
-
-       /*
-        * SRC_ADINR
-        */
-       adinr = rsnd_get_adinr_bit(mod, io) | chan;
-
-       /*
-        * SRC_IFSCR / SRC_IFSVR
-        */
-       ifscr = 0;
-       fsrate = 0;
-       if (use_src) {
-               u64 n;
-
-               ifscr = 1;
-               n = (u64)0x0400000 * fin;
-               do_div(n, fout);
-               fsrate = n;
-       }
-
-       /*
-        * SRC_SRCCR / SRC_ROUTE_MODE0
-        */
-       cr      = 0x00011110;
-       route   = 0x0;
-       if (use_src) {
-               route   = 0x1;
-
-               if (rsnd_src_sync_is_enabled(mod)) {
-                       cr |= 0x1;
-                       route |= rsnd_io_is_play(io) ?
-                               (0x1 << 24) : (0x1 << 25);
-               }
-       }
-
-       /*
-        * SRC_BSDSR / SRC_BSISR
-        *
-        * see
-        *      Combination of Register Setting Related to
-        *      FSO/FSI Ratio and Channel, Latency
-        */
-       switch (rsnd_mod_id(mod)) {
-       case 0:
-               chptn           = chan288888;
-               bsdsr_table     = bsdsr_table_pattern1;
-               break;
-       case 1:
-       case 3:
-       case 4:
-               chptn           = chan244888;
-               bsdsr_table     = bsdsr_table_pattern1;
-               break;
-       case 2:
-       case 9:
-               chptn           = chan222222;
-               bsdsr_table     = bsdsr_table_pattern1;
-               break;
-       case 5:
-       case 6:
-       case 7:
-       case 8:
-               chptn           = chan222222;
-               bsdsr_table     = bsdsr_table_pattern2;
-               break;
-       default:
-               goto convert_rate_err;
-       }
-
-       /*
-        * E3 need to overwrite
-        */
-       if (rsnd_is_gen3_e3(priv))
-               switch (rsnd_mod_id(mod)) {
-               case 0:
-               case 4:
-                       chptn   = chan222222;
-               }
-
-       for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++)
-               if (chptn[idx] & (1 << chan))
-                       break;
-
-       if (chan > 8 ||
-           idx >= ARRAY_SIZE(chan222222))
-               goto convert_rate_err;
-
-       /* BUSIF_MODE */
-       tmp = rsnd_get_busif_shift(io, mod);
-       i_busif = ( is_play ? tmp : 0) | 1;
-       o_busif = (!is_play ? tmp : 0) | 1;
-
-       rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);
-
-       rsnd_mod_write(mod, SRC_SRCIR, 1);      /* initialize */
-       rsnd_mod_write(mod, SRC_ADINR, adinr);
-       rsnd_mod_write(mod, SRC_IFSCR, ifscr);
-       rsnd_mod_write(mod, SRC_IFSVR, fsrate);
-       rsnd_mod_write(mod, SRC_SRCCR, cr);
-       rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]);
-       rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]);
-       rsnd_mod_write(mod, SRC_SRCIR, 0);      /* cancel initialize */
-
-       rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif);
-       rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif);
-
-       rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
-
-       rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
-
-       return;
-
-convert_rate_err:
-       dev_err(dev, "unknown BSDSR/BSDIR settings\n");
-}
-
-static int rsnd_src_irq(struct rsnd_mod *mod,
-                       struct rsnd_dai_stream *io,
-                       struct rsnd_priv *priv,
-                       int enable)
-{
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 sys_int_val, int_val, sys_int_mask;
-       int irq = src->irq;
-       int id = rsnd_mod_id(mod);
-
-       sys_int_val =
-       sys_int_mask = OUF_SRC(id);
-       int_val = 0x3300;
-
-       /*
-        * IRQ is not supported on non-DT
-        * see
-        *      rsnd_src_probe_()
-        */
-       if ((irq <= 0) || !enable) {
-               sys_int_val = 0;
-               int_val = 0;
-       }
-
-       /*
-        * WORKAROUND
-        *
-        * ignore over flow error when rsnd_src_sync_is_enabled()
-        */
-       if (rsnd_src_sync_is_enabled(mod))
-               sys_int_val = sys_int_val & 0xffff;
-
-       rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
-       rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
-       rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
-
-       return 0;
-}
-
-static void rsnd_src_status_clear(struct rsnd_mod *mod)
-{
-       u32 val = OUF_SRC(rsnd_mod_id(mod));
-
-       rsnd_mod_write(mod, SCU_SYS_STATUS0, val);
-       rsnd_mod_write(mod, SCU_SYS_STATUS1, val);
-}
-
-static bool rsnd_src_error_occurred(struct rsnd_mod *mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       u32 val0, val1;
-       u32 status0, status1;
-       bool ret = false;
-
-       val0 = val1 = OUF_SRC(rsnd_mod_id(mod));
-
-       /*
-        * WORKAROUND
-        *
-        * ignore over flow error when rsnd_src_sync_is_enabled()
-        */
-       if (rsnd_src_sync_is_enabled(mod))
-               val0 = val0 & 0xffff;
-
-       status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0);
-       status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1);
-       if ((status0 & val0) || (status1 & val1)) {
-               rsnd_print_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n",
-                                     rsnd_mod_name(mod), status0, status1);
-
-               ret = true;
-       }
-
-       return ret;
-}
-
-static int rsnd_src_start(struct rsnd_mod *mod,
-                         struct rsnd_dai_stream *io,
-                         struct rsnd_priv *priv)
-{
-       u32 val;
-
-       /*
-        * WORKAROUND
-        *
-        * Enable SRC output if you want to use sync convert together with DVC
-        */
-       val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ?
-               0x01 : 0x11;
-
-       rsnd_mod_write(mod, SRC_CTRL, val);
-
-       return 0;
-}
-
-static int rsnd_src_stop(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       rsnd_mod_write(mod, SRC_CTRL, 0);
-
-       return 0;
-}
-
-static int rsnd_src_init(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       int ret;
-
-       /* reset sync convert_rate */
-       src->sync.val = 0;
-
-       ret = rsnd_mod_power_on(mod);
-       if (ret < 0)
-               return ret;
-
-       rsnd_src_activation(mod);
-
-       rsnd_src_set_convert_rate(io, mod);
-
-       rsnd_src_status_clear(mod);
-
-       return 0;
-}
-
-static int rsnd_src_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-
-       rsnd_src_halt(mod);
-
-       rsnd_mod_power_off(mod);
-
-       /* reset sync convert_rate */
-       src->sync.val = 0;
-
-       return 0;
-}
-
-static void __rsnd_src_interrupt(struct rsnd_mod *mod,
-                                struct rsnd_dai_stream *io)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       bool stop = false;
-
-       spin_lock(&priv->lock);
-
-       /* ignore all cases if not working */
-       if (!rsnd_io_is_working(io))
-               goto rsnd_src_interrupt_out;
-
-       if (rsnd_src_error_occurred(mod))
-               stop = true;
-
-       rsnd_src_status_clear(mod);
-rsnd_src_interrupt_out:
-
-       spin_unlock(&priv->lock);
-
-       if (stop)
-               snd_pcm_stop_xrun(io->substream);
-}
-
-static irqreturn_t rsnd_src_interrupt(int irq, void *data)
-{
-       struct rsnd_mod *mod = data;
-
-       rsnd_mod_interrupt(mod, __rsnd_src_interrupt);
-
-       return IRQ_HANDLED;
-}
-
-static int rsnd_src_probe_(struct rsnd_mod *mod,
-                          struct rsnd_dai_stream *io,
-                          struct rsnd_priv *priv)
-{
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int irq = src->irq;
-       int ret;
-
-       if (irq > 0) {
-               /*
-                * IRQ is not supported on non-DT
-                * see
-                *      rsnd_src_irq()
-                */
-               ret = devm_request_irq(dev, irq,
-                                      rsnd_src_interrupt,
-                                      IRQF_SHARED,
-                                      dev_name(dev), mod);
-               if (ret)
-                       return ret;
-       }
-
-       ret = rsnd_dma_attach(io, mod, &src->dma);
-
-       return ret;
-}
-
-static int rsnd_src_pcm_new(struct rsnd_mod *mod,
-                           struct rsnd_dai_stream *io,
-                           struct snd_soc_pcm_runtime *rtd)
-{
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       int ret;
-
-       /*
-        * enable SRC sync convert if possible
-        */
-
-       /*
-        * It can't use SRC Synchronous convert
-        * when Capture if it uses CMD
-        */
-       if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io))
-               return 0;
-
-       /*
-        * enable sync convert
-        */
-       ret = rsnd_kctrl_new_s(mod, io, rtd,
-                              rsnd_io_is_play(io) ?
-                              "SRC Out Rate Switch" :
-                              "SRC In Rate Switch",
-                              rsnd_kctrl_accept_anytime,
-                              rsnd_src_set_convert_rate,
-                              &src->sen, 1);
-       if (ret < 0)
-               return ret;
-
-       ret = rsnd_kctrl_new_s(mod, io, rtd,
-                              rsnd_io_is_play(io) ?
-                              "SRC Out Rate" :
-                              "SRC In Rate",
-                              rsnd_kctrl_accept_runtime,
-                              rsnd_src_set_convert_rate,
-                              &src->sync, 192000);
-
-       return ret;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void rsnd_src_debug_info(struct seq_file *m,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_mod *mod)
-{
-       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
-                                 rsnd_mod_id(mod) * 0x20, 0x20);
-       seq_puts(m, "\n");
-       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
-                                 0x1c0, 0x20);
-       seq_puts(m, "\n");
-       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,
-                                 0x200 + rsnd_mod_id(mod) * 0x40, 0x40);
-}
-#define DEBUG_INFO .debug_info = rsnd_src_debug_info
-#else
-#define DEBUG_INFO
-#endif
-
-static struct rsnd_mod_ops rsnd_src_ops = {
-       .name           = SRC_NAME,
-       .dma_req        = rsnd_src_dma_req,
-       .probe          = rsnd_src_probe_,
-       .init           = rsnd_src_init,
-       .quit           = rsnd_src_quit,
-       .start          = rsnd_src_start,
-       .stop           = rsnd_src_stop,
-       .irq            = rsnd_src_irq,
-       .pcm_new        = rsnd_src_pcm_new,
-       .get_status     = rsnd_mod_get_status,
-       DEBUG_INFO
-};
-
-struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)
-{
-       if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))
-               id = 0;
-
-       return rsnd_mod_get(rsnd_src_get(priv, id));
-}
-
-int rsnd_src_probe(struct rsnd_priv *priv)
-{
-       struct device_node *node;
-       struct device_node *np;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_src *src;
-       struct clk *clk;
-       char name[RSND_SRC_NAME_SIZE];
-       int i, nr, ret;
-
-       node = rsnd_src_of_node(priv);
-       if (!node)
-               return 0; /* not used is not error */
-
-       nr = rsnd_node_count(priv, node, SRC_NAME);
-       if (!nr) {
-               ret = -EINVAL;
-               goto rsnd_src_probe_done;
-       }
-
-       src     = devm_kcalloc(dev, nr, sizeof(*src), GFP_KERNEL);
-       if (!src) {
-               ret = -ENOMEM;
-               goto rsnd_src_probe_done;
-       }
-
-       priv->src_nr    = nr;
-       priv->src       = src;
-
-       i = 0;
-       for_each_child_of_node(node, np) {
-               if (!of_device_is_available(np))
-                       goto skip;
-
-               i = rsnd_node_fixed_index(dev, np, SRC_NAME, i);
-               if (i < 0) {
-                       ret = -EINVAL;
-                       of_node_put(np);
-                       goto rsnd_src_probe_done;
-               }
-
-               src = rsnd_src_get(priv, i);
-
-               snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",
-                        SRC_NAME, i);
-
-               src->irq = irq_of_parse_and_map(np, 0);
-               if (!src->irq) {
-                       ret = -EINVAL;
-                       of_node_put(np);
-                       goto rsnd_src_probe_done;
-               }
-
-               clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk)) {
-                       ret = PTR_ERR(clk);
-                       of_node_put(np);
-                       goto rsnd_src_probe_done;
-               }
-
-               ret = rsnd_mod_init(priv, rsnd_mod_get(src),
-                                   &rsnd_src_ops, clk, RSND_MOD_SRC, i);
-               if (ret) {
-                       of_node_put(np);
-                       goto rsnd_src_probe_done;
-               }
-
-skip:
-               i++;
-       }
-
-       ret = 0;
-
-rsnd_src_probe_done:
-       of_node_put(node);
-
-       return ret;
-}
-
-void rsnd_src_remove(struct rsnd_priv *priv)
-{
-       struct rsnd_src *src;
-       int i;
-
-       for_each_rsnd_src(src, priv, i) {
-               rsnd_mod_quit(rsnd_mod_get(src));
-       }
-}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
deleted file mode 100644 (file)
index b3d4e8a..0000000
+++ /dev/null
@@ -1,1260 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car SSIU/SSI support
-//
-// Copyright (C) 2013 Renesas Solutions Corp.
-// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-//
-// Based on fsi.c
-// Kuninori Morimoto <morimoto.kuninori@renesas.com>
-
-/*
- * you can enable below define if you don't need
- * SSI interrupt status debug message when debugging
- * see rsnd_print_irq_status()
- *
- * #define RSND_DEBUG_NO_IRQ_STATUS 1
- */
-
-#include <sound/simple_card_utils.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/delay.h>
-#include "rsnd.h"
-#define RSND_SSI_NAME_SIZE 16
-
-/*
- * SSICR
- */
-#define        FORCE           (1u << 31)      /* Fixed */
-#define        DMEN            (1u << 28)      /* DMA Enable */
-#define        UIEN            (1u << 27)      /* Underflow Interrupt Enable */
-#define        OIEN            (1u << 26)      /* Overflow Interrupt Enable */
-#define        IIEN            (1u << 25)      /* Idle Mode Interrupt Enable */
-#define        DIEN            (1u << 24)      /* Data Interrupt Enable */
-#define        CHNL_4          (1u << 22)      /* Channels */
-#define        CHNL_6          (2u << 22)      /* Channels */
-#define        CHNL_8          (3u << 22)      /* Channels */
-#define DWL_MASK       (7u << 19)      /* Data Word Length mask */
-#define        DWL_8           (0u << 19)      /* Data Word Length */
-#define        DWL_16          (1u << 19)      /* Data Word Length */
-#define        DWL_18          (2u << 19)      /* Data Word Length */
-#define        DWL_20          (3u << 19)      /* Data Word Length */
-#define        DWL_22          (4u << 19)      /* Data Word Length */
-#define        DWL_24          (5u << 19)      /* Data Word Length */
-#define        DWL_32          (6u << 19)      /* Data Word Length */
-
-/*
- * System word length
- */
-#define        SWL_16          (1 << 16)       /* R/W System Word Length */
-#define        SWL_24          (2 << 16)       /* R/W System Word Length */
-#define        SWL_32          (3 << 16)       /* R/W System Word Length */
-
-#define        SCKD            (1 << 15)       /* Serial Bit Clock Direction */
-#define        SWSD            (1 << 14)       /* Serial WS Direction */
-#define        SCKP            (1 << 13)       /* Serial Bit Clock Polarity */
-#define        SWSP            (1 << 12)       /* Serial WS Polarity */
-#define        SDTA            (1 << 10)       /* Serial Data Alignment */
-#define        PDTA            (1 <<  9)       /* Parallel Data Alignment */
-#define        DEL             (1 <<  8)       /* Serial Data Delay */
-#define        CKDV(v)         (v <<  4)       /* Serial Clock Division Ratio */
-#define        TRMD            (1 <<  1)       /* Transmit/Receive Mode Select */
-#define        EN              (1 <<  0)       /* SSI Module Enable */
-
-/*
- * SSISR
- */
-#define        UIRQ            (1 << 27)       /* Underflow Error Interrupt Status */
-#define        OIRQ            (1 << 26)       /* Overflow Error Interrupt Status */
-#define        IIRQ            (1 << 25)       /* Idle Mode Interrupt Status */
-#define        DIRQ            (1 << 24)       /* Data Interrupt Status Flag */
-
-/*
- * SSIWSR
- */
-#define CONT           (1 << 8)        /* WS Continue Function */
-#define WS_MODE                (1 << 0)        /* WS Mode */
-
-#define SSI_NAME "ssi"
-
-struct rsnd_ssi {
-       struct rsnd_mod mod;
-
-       u32 flags;
-       u32 cr_own;
-       u32 cr_clk;
-       u32 cr_mode;
-       u32 cr_en;
-       u32 wsr;
-       int chan;
-       int rate;
-       int irq;
-       unsigned int usrcnt;
-
-       /* for PIO */
-       int byte_pos;
-       int byte_per_period;
-       int next_period_byte;
-};
-
-/* flags */
-#define RSND_SSI_CLK_PIN_SHARE         (1 << 0)
-#define RSND_SSI_NO_BUSIF              (1 << 1) /* SSI+DMA without BUSIF */
-#define RSND_SSI_PROBED                        (1 << 2)
-
-#define for_each_rsnd_ssi(pos, priv, i)                                        \
-       for (i = 0;                                                     \
-            (i < rsnd_ssi_nr(priv)) &&                                 \
-               ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i));         \
-            i++)
-
-#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
-#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
-#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
-#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
-#define rsnd_ssi_is_multi_secondary(mod, io)                           \
-       (rsnd_ssi_multi_secondaries(io) & (1 << rsnd_mod_id(mod)))
-#define rsnd_ssi_is_run_mods(mod, io) \
-       (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
-#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
-
-int rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
-{
-       struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       int use_busif = 0;
-
-       if (!rsnd_ssi_is_dma_mode(mod))
-               return 0;
-
-       if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF)))
-               use_busif = 1;
-       if (rsnd_io_to_mod_src(io))
-               use_busif = 1;
-
-       return use_busif;
-}
-
-static void rsnd_ssi_status_clear(struct rsnd_mod *mod)
-{
-       rsnd_mod_write(mod, SSISR, 0);
-}
-
-static u32 rsnd_ssi_status_get(struct rsnd_mod *mod)
-{
-       return rsnd_mod_read(mod, SSISR);
-}
-
-static void rsnd_ssi_status_check(struct rsnd_mod *mod,
-                                 u32 bit)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       u32 status;
-       int i;
-
-       for (i = 0; i < 1024; i++) {
-               status = rsnd_ssi_status_get(mod);
-               if (status & bit)
-                       return;
-
-               udelay(5);
-       }
-
-       dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod));
-}
-
-static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io)
-{
-       static const enum rsnd_mod_type types[] = {
-               RSND_MOD_SSIM1,
-               RSND_MOD_SSIM2,
-               RSND_MOD_SSIM3,
-       };
-       int i, mask;
-
-       mask = 0;
-       for (i = 0; i < ARRAY_SIZE(types); i++) {
-               struct rsnd_mod *mod = rsnd_io_to_mod(io, types[i]);
-
-               if (!mod)
-                       continue;
-
-               mask |= 1 << rsnd_mod_id(mod);
-       }
-
-       return mask;
-}
-
-static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
-{
-       struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
-       struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
-       u32 mods;
-
-       mods = rsnd_ssi_multi_secondaries_runtime(io) |
-               1 << rsnd_mod_id(ssi_mod);
-
-       if (ssi_parent_mod)
-               mods |= 1 << rsnd_mod_id(ssi_parent_mod);
-
-       return mods;
-}
-
-u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io)
-{
-       if (rsnd_runtime_is_multi_ssi(io))
-               return rsnd_ssi_multi_secondaries(io);
-
-       return 0;
-}
-
-static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai)
-{
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int width = rsnd_rdai_width_get(rdai);
-
-       switch (width) {
-       case 32: return SWL_32;
-       case 24: return SWL_24;
-       case 16: return SWL_16;
-       }
-
-       dev_err(dev, "unsupported slot width value: %d\n", width);
-       return 0;
-}
-
-unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
-                      int param1, int param2, int *idx)
-{
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       static const int ssi_clk_mul_table[] = {
-               1, 2, 4, 8, 16, 6, 12,
-       };
-       int j, ret;
-       unsigned int main_rate;
-       int width = rsnd_rdai_width_get(rdai);
-
-       for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
-
-               /*
-                * It will set SSIWSR.CONT here, but SSICR.CKDV = 000
-                * with it is not allowed. (SSIWSR.WS_MODE with
-                * SSICR.CKDV = 000 is not allowed either).
-                * Skip it. See SSICR.CKDV
-                */
-               if (j == 0)
-                       continue;
-
-               main_rate = width * param1 * param2 * ssi_clk_mul_table[j];
-
-               ret = rsnd_adg_clk_query(priv, main_rate);
-               if (ret < 0)
-                       continue;
-
-               if (idx)
-                       *idx = j;
-
-               return main_rate;
-       }
-
-       return 0;
-}
-
-static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
-                                    struct rsnd_dai_stream *io)
-{
-       struct rsnd_priv *priv = rsnd_io_to_priv(io);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       int chan = rsnd_runtime_channel_for_ssi(io);
-       int idx, ret;
-       unsigned int main_rate;
-       unsigned int rate = rsnd_io_is_play(io) ?
-               rsnd_src_get_out_rate(priv, io) :
-               rsnd_src_get_in_rate(priv, io);
-
-       if (!rsnd_rdai_is_clk_master(rdai))
-               return 0;
-
-       if (!rsnd_ssi_can_output_clk(mod))
-               return 0;
-
-       if (rsnd_ssi_is_multi_secondary(mod, io))
-               return 0;
-
-       if (rsnd_runtime_is_tdm_split(io))
-               chan = rsnd_io_converted_chan(io);
-
-       chan = rsnd_channel_normalization(chan);
-
-       if (ssi->usrcnt > 0) {
-               if (ssi->rate != rate) {
-                       dev_err(dev, "SSI parent/child should use same rate\n");
-                       return -EINVAL;
-               }
-
-               if (ssi->chan != chan) {
-                       dev_err(dev, "SSI parent/child should use same chan\n");
-                       return -EINVAL;
-               }
-
-               return 0;
-       }
-
-       ret = -EIO;
-       main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
-       if (!main_rate)
-               goto rate_err;
-
-       ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
-       if (ret < 0)
-               goto rate_err;
-
-       /*
-        * SSI clock will be output contiguously
-        * by below settings.
-        * This means, rsnd_ssi_master_clk_start()
-        * and rsnd_ssi_register_setup() are necessary
-        * for SSI parent
-        *
-        * SSICR  : FORCE, SCKD, SWSD
-        * SSIWSR : CONT
-        */
-       ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) |
-                       SCKD | SWSD | CKDV(idx);
-       ssi->wsr = CONT;
-       ssi->rate = rate;
-       ssi->chan = chan;
-
-       dev_dbg(dev, "%s outputs %d chan %u Hz\n",
-               rsnd_mod_name(mod), chan, rate);
-
-       return 0;
-
-rate_err:
-       dev_err(dev, "unsupported clock rate\n");
-       return ret;
-}
-
-static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
-                                    struct rsnd_dai_stream *io)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
-       if (!rsnd_rdai_is_clk_master(rdai))
-               return;
-
-       if (!rsnd_ssi_can_output_clk(mod))
-               return;
-
-       if (ssi->usrcnt > 1)
-               return;
-
-       ssi->cr_clk     = 0;
-       ssi->rate       = 0;
-       ssi->chan       = 0;
-
-       rsnd_adg_ssi_clk_stop(mod);
-}
-
-static void rsnd_ssi_config_init(struct rsnd_mod *mod,
-                               struct rsnd_dai_stream *io)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       u32 cr_own      = ssi->cr_own;
-       u32 cr_mode     = ssi->cr_mode;
-       u32 wsr         = ssi->wsr;
-       int width;
-       int is_tdm, is_tdm_split;
-
-       is_tdm          = rsnd_runtime_is_tdm(io);
-       is_tdm_split    = rsnd_runtime_is_tdm_split(io);
-
-       if (is_tdm)
-               dev_dbg(dev, "TDM mode\n");
-       if (is_tdm_split)
-               dev_dbg(dev, "TDM Split mode\n");
-
-       cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
-
-       if (rdai->bit_clk_inv)
-               cr_own |= SCKP;
-       if (rdai->frm_clk_inv && !is_tdm)
-               cr_own |= SWSP;
-       if (rdai->data_alignment)
-               cr_own |= SDTA;
-       if (rdai->sys_delay)
-               cr_own |= DEL;
-
-       /*
-        * TDM Mode
-        * see
-        *      rsnd_ssiu_init_gen2()
-        */
-       if (is_tdm || is_tdm_split) {
-               wsr     |= WS_MODE;
-               cr_own  |= CHNL_8;
-       }
-
-       /*
-        * We shouldn't exchange SWSP after running.
-        * This means, parent needs to care it.
-        */
-       if (rsnd_ssi_is_parent(mod, io))
-               goto init_end;
-
-       if (rsnd_io_is_play(io))
-               cr_own |= TRMD;
-
-       cr_own &= ~DWL_MASK;
-       width = snd_pcm_format_width(runtime->format);
-       if (is_tdm_split) {
-               /*
-                * The SWL and DWL bits in SSICR should be fixed at 32-bit
-                * setting when TDM split mode.
-                * see datasheet
-                *      Operation :: TDM Format Split Function (TDM Split Mode)
-                */
-               width = 32;
-       }
-
-       switch (width) {
-       case 8:
-               cr_own |= DWL_8;
-               break;
-       case 16:
-               cr_own |= DWL_16;
-               break;
-       case 24:
-               cr_own |= DWL_24;
-               break;
-       case 32:
-               cr_own |= DWL_32;
-               break;
-       }
-
-       if (rsnd_ssi_is_dma_mode(mod)) {
-               cr_mode = UIEN | OIEN | /* over/under run */
-                         DMEN;         /* DMA : enable DMA */
-       } else {
-               cr_mode = DIEN;         /* PIO : enable Data interrupt */
-       }
-
-init_end:
-       ssi->cr_own     = cr_own;
-       ssi->cr_mode    = cr_mode;
-       ssi->wsr        = wsr;
-}
-
-static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
-       rsnd_mod_write(mod, SSIWSR,     ssi->wsr);
-       rsnd_mod_write(mod, SSICR,      ssi->cr_own     |
-                                       ssi->cr_clk     |
-                                       ssi->cr_mode    |
-                                       ssi->cr_en);
-}
-
-/*
- *     SSI mod common functions
- */
-static int rsnd_ssi_init(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       int ret;
-
-       if (!rsnd_ssi_is_run_mods(mod, io))
-               return 0;
-
-       ret = rsnd_ssi_master_clk_start(mod, io);
-       if (ret < 0)
-               return ret;
-
-       ssi->usrcnt++;
-
-       ret = rsnd_mod_power_on(mod);
-       if (ret < 0)
-               return ret;
-
-       rsnd_ssi_config_init(mod, io);
-
-       rsnd_ssi_register_setup(mod);
-
-       /* clear error status */
-       rsnd_ssi_status_clear(mod);
-
-       return 0;
-}
-
-static int rsnd_ssi_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       if (!rsnd_ssi_is_run_mods(mod, io))
-               return 0;
-
-       if (!ssi->usrcnt) {
-               dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod));
-               return -EIO;
-       }
-
-       rsnd_ssi_master_clk_stop(mod, io);
-
-       rsnd_mod_power_off(mod);
-
-       ssi->usrcnt--;
-
-       if (!ssi->usrcnt) {
-               ssi->cr_own     = 0;
-               ssi->cr_mode    = 0;
-               ssi->wsr        = 0;
-       }
-
-       return 0;
-}
-
-static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       unsigned int fmt_width = snd_pcm_format_width(params_format(params));
-
-       if (fmt_width > rdai->chan_width) {
-               struct rsnd_priv *priv = rsnd_io_to_priv(io);
-               struct device *dev = rsnd_priv_to_dev(priv);
-
-               dev_err(dev, "invalid combination of slot-width and format-data-width\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int rsnd_ssi_start(struct rsnd_mod *mod,
-                         struct rsnd_dai_stream *io,
-                         struct rsnd_priv *priv)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
-       if (!rsnd_ssi_is_run_mods(mod, io))
-               return 0;
-
-       /*
-        * EN will be set via SSIU :: SSI_CONTROL
-        * if Multi channel mode
-        */
-       if (rsnd_ssi_multi_secondaries_runtime(io))
-               return 0;
-
-       /*
-        * EN is for data output.
-        * SSI parent EN is not needed.
-        */
-       if (rsnd_ssi_is_parent(mod, io))
-               return 0;
-
-       ssi->cr_en = EN;
-
-       rsnd_mod_write(mod, SSICR,      ssi->cr_own     |
-                                       ssi->cr_clk     |
-                                       ssi->cr_mode    |
-                                       ssi->cr_en);
-
-       return 0;
-}
-
-static int rsnd_ssi_stop(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       u32 cr;
-
-       if (!rsnd_ssi_is_run_mods(mod, io))
-               return 0;
-
-       if (rsnd_ssi_is_parent(mod, io))
-               return 0;
-
-       cr  =   ssi->cr_own     |
-               ssi->cr_clk;
-
-       /*
-        * disable all IRQ,
-        * Playback: Wait all data was sent
-        * Capture:  It might not receave data. Do nothing
-        */
-       if (rsnd_io_is_play(io)) {
-               rsnd_mod_write(mod, SSICR, cr | ssi->cr_en);
-               rsnd_ssi_status_check(mod, DIRQ);
-       }
-
-       /* In multi-SSI mode, stop is performed by setting ssi0129 in
-        * SSI_CONTROL to 0 (in rsnd_ssio_stop_gen2). Do nothing here.
-        */
-       if (rsnd_ssi_multi_secondaries_runtime(io))
-               return 0;
-
-       /*
-        * disable SSI,
-        * and, wait idle state
-        */
-       rsnd_mod_write(mod, SSICR, cr); /* disabled all */
-       rsnd_ssi_status_check(mod, IIRQ);
-
-       ssi->cr_en = 0;
-
-       return 0;
-}
-
-static int rsnd_ssi_irq(struct rsnd_mod *mod,
-                       struct rsnd_dai_stream *io,
-                       struct rsnd_priv *priv,
-                       int enable)
-{
-       u32 val = 0;
-       int is_tdm, is_tdm_split;
-       int id = rsnd_mod_id(mod);
-
-       is_tdm          = rsnd_runtime_is_tdm(io);
-       is_tdm_split    = rsnd_runtime_is_tdm_split(io);
-
-       if (rsnd_is_gen1(priv))
-               return 0;
-
-       if (rsnd_ssi_is_parent(mod, io))
-               return 0;
-
-       if (!rsnd_ssi_is_run_mods(mod, io))
-               return 0;
-
-       if (enable)
-               val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000;
-
-       if (is_tdm || is_tdm_split) {
-               switch (id) {
-               case 0:
-               case 1:
-               case 2:
-               case 3:
-               case 4:
-               case 9:
-                       val |= 0x0000ff00;
-                       break;
-               }
-       }
-
-       rsnd_mod_write(mod, SSI_INT_ENABLE, val);
-
-       return 0;
-}
-
-static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
-                                  struct rsnd_dai_stream *io);
-static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
-                                struct rsnd_dai_stream *io)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int is_dma = rsnd_ssi_is_dma_mode(mod);
-       u32 status;
-       bool elapsed = false;
-       bool stop = false;
-
-       spin_lock(&priv->lock);
-
-       /* ignore all cases if not working */
-       if (!rsnd_io_is_working(io))
-               goto rsnd_ssi_interrupt_out;
-
-       status = rsnd_ssi_status_get(mod);
-
-       /* PIO only */
-       if (!is_dma && (status & DIRQ))
-               elapsed = rsnd_ssi_pio_interrupt(mod, io);
-
-       /* DMA only */
-       if (is_dma && (status & (UIRQ | OIRQ))) {
-               rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
-                                     rsnd_mod_name(mod), status);
-
-               stop = true;
-       }
-
-       stop |= rsnd_ssiu_busif_err_status_clear(mod);
-
-       rsnd_ssi_status_clear(mod);
-rsnd_ssi_interrupt_out:
-       spin_unlock(&priv->lock);
-
-       if (elapsed)
-               snd_pcm_period_elapsed(io->substream);
-
-       if (stop)
-               snd_pcm_stop_xrun(io->substream);
-
-}
-
-static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
-{
-       struct rsnd_mod *mod = data;
-
-       rsnd_mod_interrupt(mod, __rsnd_ssi_interrupt);
-
-       return IRQ_HANDLED;
-}
-
-static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod,
-                               struct rsnd_dai_stream *io,
-                               enum rsnd_mod_type type)
-{
-       /*
-        * SSIP (= SSI parent) needs to be special, otherwise,
-        * 2nd SSI might doesn't start. see also rsnd_mod_call()
-        *
-        * We can't include parent SSI status on SSI, because we don't know
-        * how many SSI requests parent SSI. Thus, it is localed on "io" now.
-        * ex) trouble case
-        *      Playback: SSI0
-        *      Capture : SSI1 (needs SSI0)
-        *
-        * 1) start Capture  -> SSI0/SSI1 are started.
-        * 2) start Playback -> SSI0 doesn't work, because it is already
-        *                      marked as "started" on 1)
-        *
-        * OTOH, using each mod's status is good for MUX case.
-        * It doesn't need to start in 2nd start
-        * ex)
-        *      IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
-        *                          |
-        *      IO-1: SRC1 -> CTU2 -+
-        *
-        * 1) start IO-0 ->     start SSI0
-        * 2) start IO-1 ->     SSI0 doesn't need to start, because it is
-        *                      already started on 1)
-        */
-       if (type == RSND_MOD_SSIP)
-               return &io->parent_ssi_status;
-
-       return rsnd_mod_get_status(mod, io, type);
-}
-
-/*
- *             SSI PIO
- */
-static void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
-                                  struct rsnd_dai_stream *io)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-
-       if (!__rsnd_ssi_is_pin_sharing(mod))
-               return;
-
-       if (!rsnd_rdai_is_clk_master(rdai))
-               return;
-
-       if (rsnd_ssi_is_multi_secondary(mod, io))
-               return;
-
-       switch (rsnd_mod_id(mod)) {
-       case 1:
-       case 2:
-       case 9:
-               rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP);
-               break;
-       case 4:
-               rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP);
-               break;
-       case 8:
-               rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP);
-               break;
-       }
-}
-
-static int rsnd_ssi_pcm_new(struct rsnd_mod *mod,
-                           struct rsnd_dai_stream *io,
-                           struct snd_soc_pcm_runtime *rtd)
-{
-       /*
-        * rsnd_rdai_is_clk_master() will be enabled after set_fmt,
-        * and, pcm_new will be called after it.
-        * This function reuse pcm_new at this point.
-        */
-       rsnd_ssi_parent_attach(mod, io);
-
-       return 0;
-}
-
-static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
-                                struct rsnd_dai_stream *io,
-                                struct rsnd_priv *priv)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       int ret = 0;
-
-       /*
-        * SSIP/SSIU/IRQ are not needed on
-        * SSI Multi secondaries
-        */
-       if (rsnd_ssi_is_multi_secondary(mod, io))
-               return 0;
-
-       /*
-        * It can't judge ssi parent at this point
-        * see rsnd_ssi_pcm_new()
-        */
-
-       /*
-        * SSI might be called again as PIO fallback
-        * It is easy to manual handling for IRQ request/free
-        *
-        * OTOH, this function might be called many times if platform is
-        * using MIX. It needs xxx_attach() many times on xxx_probe().
-        * Because of it, we can't control .probe/.remove calling count by
-        * mod->status.
-        * But it don't need to call request_irq() many times.
-        * Let's control it by RSND_SSI_PROBED flag.
-        */
-       if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
-               ret = request_irq(ssi->irq,
-                                 rsnd_ssi_interrupt,
-                                 IRQF_SHARED,
-                                 dev_name(dev), mod);
-
-               rsnd_flags_set(ssi, RSND_SSI_PROBED);
-       }
-
-       return ret;
-}
-
-static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
-                                 struct rsnd_dai_stream *io,
-                                 struct rsnd_priv *priv)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io);
-
-       /* Do nothing if non SSI (= SSI parent, multi SSI) mod */
-       if (pure_ssi_mod != mod)
-               return 0;
-
-       /* PIO will request IRQ again */
-       if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
-               free_irq(ssi->irq, mod);
-
-               rsnd_flags_del(ssi, RSND_SSI_PROBED);
-       }
-
-       return 0;
-}
-
-/*
- *     SSI PIO functions
- */
-static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
-                                  struct rsnd_dai_stream *io)
-{
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos);
-       int shift = 0;
-       int byte_pos;
-       bool elapsed = false;
-
-       if (snd_pcm_format_width(runtime->format) == 24)
-               shift = 8;
-
-       /*
-        * 8/16/32 data can be assesse to TDR/RDR register
-        * directly as 32bit data
-        * see rsnd_ssi_init()
-        */
-       if (rsnd_io_is_play(io))
-               rsnd_mod_write(mod, SSITDR, (*buf) << shift);
-       else
-               *buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
-
-       byte_pos = ssi->byte_pos + sizeof(*buf);
-
-       if (byte_pos >= ssi->next_period_byte) {
-               int period_pos = byte_pos / ssi->byte_per_period;
-
-               if (period_pos >= runtime->periods) {
-                       byte_pos = 0;
-                       period_pos = 0;
-               }
-
-               ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period;
-
-               elapsed = true;
-       }
-
-       WRITE_ONCE(ssi->byte_pos, byte_pos);
-
-       return elapsed;
-}
-
-static int rsnd_ssi_pio_init(struct rsnd_mod *mod,
-                            struct rsnd_dai_stream *io,
-                            struct rsnd_priv *priv)
-{
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
-       if (!rsnd_ssi_is_parent(mod, io)) {
-               ssi->byte_pos           = 0;
-               ssi->byte_per_period    = runtime->period_size *
-                                         runtime->channels *
-                                         samples_to_bytes(runtime, 1);
-               ssi->next_period_byte   = ssi->byte_per_period;
-       }
-
-       return rsnd_ssi_init(mod, io, priv);
-}
-
-static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod,
-                           struct rsnd_dai_stream *io,
-                           snd_pcm_uframes_t *pointer)
-{
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
-
-       *pointer = bytes_to_frames(runtime, READ_ONCE(ssi->byte_pos));
-
-       return 0;
-}
-
-static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
-       .name           = SSI_NAME,
-       .probe          = rsnd_ssi_common_probe,
-       .remove         = rsnd_ssi_common_remove,
-       .init           = rsnd_ssi_pio_init,
-       .quit           = rsnd_ssi_quit,
-       .start          = rsnd_ssi_start,
-       .stop           = rsnd_ssi_stop,
-       .irq            = rsnd_ssi_irq,
-       .pointer        = rsnd_ssi_pio_pointer,
-       .pcm_new        = rsnd_ssi_pcm_new,
-       .hw_params      = rsnd_ssi_hw_params,
-       .get_status     = rsnd_ssi_get_status,
-};
-
-static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
-                             struct rsnd_dai_stream *io,
-                             struct rsnd_priv *priv)
-{
-       int ret;
-
-       /*
-        * SSIP/SSIU/IRQ/DMA are not needed on
-        * SSI Multi secondaries
-        */
-       if (rsnd_ssi_is_multi_secondary(mod, io))
-               return 0;
-
-       ret = rsnd_ssi_common_probe(mod, io, priv);
-       if (ret)
-               return ret;
-
-       /* SSI probe might be called many times in MUX multi path */
-       ret = rsnd_dma_attach(io, mod, &io->dma);
-
-       return ret;
-}
-
-static int rsnd_ssi_fallback(struct rsnd_mod *mod,
-                            struct rsnd_dai_stream *io,
-                            struct rsnd_priv *priv)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-
-       /*
-        * fallback to PIO
-        *
-        * SSI .probe might be called again.
-        * see
-        *      rsnd_rdai_continuance_probe()
-        */
-       mod->ops = &rsnd_ssi_pio_ops;
-
-       dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod));
-
-       return 0;
-}
-
-static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
-                                        struct rsnd_mod *mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       int is_play = rsnd_io_is_play(io);
-       char *name;
-
-       /*
-        * It should use "rcar_sound,ssiu" on DT.
-        * But, we need to keep compatibility for old version.
-        *
-        * If it has "rcar_sound.ssiu", it will be used.
-        * If not, "rcar_sound.ssi" will be used.
-        * see
-        *      rsnd_ssiu_dma_req()
-        *      rsnd_dma_of_path()
-        */
-
-       if (rsnd_ssi_use_busif(io))
-               name = is_play ? "rxu" : "txu";
-       else
-               name = is_play ? "rx" : "tx";
-
-       return rsnd_dma_request_channel(rsnd_ssi_of_node(priv),
-                                       SSI_NAME, mod, name);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void rsnd_ssi_debug_info(struct seq_file *m,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_mod *mod)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
-       seq_printf(m, "clock:           %s\n",          rsnd_rdai_is_clk_master(rdai) ?
-                                                               "provider" : "consumer");
-       seq_printf(m, "bit_clk_inv:     %d\n",          rdai->bit_clk_inv);
-       seq_printf(m, "frm_clk_inv:     %d\n",          rdai->frm_clk_inv);
-       seq_printf(m, "pin share:       %d\n",          __rsnd_ssi_is_pin_sharing(mod));
-       seq_printf(m, "can out clk:     %d\n",          rsnd_ssi_can_output_clk(mod));
-       seq_printf(m, "multi secondary: %d\n",          rsnd_ssi_is_multi_secondary(mod, io));
-       seq_printf(m, "tdm:             %d, %d\n",      rsnd_runtime_is_tdm(io),
-                                                       rsnd_runtime_is_tdm_split(io));
-       seq_printf(m, "chan:            %d\n",          ssi->chan);
-       seq_printf(m, "user:            %d\n",          ssi->usrcnt);
-
-       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSI,
-                                 rsnd_mod_id(mod) * 0x40, 0x40);
-}
-#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info
-#else
-#define DEBUG_INFO
-#endif
-
-static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
-       .name           = SSI_NAME,
-       .dma_req        = rsnd_ssi_dma_req,
-       .probe          = rsnd_ssi_dma_probe,
-       .remove         = rsnd_ssi_common_remove,
-       .init           = rsnd_ssi_init,
-       .quit           = rsnd_ssi_quit,
-       .start          = rsnd_ssi_start,
-       .stop           = rsnd_ssi_stop,
-       .irq            = rsnd_ssi_irq,
-       .pcm_new        = rsnd_ssi_pcm_new,
-       .fallback       = rsnd_ssi_fallback,
-       .hw_params      = rsnd_ssi_hw_params,
-       .get_status     = rsnd_ssi_get_status,
-       DEBUG_INFO
-};
-
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
-{
-       return mod->ops == &rsnd_ssi_dma_ops;
-}
-
-/*
- *             ssi mod function
- */
-static void rsnd_ssi_connect(struct rsnd_mod *mod,
-                            struct rsnd_dai_stream *io)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       static const enum rsnd_mod_type types[] = {
-               RSND_MOD_SSI,
-               RSND_MOD_SSIM1,
-               RSND_MOD_SSIM2,
-               RSND_MOD_SSIM3,
-       };
-       enum rsnd_mod_type type;
-       int i;
-
-       /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */
-       for (i = 0; i < ARRAY_SIZE(types); i++) {
-               type = types[i];
-               if (!rsnd_io_to_mod(io, type)) {
-                       rsnd_dai_connect(mod, io, type);
-                       rsnd_rdai_channels_set(rdai, (i + 1) * 2);
-                       rsnd_rdai_ssi_lane_set(rdai, (i + 1));
-                       return;
-               }
-       }
-}
-
-void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
-                           struct device_node *playback,
-                           struct device_node *capture)
-{
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *node;
-       struct device_node *np;
-       int i;
-
-       node = rsnd_ssi_of_node(priv);
-       if (!node)
-               return;
-
-       i = 0;
-       for_each_child_of_node(node, np) {
-               struct rsnd_mod *mod;
-
-               i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
-               if (i < 0) {
-                       of_node_put(np);
-                       break;
-               }
-
-               mod = rsnd_ssi_mod_get(priv, i);
-
-               if (np == playback)
-                       rsnd_ssi_connect(mod, &rdai->playback);
-               if (np == capture)
-                       rsnd_ssi_connect(mod, &rdai->capture);
-               i++;
-       }
-
-       of_node_put(node);
-}
-
-struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
-{
-       if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
-               id = 0;
-
-       return rsnd_mod_get(rsnd_ssi_get(priv, id));
-}
-
-int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
-{
-       if (!mod)
-               return 0;
-
-       return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE));
-}
-
-int rsnd_ssi_probe(struct rsnd_priv *priv)
-{
-       struct device_node *node;
-       struct device_node *np;
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct rsnd_mod_ops *ops;
-       struct clk *clk;
-       struct rsnd_ssi *ssi;
-       char name[RSND_SSI_NAME_SIZE];
-       int i, nr, ret;
-
-       node = rsnd_ssi_of_node(priv);
-       if (!node)
-               return -EINVAL;
-
-       nr = rsnd_node_count(priv, node, SSI_NAME);
-       if (!nr) {
-               ret = -EINVAL;
-               goto rsnd_ssi_probe_done;
-       }
-
-       ssi     = devm_kcalloc(dev, nr, sizeof(*ssi), GFP_KERNEL);
-       if (!ssi) {
-               ret = -ENOMEM;
-               goto rsnd_ssi_probe_done;
-       }
-
-       priv->ssi       = ssi;
-       priv->ssi_nr    = nr;
-
-       i = 0;
-       for_each_child_of_node(node, np) {
-               if (!of_device_is_available(np))
-                       goto skip;
-
-               i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
-               if (i < 0) {
-                       ret = -EINVAL;
-                       of_node_put(np);
-                       goto rsnd_ssi_probe_done;
-               }
-
-               ssi = rsnd_ssi_get(priv, i);
-
-               snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
-                        SSI_NAME, i);
-
-               clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk)) {
-                       ret = PTR_ERR(clk);
-                       of_node_put(np);
-                       goto rsnd_ssi_probe_done;
-               }
-
-               if (of_property_read_bool(np, "shared-pin"))
-                       rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
-
-               if (of_property_read_bool(np, "no-busif"))
-                       rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF);
-
-               ssi->irq = irq_of_parse_and_map(np, 0);
-               if (!ssi->irq) {
-                       ret = -EINVAL;
-                       of_node_put(np);
-                       goto rsnd_ssi_probe_done;
-               }
-
-               if (of_property_read_bool(np, "pio-transfer"))
-                       ops = &rsnd_ssi_pio_ops;
-               else
-                       ops = &rsnd_ssi_dma_ops;
-
-               ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
-                                   RSND_MOD_SSI, i);
-               if (ret) {
-                       of_node_put(np);
-                       goto rsnd_ssi_probe_done;
-               }
-skip:
-               i++;
-       }
-
-       ret = 0;
-
-rsnd_ssi_probe_done:
-       of_node_put(node);
-
-       return ret;
-}
-
-void rsnd_ssi_remove(struct rsnd_priv *priv)
-{
-       struct rsnd_ssi *ssi;
-       int i;
-
-       for_each_rsnd_ssi(ssi, priv, i) {
-               rsnd_mod_quit(rsnd_mod_get(ssi));
-       }
-}
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
deleted file mode 100644 (file)
index 665e8b2..0000000
+++ /dev/null
@@ -1,609 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas R-Car SSIU support
-//
-// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
-
-#include "rsnd.h"
-
-#define SSIU_NAME "ssiu"
-
-struct rsnd_ssiu {
-       struct rsnd_mod mod;
-       u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
-       unsigned int usrcnt;
-       int id;
-       int id_sub;
-};
-
-/* SSI_MODE */
-#define TDM_EXT                (1 << 0)
-#define TDM_SPLIT      (1 << 8)
-
-#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
-#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
-#define for_each_rsnd_ssiu(pos, priv, i)                               \
-       for (i = 0;                                                     \
-            (i < rsnd_ssiu_nr(priv)) &&                                \
-                    ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));  \
-            i++)
-
-/*
- *     SSI     Gen2            Gen3            Gen4
- *     0       BUSIF0-3        BUSIF0-7        BUSIF0-7
- *     1       BUSIF0-3        BUSIF0-7
- *     2       BUSIF0-3        BUSIF0-7
- *     3       BUSIF0          BUSIF0-7
- *     4       BUSIF0          BUSIF0-7
- *     5       BUSIF0          BUSIF0
- *     6       BUSIF0          BUSIF0
- *     7       BUSIF0          BUSIF0
- *     8       BUSIF0          BUSIF0
- *     9       BUSIF0-3        BUSIF0-7
- *     total   22              52              8
- */
-static const int gen2_id[] = { 0, 4,  8, 12, 13, 14, 15, 16, 17, 18 };
-static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
-static const int gen4_id[] = { 0 };
-
-/* enable busif buffer over/under run interrupt. */
-#define rsnd_ssiu_busif_err_irq_enable(mod)  rsnd_ssiu_busif_err_irq_ctrl(mod, 1)
-#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0)
-static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
-{
-       int id = rsnd_mod_id(mod);
-       int shift, offset;
-       int i;
-
-       switch (id) {
-       case 0:
-       case 1:
-       case 2:
-       case 3:
-       case 4:
-               shift  = id;
-               offset = 0;
-               break;
-       case 9:
-               shift  = 1;
-               offset = 1;
-               break;
-       default:
-               return;
-       }
-
-       for (i = 0; i < 4; i++) {
-               enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset);
-               u32 val = 0xf << (shift * 4);
-               u32 sys_int_enable = rsnd_mod_read(mod, reg);
-
-               if (enable)
-                       sys_int_enable |= val;
-               else
-                       sys_int_enable &= ~val;
-               rsnd_mod_write(mod, reg, sys_int_enable);
-       }
-}
-
-bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
-{
-       bool error = false;
-       int id = rsnd_mod_id(mod);
-       int shift, offset;
-       int i;
-
-       switch (id) {
-       case 0:
-       case 1:
-       case 2:
-       case 3:
-       case 4:
-               shift  = id;
-               offset = 0;
-               break;
-       case 9:
-               shift  = 1;
-               offset = 1;
-               break;
-       default:
-               goto out;
-       }
-
-       for (i = 0; i < 4; i++) {
-               u32 reg = SSI_SYS_STATUS(i * 2) + offset;
-               u32 status = rsnd_mod_read(mod, reg);
-               u32 val = 0xf << (shift * 4);
-
-               status &= val;
-               if (status) {
-                       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-                       struct device *dev = rsnd_priv_to_dev(priv);
-
-                       rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
-                                             rsnd_mod_name(mod), status);
-                       error = true;
-               }
-               rsnd_mod_write(mod, reg, val);
-       }
-out:
-       return error;
-}
-
-static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
-                                struct rsnd_dai_stream *io,
-                                enum rsnd_mod_type type)
-{
-       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
-       int busif = rsnd_mod_id_sub(mod);
-
-       return &ssiu->busif_status[busif];
-}
-
-static int rsnd_ssiu_init(struct rsnd_mod *mod,
-                         struct rsnd_dai_stream *io,
-                         struct rsnd_priv *priv)
-{
-       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
-       int use_busif = rsnd_ssi_use_busif(io);
-       int id = rsnd_mod_id(mod);
-       int is_clk_master = rsnd_rdai_is_clk_master(rdai);
-       u32 val1, val2;
-
-       /* clear status */
-       rsnd_ssiu_busif_err_status_clear(mod);
-
-       /* Gen4 doesn't have SSI_MODE */
-       if (rsnd_is_gen4(priv))
-               goto ssi_mode_setting_end;
-
-       /*
-        * SSI_MODE0
-        */
-       rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
-
-       /*
-        * SSI_MODE1 / SSI_MODE2
-        *
-        * FIXME
-        * sharing/multi with SSI0 are mainly supported
-        */
-       val1 = rsnd_mod_read(mod, SSI_MODE1);
-       val2 = rsnd_mod_read(mod, SSI_MODE2);
-       if (rsnd_ssi_is_pin_sharing(io)) {
-
-               ssis |= (1 << id);
-
-       } else if (ssis) {
-               /*
-                * Multi SSI
-                *
-                * set synchronized bit here
-                */
-
-               /* SSI4 is synchronized with SSI3 */
-               if (ssis & (1 << 4))
-                       val1 |= (1 << 20);
-               /* SSI012 are synchronized */
-               if (ssis == 0x0006)
-                       val1 |= (1 << 4);
-               /* SSI0129 are synchronized */
-               if (ssis == 0x0206)
-                       val2 |= (1 << 4);
-       }
-
-       /* SSI1 is sharing pin with SSI0 */
-       if (ssis & (1 << 1))
-               val1 |= is_clk_master ? 0x2 : 0x1;
-
-       /* SSI2 is sharing pin with SSI0 */
-       if (ssis & (1 << 2))
-               val1 |= is_clk_master ? 0x2 << 2 :
-                                       0x1 << 2;
-       /* SSI4 is sharing pin with SSI3 */
-       if (ssis & (1 << 4))
-               val1 |= is_clk_master ? 0x2 << 16 :
-                                       0x1 << 16;
-       /* SSI9 is sharing pin with SSI0 */
-       if (ssis & (1 << 9))
-               val2 |= is_clk_master ? 0x2 : 0x1;
-
-       rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
-       rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
-
-ssi_mode_setting_end:
-       /*
-        * Enable busif buffer over/under run interrupt.
-        * It will be handled from ssi.c
-        * see
-        *      __rsnd_ssi_interrupt()
-        */
-       rsnd_ssiu_busif_err_irq_enable(mod);
-
-       return 0;
-}
-
-static int rsnd_ssiu_quit(struct rsnd_mod *mod,
-                         struct rsnd_dai_stream *io,
-                         struct rsnd_priv *priv)
-{
-       /* disable busif buffer over/under run interrupt. */
-       rsnd_ssiu_busif_err_irq_disable(mod);
-
-       return 0;
-}
-
-static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
-       .name           = SSIU_NAME,
-       .init           = rsnd_ssiu_init,
-       .quit           = rsnd_ssiu_quit,
-       .get_status     = rsnd_ssiu_get_status,
-};
-
-static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai_stream *io,
-                              struct rsnd_priv *priv)
-{
-       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
-       u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
-       u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
-       int ret;
-       u32 mode = 0;
-
-       ret = rsnd_ssiu_init(mod, io, priv);
-       if (ret < 0)
-               return ret;
-
-       ssiu->usrcnt++;
-
-       /*
-        * TDM Extend/Split Mode
-        * see
-        *      rsnd_ssi_config_init()
-        */
-       if (rsnd_runtime_is_tdm(io))
-               mode = TDM_EXT;
-       else if (rsnd_runtime_is_tdm_split(io))
-               mode = TDM_SPLIT;
-
-       rsnd_mod_write(mod, SSI_MODE, mode);
-
-       if (rsnd_ssi_use_busif(io)) {
-               int id = rsnd_mod_id(mod);
-               int busif = rsnd_mod_id_sub(mod);
-               enum rsnd_reg adinr_reg, mode_reg, dalign_reg;
-
-               if ((id == 9) && (busif >= 4)) {
-                       adinr_reg = SSI9_BUSIF_ADINR(busif);
-                       mode_reg = SSI9_BUSIF_MODE(busif);
-                       dalign_reg = SSI9_BUSIF_DALIGN(busif);
-               } else {
-                       adinr_reg = SSI_BUSIF_ADINR(busif);
-                       mode_reg = SSI_BUSIF_MODE(busif);
-                       dalign_reg = SSI_BUSIF_DALIGN(busif);
-               }
-
-               rsnd_mod_write(mod, adinr_reg,
-                              rsnd_get_adinr_bit(mod, io) |
-                              (rsnd_io_is_play(io) ?
-                               rsnd_runtime_channel_after_ctu(io) :
-                               rsnd_runtime_channel_original(io)));
-               rsnd_mod_write(mod, mode_reg,
-                              rsnd_get_busif_shift(io, mod) | 1);
-               rsnd_mod_write(mod, dalign_reg,
-                              rsnd_get_dalign(mod, io));
-       }
-
-       if (has_hdmi0 || has_hdmi1) {
-               enum rsnd_mod_type rsnd_ssi_array[] = {
-                       RSND_MOD_SSIM1,
-                       RSND_MOD_SSIM2,
-                       RSND_MOD_SSIM3,
-               };
-               struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
-               struct rsnd_mod *pos;
-               u32 val;
-               int i;
-
-               i = rsnd_mod_id(ssi_mod);
-
-               /* output all same SSI as default */
-               val =   i << 16 |
-                       i << 20 |
-                       i << 24 |
-                       i << 28 |
-                       i;
-
-               for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
-                       int shift = (i * 4) + 20;
-
-                       val     = (val & ~(0xF << shift)) |
-                               rsnd_mod_id(pos) << shift;
-               }
-
-               if (has_hdmi0)
-                       rsnd_mod_write(mod, HDMI0_SEL, val);
-               if (has_hdmi1)
-                       rsnd_mod_write(mod, HDMI1_SEL, val);
-       }
-
-       return 0;
-}
-
-static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_priv *priv)
-{
-       int busif = rsnd_mod_id_sub(mod);
-
-       if (!rsnd_ssi_use_busif(io))
-               return 0;
-
-       rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
-
-       if (rsnd_ssi_multi_secondaries_runtime(io))
-               rsnd_mod_write(mod, SSI_CONTROL, 0x1);
-
-       return 0;
-}
-
-static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai_stream *io,
-                              struct rsnd_priv *priv)
-{
-       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
-       int busif = rsnd_mod_id_sub(mod);
-
-       if (!rsnd_ssi_use_busif(io))
-               return 0;
-
-       rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
-
-       if (--ssiu->usrcnt)
-               return 0;
-
-       if (rsnd_ssi_multi_secondaries_runtime(io))
-               rsnd_mod_write(mod, SSI_CONTROL, 0);
-
-       return 0;
-}
-
-static int rsnd_ssiu_id(struct rsnd_mod *mod)
-{
-       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
-
-       /* see rsnd_ssiu_probe() */
-       return ssiu->id;
-}
-
-static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
-{
-       struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
-
-       /* see rsnd_ssiu_probe() */
-       return ssiu->id_sub;
-}
-
-static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
-                                         struct rsnd_mod *mod)
-{
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-       int is_play = rsnd_io_is_play(io);
-       char *name;
-
-       /*
-        * It should use "rcar_sound,ssiu" on DT.
-        * But, we need to keep compatibility for old version.
-        *
-        * If it has "rcar_sound.ssiu", it will be used.
-        * If not, "rcar_sound.ssi" will be used.
-        * see
-        *      rsnd_ssi_dma_req()
-        *      rsnd_dma_of_path()
-        */
-
-       name = is_play ? "rx" : "tx";
-
-       return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
-                                       SSIU_NAME, mod, name);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void rsnd_ssiu_debug_info(struct seq_file *m,
-                                struct rsnd_dai_stream *io,
-                               struct rsnd_mod *mod)
-{
-       rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSIU,
-                                 rsnd_mod_id(mod) * 0x80, 0x80);
-}
-#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info
-#else
-#define DEBUG_INFO
-#endif
-
-static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
-       .name           = SSIU_NAME,
-       .dma_req        = rsnd_ssiu_dma_req,
-       .init           = rsnd_ssiu_init_gen2,
-       .quit           = rsnd_ssiu_quit,
-       .start          = rsnd_ssiu_start_gen2,
-       .stop           = rsnd_ssiu_stop_gen2,
-       .get_status     = rsnd_ssiu_get_status,
-       DEBUG_INFO
-};
-
-static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
-{
-       if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
-               id = 0;
-
-       return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
-}
-
-static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
-                                              struct rsnd_dai_stream *io)
-{
-       struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
-       struct rsnd_ssiu *ssiu;
-       int is_dma_mode;
-       int i;
-
-       if (!ssi_mod)
-               return;
-
-       is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod);
-
-       /* select BUSIF0 */
-       for_each_rsnd_ssiu(ssiu, priv, i) {
-               struct rsnd_mod *mod = rsnd_mod_get(ssiu);
-
-               if (is_dma_mode &&
-                   (rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
-                   (rsnd_mod_id_sub(mod) == 0)) {
-                       rsnd_dai_connect(mod, io, mod->type);
-                       return;
-               }
-       }
-}
-
-void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
-                            struct device_node *playback,
-                            struct device_node *capture)
-{
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *node = rsnd_ssiu_of_node(priv);
-       struct rsnd_dai_stream *io_p = &rdai->playback;
-       struct rsnd_dai_stream *io_c = &rdai->capture;
-
-       /* use rcar_sound,ssiu if exist */
-       if (node) {
-               struct device_node *np;
-               int i = 0;
-
-               for_each_child_of_node(node, np) {
-                       struct rsnd_mod *mod;
-
-                       i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i);
-                       if (i < 0) {
-                               of_node_put(np);
-                               break;
-                       }
-
-                       mod = rsnd_ssiu_mod_get(priv, i);
-
-                       if (np == playback)
-                               rsnd_dai_connect(mod, io_p, mod->type);
-                       if (np == capture)
-                               rsnd_dai_connect(mod, io_c, mod->type);
-                       i++;
-               }
-
-               of_node_put(node);
-       }
-
-       /* Keep DT compatibility */
-       if (!rsnd_io_to_mod_ssiu(io_p))
-               rsnd_parse_connect_ssiu_compatible(priv, io_p);
-       if (!rsnd_io_to_mod_ssiu(io_c))
-               rsnd_parse_connect_ssiu_compatible(priv, io_c);
-}
-
-int rsnd_ssiu_probe(struct rsnd_priv *priv)
-{
-       struct device *dev = rsnd_priv_to_dev(priv);
-       struct device_node *node;
-       struct rsnd_ssiu *ssiu;
-       struct rsnd_mod_ops *ops;
-       const int *list = NULL;
-       int i, nr;
-
-       /*
-        * Keep DT compatibility.
-        * if it has "rcar_sound,ssiu", use it.
-        * if not, use "rcar_sound,ssi"
-        * see
-        *      rsnd_ssiu_bufsif_to_id()
-        */
-       node = rsnd_ssiu_of_node(priv);
-       if (node)
-               nr = rsnd_node_count(priv, node, SSIU_NAME);
-       else
-               nr = priv->ssi_nr;
-
-       if (!nr)
-               return -EINVAL;
-
-       ssiu    = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
-       if (!ssiu)
-               return -ENOMEM;
-
-       priv->ssiu      = ssiu;
-       priv->ssiu_nr   = nr;
-
-       if (rsnd_is_gen1(priv))
-               ops = &rsnd_ssiu_ops_gen1;
-       else
-               ops = &rsnd_ssiu_ops_gen2;
-
-       /* Keep compatibility */
-       nr = 0;
-       if ((node) &&
-           (ops == &rsnd_ssiu_ops_gen2)) {
-               ops->id         = rsnd_ssiu_id;
-               ops->id_sub     = rsnd_ssiu_id_sub;
-
-               if (rsnd_is_gen2(priv)) {
-                       list    = gen2_id;
-                       nr      = ARRAY_SIZE(gen2_id);
-               } else if (rsnd_is_gen3(priv)) {
-                       list    = gen3_id;
-                       nr      = ARRAY_SIZE(gen3_id);
-               } else if (rsnd_is_gen4(priv)) {
-                       list    = gen4_id;
-                       nr      = ARRAY_SIZE(gen4_id);
-               } else {
-                       dev_err(dev, "unknown SSIU\n");
-                       return -ENODEV;
-               }
-       }
-
-       for_each_rsnd_ssiu(ssiu, priv, i) {
-               int ret;
-
-               if (node) {
-                       int j;
-
-                       /*
-                        * see
-                        *      rsnd_ssiu_get_id()
-                        *      rsnd_ssiu_get_id_sub()
-                        */
-                       for (j = 0; j < nr; j++) {
-                               if (list[j] > i)
-                                       break;
-                               ssiu->id        = j;
-                               ssiu->id_sub    = i - list[ssiu->id];
-                       }
-               } else {
-                       ssiu->id = i;
-               }
-
-               ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
-                                   ops, NULL, RSND_MOD_SSIU, i);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-void rsnd_ssiu_remove(struct rsnd_priv *priv)
-{
-       struct rsnd_ssiu *ssiu;
-       int i;
-
-       for_each_rsnd_ssiu(ssiu, priv, i) {
-               rsnd_mod_quit(rsnd_mod_get(ssiu));
-       }
-}
diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c
deleted file mode 100644 (file)
index 6efd017..0000000
+++ /dev/null
@@ -1,1212 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Renesas RZ/G2L ASoC Serial Sound Interface (SSIF-2) Driver
-//
-// Copyright (C) 2021 Renesas Electronics Corp.
-// Copyright (C) 2019 Chris Brandt.
-//
-
-#include <linux/clk.h>
-#include <linux/dmaengine.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/pm_runtime.h>
-#include <linux/reset.h>
-#include <sound/soc.h>
-
-/* REGISTER OFFSET */
-#define SSICR                  0x000
-#define SSISR                  0x004
-#define SSIFCR                 0x010
-#define SSIFSR                 0x014
-#define SSIFTDR                        0x018
-#define SSIFRDR                        0x01c
-#define SSIOFR                 0x020
-#define SSISCR                 0x024
-
-/* SSI REGISTER BITS */
-#define SSICR_DWL(x)           (((x) & 0x7) << 19)
-#define SSICR_SWL(x)           (((x) & 0x7) << 16)
-
-#define SSICR_CKS              BIT(30)
-#define SSICR_TUIEN            BIT(29)
-#define SSICR_TOIEN            BIT(28)
-#define SSICR_RUIEN            BIT(27)
-#define SSICR_ROIEN            BIT(26)
-#define SSICR_MST              BIT(14)
-#define SSICR_BCKP             BIT(13)
-#define SSICR_LRCKP            BIT(12)
-#define SSICR_CKDV(x)          (((x) & 0xf) << 4)
-#define SSICR_TEN              BIT(1)
-#define SSICR_REN              BIT(0)
-
-#define SSISR_TUIRQ            BIT(29)
-#define SSISR_TOIRQ            BIT(28)
-#define SSISR_RUIRQ            BIT(27)
-#define SSISR_ROIRQ            BIT(26)
-#define SSISR_IIRQ             BIT(25)
-
-#define SSIFCR_AUCKE           BIT(31)
-#define SSIFCR_SSIRST          BIT(16)
-#define SSIFCR_TIE             BIT(3)
-#define SSIFCR_RIE             BIT(2)
-#define SSIFCR_TFRST           BIT(1)
-#define SSIFCR_RFRST           BIT(0)
-#define SSIFCR_FIFO_RST                (SSIFCR_TFRST | SSIFCR_RFRST)
-
-#define SSIFSR_TDC_MASK                0x3f
-#define SSIFSR_TDC_SHIFT       24
-#define SSIFSR_RDC_MASK                0x3f
-#define SSIFSR_RDC_SHIFT       8
-
-#define SSIFSR_TDE             BIT(16)
-#define SSIFSR_RDF             BIT(0)
-
-#define SSIOFR_LRCONT          BIT(8)
-
-#define SSISCR_TDES(x)         (((x) & 0x1f) << 8)
-#define SSISCR_RDFS(x)         (((x) & 0x1f) << 0)
-
-/* Pre allocated buffers sizes */
-#define PREALLOC_BUFFER                (SZ_32K)
-#define PREALLOC_BUFFER_MAX    (SZ_32K)
-
-#define SSI_RATES              SNDRV_PCM_RATE_8000_48000 /* 8k-44.1kHz */
-#define SSI_FMTS               SNDRV_PCM_FMTBIT_S16_LE
-#define SSI_CHAN_MIN           2
-#define SSI_CHAN_MAX           2
-#define SSI_FIFO_DEPTH         32
-
-struct rz_ssi_priv;
-
-struct rz_ssi_stream {
-       struct rz_ssi_priv *priv;
-       struct snd_pcm_substream *substream;
-       int fifo_sample_size;   /* sample capacity of SSI FIFO */
-       int dma_buffer_pos;     /* The address for the next DMA descriptor */
-       int period_counter;     /* for keeping track of periods transferred */
-       int sample_width;
-       int buffer_pos;         /* current frame position in the buffer */
-       int running;            /* 0=stopped, 1=running */
-
-       int uerr_num;
-       int oerr_num;
-
-       struct dma_chan *dma_ch;
-
-       int (*transfer)(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm);
-};
-
-struct rz_ssi_priv {
-       void __iomem *base;
-       struct platform_device *pdev;
-       struct reset_control *rstc;
-       struct device *dev;
-       struct clk *sfr_clk;
-       struct clk *clk;
-
-       phys_addr_t phys;
-       int irq_int;
-       int irq_tx;
-       int irq_rx;
-       int irq_rt;
-
-       spinlock_t lock;
-
-       /*
-        * The SSI supports full-duplex transmission and reception.
-        * However, if an error occurs, channel reset (both transmission
-        * and reception reset) is required.
-        * So it is better to use as half-duplex (playing and recording
-        * should be done on separate channels).
-        */
-       struct rz_ssi_stream playback;
-       struct rz_ssi_stream capture;
-
-       /* clock */
-       unsigned long audio_mck;
-       unsigned long audio_clk_1;
-       unsigned long audio_clk_2;
-
-       bool lrckp_fsync_fall;  /* LR clock polarity (SSICR.LRCKP) */
-       bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */
-       bool dma_rt;
-
-       /* Full duplex communication support */
-       struct {
-               unsigned int rate;
-               unsigned int channels;
-               unsigned int sample_width;
-               unsigned int sample_bits;
-       } hw_params_cache;
-};
-
-static void rz_ssi_dma_complete(void *data);
-
-static void rz_ssi_reg_writel(struct rz_ssi_priv *priv, uint reg, u32 data)
-{
-       writel(data, (priv->base + reg));
-}
-
-static u32 rz_ssi_reg_readl(struct rz_ssi_priv *priv, uint reg)
-{
-       return readl(priv->base + reg);
-}
-
-static void rz_ssi_reg_mask_setl(struct rz_ssi_priv *priv, uint reg,
-                                u32 bclr, u32 bset)
-{
-       u32 val;
-
-       val = readl(priv->base + reg);
-       val = (val & ~bclr) | bset;
-       writel(val, (priv->base + reg));
-}
-
-static inline struct snd_soc_dai *
-rz_ssi_get_dai(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-
-       return snd_soc_rtd_to_cpu(rtd, 0);
-}
-
-static inline bool rz_ssi_stream_is_play(struct rz_ssi_priv *ssi,
-                                        struct snd_pcm_substream *substream)
-{
-       return substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-}
-
-static inline struct rz_ssi_stream *
-rz_ssi_stream_get(struct rz_ssi_priv *ssi, struct snd_pcm_substream *substream)
-{
-       struct rz_ssi_stream *stream = &ssi->playback;
-
-       if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
-               stream = &ssi->capture;
-
-       return stream;
-}
-
-static inline bool rz_ssi_is_dma_enabled(struct rz_ssi_priv *ssi)
-{
-       return (ssi->playback.dma_ch && (ssi->dma_rt || ssi->capture.dma_ch));
-}
-
-static void rz_ssi_set_substream(struct rz_ssi_stream *strm,
-                                struct snd_pcm_substream *substream)
-{
-       struct rz_ssi_priv *ssi = strm->priv;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ssi->lock, flags);
-       strm->substream = substream;
-       spin_unlock_irqrestore(&ssi->lock, flags);
-}
-
-static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi,
-                                  struct rz_ssi_stream *strm)
-{
-       unsigned long flags;
-       bool ret;
-
-       spin_lock_irqsave(&ssi->lock, flags);
-       ret = strm->substream && strm->substream->runtime;
-       spin_unlock_irqrestore(&ssi->lock, flags);
-
-       return ret;
-}
-
-static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm)
-{
-       return strm->substream && strm->running;
-}
-
-static void rz_ssi_stream_init(struct rz_ssi_stream *strm,
-                              struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       rz_ssi_set_substream(strm, substream);
-       strm->sample_width = samples_to_bytes(runtime, 1);
-       strm->dma_buffer_pos = 0;
-       strm->period_counter = 0;
-       strm->buffer_pos = 0;
-
-       strm->oerr_num = 0;
-       strm->uerr_num = 0;
-       strm->running = 0;
-
-       /* fifo init */
-       strm->fifo_sample_size = SSI_FIFO_DEPTH;
-}
-
-static void rz_ssi_stream_quit(struct rz_ssi_priv *ssi,
-                              struct rz_ssi_stream *strm)
-{
-       struct snd_soc_dai *dai = rz_ssi_get_dai(strm->substream);
-
-       rz_ssi_set_substream(strm, NULL);
-
-       if (strm->oerr_num > 0)
-               dev_info(dai->dev, "overrun = %d\n", strm->oerr_num);
-
-       if (strm->uerr_num > 0)
-               dev_info(dai->dev, "underrun = %d\n", strm->uerr_num);
-}
-
-static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate,
-                           unsigned int channels)
-{
-       static s8 ckdv[16] = { 1,  2,  4,  8, 16, 32, 64, 128,
-                              6, 12, 24, 48, 96, -1, -1, -1 };
-       unsigned int channel_bits = 32; /* System Word Length */
-       unsigned long bclk_rate = rate * channels * channel_bits;
-       unsigned int div;
-       unsigned int i;
-       u32 ssicr = 0;
-       u32 clk_ckdv;
-
-       /* Clear AUCKE so we can set MST */
-       rz_ssi_reg_writel(ssi, SSIFCR, 0);
-
-       /* Continue to output LRCK pin even when idle */
-       rz_ssi_reg_writel(ssi, SSIOFR, SSIOFR_LRCONT);
-       if (ssi->audio_clk_1 && ssi->audio_clk_2) {
-               if (ssi->audio_clk_1 % bclk_rate)
-                       ssi->audio_mck = ssi->audio_clk_2;
-               else
-                       ssi->audio_mck = ssi->audio_clk_1;
-       }
-
-       /* Clock setting */
-       ssicr |= SSICR_MST;
-       if (ssi->audio_mck == ssi->audio_clk_1)
-               ssicr |= SSICR_CKS;
-       if (ssi->bckp_rise)
-               ssicr |= SSICR_BCKP;
-       if (ssi->lrckp_fsync_fall)
-               ssicr |= SSICR_LRCKP;
-
-       /* Determine the clock divider */
-       clk_ckdv = 0;
-       div = ssi->audio_mck / bclk_rate;
-       /* try to find an match */
-       for (i = 0; i < ARRAY_SIZE(ckdv); i++) {
-               if (ckdv[i] == div) {
-                       clk_ckdv = i;
-                       break;
-               }
-       }
-
-       if (i == ARRAY_SIZE(ckdv)) {
-               dev_err(ssi->dev, "Rate not divisible by audio clock source\n");
-               return -EINVAL;
-       }
-
-       /*
-        * DWL: Data Word Length = 16 bits
-        * SWL: System Word Length = 32 bits
-        */
-       ssicr |= SSICR_CKDV(clk_ckdv);
-       ssicr |= SSICR_DWL(1) | SSICR_SWL(3);
-       rz_ssi_reg_writel(ssi, SSICR, ssicr);
-       rz_ssi_reg_writel(ssi, SSIFCR, SSIFCR_AUCKE | SSIFCR_FIFO_RST);
-
-       return 0;
-}
-
-static void rz_ssi_set_idle(struct rz_ssi_priv *ssi)
-{
-       int timeout;
-
-       /* Disable irqs */
-       rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN |
-                            SSICR_RUIEN | SSICR_ROIEN, 0);
-       rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0);
-
-       /* Clear all error flags */
-       rz_ssi_reg_mask_setl(ssi, SSISR,
-                            (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ |
-                             SSISR_RUIRQ), 0);
-
-       /* Wait for idle */
-       timeout = 100;
-       while (--timeout) {
-               if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ)
-                       break;
-               udelay(1);
-       }
-
-       if (!timeout)
-               dev_info(ssi->dev, "timeout waiting for SSI idle\n");
-
-       /* Hold FIFOs in reset */
-       rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_FIFO_RST);
-}
-
-static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
-{
-       bool is_play = rz_ssi_stream_is_play(ssi, strm->substream);
-       bool is_full_duplex;
-       u32 ssicr, ssifcr;
-
-       is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) ||
-               rz_ssi_is_stream_running(&ssi->capture);
-       ssicr = rz_ssi_reg_readl(ssi, SSICR);
-       ssifcr = rz_ssi_reg_readl(ssi, SSIFCR);
-       if (!is_full_duplex) {
-               ssifcr &= ~0xF;
-       } else {
-               rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
-               rz_ssi_set_idle(ssi);
-               ssifcr &= ~SSIFCR_FIFO_RST;
-       }
-
-       /* FIFO interrupt thresholds */
-       if (rz_ssi_is_dma_enabled(ssi))
-               rz_ssi_reg_writel(ssi, SSISCR, 0);
-       else
-               rz_ssi_reg_writel(ssi, SSISCR,
-                                 SSISCR_TDES(strm->fifo_sample_size / 2 - 1) |
-                                 SSISCR_RDFS(0));
-
-       /* enable IRQ */
-       if (is_play) {
-               ssicr |= SSICR_TUIEN | SSICR_TOIEN;
-               ssifcr |= SSIFCR_TIE;
-               if (!is_full_duplex)
-                       ssifcr |= SSIFCR_RFRST;
-       } else {
-               ssicr |= SSICR_RUIEN | SSICR_ROIEN;
-               ssifcr |= SSIFCR_RIE;
-               if (!is_full_duplex)
-                       ssifcr |= SSIFCR_TFRST;
-       }
-
-       rz_ssi_reg_writel(ssi, SSICR, ssicr);
-       rz_ssi_reg_writel(ssi, SSIFCR, ssifcr);
-
-       /* Clear all error flags */
-       rz_ssi_reg_mask_setl(ssi, SSISR,
-                            (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ |
-                             SSISR_RUIRQ), 0);
-
-       strm->running = 1;
-       if (is_full_duplex)
-               ssicr |= SSICR_TEN | SSICR_REN;
-       else
-               ssicr |= is_play ? SSICR_TEN : SSICR_REN;
-
-       rz_ssi_reg_writel(ssi, SSICR, ssicr);
-
-       return 0;
-}
-
-static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
-{
-       strm->running = 0;
-
-       if (rz_ssi_is_stream_running(&ssi->playback) ||
-           rz_ssi_is_stream_running(&ssi->capture))
-               return 0;
-
-       /* Disable TX/RX */
-       rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
-
-       /* Cancel all remaining DMA transactions */
-       if (rz_ssi_is_dma_enabled(ssi))
-               dmaengine_terminate_async(strm->dma_ch);
-
-       rz_ssi_set_idle(ssi);
-
-       return 0;
-}
-
-static void rz_ssi_pointer_update(struct rz_ssi_stream *strm, int frames)
-{
-       struct snd_pcm_substream *substream = strm->substream;
-       struct snd_pcm_runtime *runtime;
-       int current_period;
-
-       if (!strm->running || !substream || !substream->runtime)
-               return;
-
-       runtime = substream->runtime;
-       strm->buffer_pos += frames;
-       WARN_ON(strm->buffer_pos > runtime->buffer_size);
-
-       /* ring buffer */
-       if (strm->buffer_pos == runtime->buffer_size)
-               strm->buffer_pos = 0;
-
-       current_period = strm->buffer_pos / runtime->period_size;
-       if (strm->period_counter != current_period) {
-               snd_pcm_period_elapsed(strm->substream);
-               strm->period_counter = current_period;
-       }
-}
-
-static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
-{
-       struct snd_pcm_substream *substream = strm->substream;
-       struct snd_pcm_runtime *runtime;
-       u16 *buf;
-       int fifo_samples;
-       int frames_left;
-       int samples;
-       int i;
-
-       if (!rz_ssi_stream_is_valid(ssi, strm))
-               return -EINVAL;
-
-       runtime = substream->runtime;
-
-       do {
-               /* frames left in this period */
-               frames_left = runtime->period_size -
-                             (strm->buffer_pos % runtime->period_size);
-               if (!frames_left)
-                       frames_left = runtime->period_size;
-
-               /* Samples in RX FIFO */
-               fifo_samples = (rz_ssi_reg_readl(ssi, SSIFSR) >>
-                               SSIFSR_RDC_SHIFT) & SSIFSR_RDC_MASK;
-
-               /* Only read full frames at a time */
-               samples = 0;
-               while (frames_left && (fifo_samples >= runtime->channels)) {
-                       samples += runtime->channels;
-                       fifo_samples -= runtime->channels;
-                       frames_left--;
-               }
-
-               /* not enough samples yet */
-               if (!samples)
-                       break;
-
-               /* calculate new buffer index */
-               buf = (u16 *)runtime->dma_area;
-               buf += strm->buffer_pos * runtime->channels;
-
-               /* Note, only supports 16-bit samples */
-               for (i = 0; i < samples; i++)
-                       *buf++ = (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16);
-
-               rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
-               rz_ssi_pointer_update(strm, samples / runtime->channels);
-       } while (!frames_left && fifo_samples >= runtime->channels);
-
-       return 0;
-}
-
-static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
-{
-       struct snd_pcm_substream *substream = strm->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int sample_space;
-       int samples = 0;
-       int frames_left;
-       int i;
-       u32 ssifsr;
-       u16 *buf;
-
-       if (!rz_ssi_stream_is_valid(ssi, strm))
-               return -EINVAL;
-
-       /* frames left in this period */
-       frames_left = runtime->period_size - (strm->buffer_pos %
-                                             runtime->period_size);
-       if (frames_left == 0)
-               frames_left = runtime->period_size;
-
-       sample_space = strm->fifo_sample_size;
-       ssifsr = rz_ssi_reg_readl(ssi, SSIFSR);
-       sample_space -= (ssifsr >> SSIFSR_TDC_SHIFT) & SSIFSR_TDC_MASK;
-
-       /* Only add full frames at a time */
-       while (frames_left && (sample_space >= runtime->channels)) {
-               samples += runtime->channels;
-               sample_space -= runtime->channels;
-               frames_left--;
-       }
-
-       /* no space to send anything right now */
-       if (samples == 0)
-               return 0;
-
-       /* calculate new buffer index */
-       buf = (u16 *)(runtime->dma_area);
-       buf += strm->buffer_pos * runtime->channels;
-
-       /* Note, only supports 16-bit samples */
-       for (i = 0; i < samples; i++)
-               rz_ssi_reg_writel(ssi, SSIFTDR, ((u32)(*buf++) << 16));
-
-       rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_TDE, 0);
-       rz_ssi_pointer_update(strm, samples / runtime->channels);
-
-       return 0;
-}
-
-static irqreturn_t rz_ssi_interrupt(int irq, void *data)
-{
-       struct rz_ssi_stream *strm_playback = NULL;
-       struct rz_ssi_stream *strm_capture = NULL;
-       struct rz_ssi_priv *ssi = data;
-       u32 ssisr = rz_ssi_reg_readl(ssi, SSISR);
-
-       if (ssi->playback.substream)
-               strm_playback = &ssi->playback;
-       if (ssi->capture.substream)
-               strm_capture = &ssi->capture;
-
-       if (!strm_playback && !strm_capture)
-               return IRQ_HANDLED; /* Left over TX/RX interrupt */
-
-       if (irq == ssi->irq_int) { /* error or idle */
-               bool is_stopped = false;
-               int i, count;
-
-               if (rz_ssi_is_dma_enabled(ssi))
-                       count = 4;
-               else
-                       count = 1;
-
-               if (ssisr & (SSISR_RUIRQ | SSISR_ROIRQ | SSISR_TUIRQ | SSISR_TOIRQ))
-                       is_stopped = true;
-
-               if (ssi->capture.substream && is_stopped) {
-                       if (ssisr & SSISR_RUIRQ)
-                               strm_capture->uerr_num++;
-                       if (ssisr & SSISR_ROIRQ)
-                               strm_capture->oerr_num++;
-
-                       rz_ssi_stop(ssi, strm_capture);
-               }
-
-               if (ssi->playback.substream && is_stopped) {
-                       if (ssisr & SSISR_TUIRQ)
-                               strm_playback->uerr_num++;
-                       if (ssisr & SSISR_TOIRQ)
-                               strm_playback->oerr_num++;
-
-                       rz_ssi_stop(ssi, strm_playback);
-               }
-
-               /* Clear all flags */
-               rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | SSISR_TUIRQ |
-                                    SSISR_ROIRQ | SSISR_RUIRQ, 0);
-
-               /* Add/remove more data */
-               if (ssi->capture.substream && is_stopped) {
-                       for (i = 0; i < count; i++)
-                               strm_capture->transfer(ssi, strm_capture);
-               }
-
-               if (ssi->playback.substream && is_stopped) {
-                       for (i = 0; i < count; i++)
-                               strm_playback->transfer(ssi, strm_playback);
-               }
-
-               /* Resume */
-               if (ssi->playback.substream && is_stopped)
-                       rz_ssi_start(ssi, &ssi->playback);
-               if (ssi->capture.substream && is_stopped)
-                       rz_ssi_start(ssi, &ssi->capture);
-       }
-
-       if (!rz_ssi_is_stream_running(&ssi->playback) &&
-           !rz_ssi_is_stream_running(&ssi->capture))
-               return IRQ_HANDLED;
-
-       /* tx data empty */
-       if (irq == ssi->irq_tx && rz_ssi_is_stream_running(&ssi->playback))
-               strm_playback->transfer(ssi, &ssi->playback);
-
-       /* rx data full */
-       if (irq == ssi->irq_rx && rz_ssi_is_stream_running(&ssi->capture)) {
-               strm_capture->transfer(ssi, &ssi->capture);
-               rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
-       }
-
-       if (irq == ssi->irq_rt) {
-               if (ssi->playback.substream) {
-                       strm_playback->transfer(ssi, &ssi->playback);
-               } else {
-                       strm_capture->transfer(ssi, &ssi->capture);
-                       rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
-               }
-       }
-
-       return IRQ_HANDLED;
-}
-
-static int rz_ssi_dma_slave_config(struct rz_ssi_priv *ssi,
-                                  struct dma_chan *dma_ch, bool is_play)
-{
-       struct dma_slave_config cfg;
-
-       memset(&cfg, 0, sizeof(cfg));
-
-       cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
-       cfg.dst_addr = ssi->phys + SSIFTDR;
-       cfg.src_addr = ssi->phys + SSIFRDR;
-       cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
-       cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
-
-       return dmaengine_slave_config(dma_ch, &cfg);
-}
-
-static int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi,
-                              struct rz_ssi_stream *strm)
-{
-       struct snd_pcm_substream *substream = strm->substream;
-       struct dma_async_tx_descriptor *desc;
-       struct snd_pcm_runtime *runtime;
-       enum dma_transfer_direction dir;
-       u32 dma_paddr, dma_size;
-       int amount;
-
-       if (!rz_ssi_stream_is_valid(ssi, strm))
-               return -EINVAL;
-
-       runtime = substream->runtime;
-       if (runtime->state == SNDRV_PCM_STATE_DRAINING)
-               /*
-                * Stream is ending, so do not queue up any more DMA
-                * transfers otherwise we play partial sound clips
-                * because we can't shut off the DMA quick enough.
-                */
-               return 0;
-
-       dir = rz_ssi_stream_is_play(ssi, substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
-
-       /* Always transfer 1 period */
-       amount = runtime->period_size;
-
-       /* DMA physical address and size */
-       dma_paddr = runtime->dma_addr + frames_to_bytes(runtime,
-                                                       strm->dma_buffer_pos);
-       dma_size = frames_to_bytes(runtime, amount);
-       desc = dmaengine_prep_slave_single(strm->dma_ch, dma_paddr, dma_size,
-                                          dir,
-                                          DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               dev_err(ssi->dev, "dmaengine_prep_slave_single() fail\n");
-               return -ENOMEM;
-       }
-
-       desc->callback = rz_ssi_dma_complete;
-       desc->callback_param = strm;
-
-       if (dmaengine_submit(desc) < 0) {
-               dev_err(ssi->dev, "dmaengine_submit() fail\n");
-               return -EIO;
-       }
-
-       /* Update DMA pointer */
-       strm->dma_buffer_pos += amount;
-       if (strm->dma_buffer_pos >= runtime->buffer_size)
-               strm->dma_buffer_pos = 0;
-
-       /* Start DMA */
-       dma_async_issue_pending(strm->dma_ch);
-
-       return 0;
-}
-
-static void rz_ssi_dma_complete(void *data)
-{
-       struct rz_ssi_stream *strm = (struct rz_ssi_stream *)data;
-
-       if (!strm->running || !strm->substream || !strm->substream->runtime)
-               return;
-
-       /* Note that next DMA transaction has probably already started */
-       rz_ssi_pointer_update(strm, strm->substream->runtime->period_size);
-
-       /* Queue up another DMA transaction */
-       rz_ssi_dma_transfer(strm->priv, strm);
-}
-
-static void rz_ssi_release_dma_channels(struct rz_ssi_priv *ssi)
-{
-       if (ssi->playback.dma_ch) {
-               dma_release_channel(ssi->playback.dma_ch);
-               ssi->playback.dma_ch = NULL;
-               if (ssi->dma_rt)
-                       ssi->dma_rt = false;
-       }
-
-       if (ssi->capture.dma_ch) {
-               dma_release_channel(ssi->capture.dma_ch);
-               ssi->capture.dma_ch = NULL;
-       }
-}
-
-static int rz_ssi_dma_request(struct rz_ssi_priv *ssi, struct device *dev)
-{
-       ssi->playback.dma_ch = dma_request_chan(dev, "tx");
-       if (IS_ERR(ssi->playback.dma_ch))
-               ssi->playback.dma_ch = NULL;
-
-       ssi->capture.dma_ch = dma_request_chan(dev, "rx");
-       if (IS_ERR(ssi->capture.dma_ch))
-               ssi->capture.dma_ch = NULL;
-
-       if (!ssi->playback.dma_ch && !ssi->capture.dma_ch) {
-               ssi->playback.dma_ch = dma_request_chan(dev, "rt");
-               if (IS_ERR(ssi->playback.dma_ch)) {
-                       ssi->playback.dma_ch = NULL;
-                       goto no_dma;
-               }
-
-               ssi->dma_rt = true;
-       }
-
-       if (!rz_ssi_is_dma_enabled(ssi))
-               goto no_dma;
-
-       if (ssi->playback.dma_ch &&
-           (rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, true) < 0))
-               goto no_dma;
-
-       if (ssi->capture.dma_ch &&
-           (rz_ssi_dma_slave_config(ssi, ssi->capture.dma_ch, false) < 0))
-               goto no_dma;
-
-       return 0;
-
-no_dma:
-       rz_ssi_release_dma_channels(ssi);
-
-       return -ENODEV;
-}
-
-static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
-                             struct snd_soc_dai *dai)
-{
-       struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
-       struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream);
-       int ret = 0, i, num_transfer = 1;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               /* Soft Reset */
-               if (!rz_ssi_is_stream_running(&ssi->playback) &&
-                   !rz_ssi_is_stream_running(&ssi->capture)) {
-                       rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST);
-                       rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0);
-                       udelay(5);
-               }
-
-               rz_ssi_stream_init(strm, substream);
-
-               if (ssi->dma_rt) {
-                       bool is_playback;
-
-                       is_playback = rz_ssi_stream_is_play(ssi, substream);
-                       ret = rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch,
-                                                     is_playback);
-                       /* Fallback to pio */
-                       if (ret < 0) {
-                               ssi->playback.transfer = rz_ssi_pio_send;
-                               ssi->capture.transfer = rz_ssi_pio_recv;
-                               rz_ssi_release_dma_channels(ssi);
-                       }
-               }
-
-               /* For DMA, queue up multiple DMA descriptors */
-               if (rz_ssi_is_dma_enabled(ssi))
-                       num_transfer = 4;
-
-               for (i = 0; i < num_transfer; i++) {
-                       ret = strm->transfer(ssi, strm);
-                       if (ret)
-                               goto done;
-               }
-
-               ret = rz_ssi_start(ssi, strm);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               rz_ssi_stop(ssi, strm);
-               rz_ssi_stream_quit(ssi, strm);
-               break;
-       }
-
-done:
-       return ret;
-}
-
-static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-       struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
-
-       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_BP_FP:
-               break;
-       default:
-               dev_err(ssi->dev, "Codec should be clk and frame consumer\n");
-               return -EINVAL;
-       }
-
-       /*
-        * set clock polarity
-        *
-        * "normal" BCLK = Signal is available at rising edge of BCLK
-        * "normal" FSYNC = (I2S) Left ch starts with falling FSYNC edge
-        */
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               ssi->bckp_rise = false;
-               ssi->lrckp_fsync_fall = false;
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               ssi->bckp_rise = false;
-               ssi->lrckp_fsync_fall = true;
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               ssi->bckp_rise = true;
-               ssi->lrckp_fsync_fall = false;
-               break;
-       case SND_SOC_DAIFMT_IB_IF:
-               ssi->bckp_rise = true;
-               ssi->lrckp_fsync_fall = true;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* only i2s support */
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               break;
-       default:
-               dev_err(ssi->dev, "Only I2S mode is supported.\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate,
-                                     unsigned int channels,
-                                     unsigned int sample_width,
-                                     unsigned int sample_bits)
-{
-       if (ssi->hw_params_cache.rate != rate ||
-           ssi->hw_params_cache.channels != channels ||
-           ssi->hw_params_cache.sample_width != sample_width ||
-           ssi->hw_params_cache.sample_bits != sample_bits)
-               return false;
-
-       return true;
-}
-
-static void rz_ssi_cache_hw_params(struct rz_ssi_priv *ssi, unsigned int rate,
-                                  unsigned int channels,
-                                  unsigned int sample_width,
-                                  unsigned int sample_bits)
-{
-       ssi->hw_params_cache.rate = rate;
-       ssi->hw_params_cache.channels = channels;
-       ssi->hw_params_cache.sample_width = sample_width;
-       ssi->hw_params_cache.sample_bits = sample_bits;
-}
-
-static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params,
-                               struct snd_soc_dai *dai)
-{
-       struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
-       struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream);
-       unsigned int sample_bits = hw_param_interval(params,
-                                       SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
-       unsigned int channels = params_channels(params);
-       unsigned int rate = params_rate(params);
-
-       if (sample_bits != 16) {
-               dev_err(ssi->dev, "Unsupported sample width: %d\n",
-                       sample_bits);
-               return -EINVAL;
-       }
-
-       if (channels != 2) {
-               dev_err(ssi->dev, "Number of channels not matched: %d\n",
-                       channels);
-               return -EINVAL;
-       }
-
-       if (rz_ssi_is_stream_running(&ssi->playback) ||
-           rz_ssi_is_stream_running(&ssi->capture)) {
-               if (rz_ssi_is_valid_hw_params(ssi, rate, channels,
-                                             strm->sample_width, sample_bits))
-                       return 0;
-
-               dev_err(ssi->dev, "Full duplex needs same HW params\n");
-               return -EINVAL;
-       }
-
-       rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width,
-                              sample_bits);
-
-       return rz_ssi_clk_setup(ssi, rate, channels);
-}
-
-static const struct snd_soc_dai_ops rz_ssi_dai_ops = {
-       .trigger        = rz_ssi_dai_trigger,
-       .set_fmt        = rz_ssi_dai_set_fmt,
-       .hw_params      = rz_ssi_dai_hw_params,
-};
-
-static const struct snd_pcm_hardware rz_ssi_pcm_hardware = {
-       .info                   = SNDRV_PCM_INFO_INTERLEAVED    |
-                                 SNDRV_PCM_INFO_MMAP           |
-                                 SNDRV_PCM_INFO_MMAP_VALID,
-       .buffer_bytes_max       = PREALLOC_BUFFER,
-       .period_bytes_min       = 32,
-       .period_bytes_max       = 8192,
-       .channels_min           = SSI_CHAN_MIN,
-       .channels_max           = SSI_CHAN_MAX,
-       .periods_min            = 1,
-       .periods_max            = 32,
-       .fifo_size              = 32 * 2,
-};
-
-static int rz_ssi_pcm_open(struct snd_soc_component *component,
-                          struct snd_pcm_substream *substream)
-{
-       snd_soc_set_runtime_hwparams(substream, &rz_ssi_pcm_hardware);
-
-       return snd_pcm_hw_constraint_integer(substream->runtime,
-                                           SNDRV_PCM_HW_PARAM_PERIODS);
-}
-
-static snd_pcm_uframes_t rz_ssi_pcm_pointer(struct snd_soc_component *component,
-                                           struct snd_pcm_substream *substream)
-{
-       struct snd_soc_dai *dai = rz_ssi_get_dai(substream);
-       struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
-       struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream);
-
-       return strm->buffer_pos;
-}
-
-static int rz_ssi_pcm_new(struct snd_soc_component *component,
-                         struct snd_soc_pcm_runtime *rtd)
-{
-       snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
-                                      rtd->card->snd_card->dev,
-                                      PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
-       return 0;
-}
-
-static struct snd_soc_dai_driver rz_ssi_soc_dai[] = {
-       {
-               .name                   = "rz-ssi-dai",
-               .playback = {
-                       .rates          = SSI_RATES,
-                       .formats        = SSI_FMTS,
-                       .channels_min   = SSI_CHAN_MIN,
-                       .channels_max   = SSI_CHAN_MAX,
-               },
-               .capture = {
-                       .rates          = SSI_RATES,
-                       .formats        = SSI_FMTS,
-                       .channels_min   = SSI_CHAN_MIN,
-                       .channels_max   = SSI_CHAN_MAX,
-               },
-               .ops = &rz_ssi_dai_ops,
-       },
-};
-
-static const struct snd_soc_component_driver rz_ssi_soc_component = {
-       .name                   = "rz-ssi",
-       .open                   = rz_ssi_pcm_open,
-       .pointer                = rz_ssi_pcm_pointer,
-       .pcm_construct          = rz_ssi_pcm_new,
-       .legacy_dai_naming      = 1,
-};
-
-static int rz_ssi_probe(struct platform_device *pdev)
-{
-       struct rz_ssi_priv *ssi;
-       struct clk *audio_clk;
-       struct resource *res;
-       int ret;
-
-       ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
-       if (!ssi)
-               return -ENOMEM;
-
-       ssi->pdev = pdev;
-       ssi->dev = &pdev->dev;
-       ssi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
-       if (IS_ERR(ssi->base))
-               return PTR_ERR(ssi->base);
-
-       ssi->phys = res->start;
-       ssi->clk = devm_clk_get(&pdev->dev, "ssi");
-       if (IS_ERR(ssi->clk))
-               return PTR_ERR(ssi->clk);
-
-       ssi->sfr_clk = devm_clk_get(&pdev->dev, "ssi_sfr");
-       if (IS_ERR(ssi->sfr_clk))
-               return PTR_ERR(ssi->sfr_clk);
-
-       audio_clk = devm_clk_get(&pdev->dev, "audio_clk1");
-       if (IS_ERR(audio_clk))
-               return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk),
-                                    "no audio clk1");
-
-       ssi->audio_clk_1 = clk_get_rate(audio_clk);
-       audio_clk = devm_clk_get(&pdev->dev, "audio_clk2");
-       if (IS_ERR(audio_clk))
-               return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk),
-                                    "no audio clk2");
-
-       ssi->audio_clk_2 = clk_get_rate(audio_clk);
-       if (!(ssi->audio_clk_1 || ssi->audio_clk_2))
-               return dev_err_probe(&pdev->dev, -EINVAL,
-                                    "no audio clk1 or audio clk2");
-
-       ssi->audio_mck = ssi->audio_clk_1 ? ssi->audio_clk_1 : ssi->audio_clk_2;
-
-       /* Detect DMA support */
-       ret = rz_ssi_dma_request(ssi, &pdev->dev);
-       if (ret < 0) {
-               dev_warn(&pdev->dev, "DMA not available, using PIO\n");
-               ssi->playback.transfer = rz_ssi_pio_send;
-               ssi->capture.transfer = rz_ssi_pio_recv;
-       } else {
-               dev_info(&pdev->dev, "DMA enabled");
-               ssi->playback.transfer = rz_ssi_dma_transfer;
-               ssi->capture.transfer = rz_ssi_dma_transfer;
-       }
-
-       ssi->playback.priv = ssi;
-       ssi->capture.priv = ssi;
-
-       spin_lock_init(&ssi->lock);
-       dev_set_drvdata(&pdev->dev, ssi);
-
-       /* Error Interrupt */
-       ssi->irq_int = platform_get_irq_byname(pdev, "int_req");
-       if (ssi->irq_int < 0) {
-               rz_ssi_release_dma_channels(ssi);
-               return ssi->irq_int;
-       }
-
-       ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt,
-                              0, dev_name(&pdev->dev), ssi);
-       if (ret < 0) {
-               rz_ssi_release_dma_channels(ssi);
-               return dev_err_probe(&pdev->dev, ret,
-                                    "irq request error (int_req)\n");
-       }
-
-       if (!rz_ssi_is_dma_enabled(ssi)) {
-               /* Tx and Rx interrupts (pio only) */
-               ssi->irq_tx = platform_get_irq_byname(pdev, "dma_tx");
-               ssi->irq_rx = platform_get_irq_byname(pdev, "dma_rx");
-               if (ssi->irq_tx == -ENXIO && ssi->irq_rx == -ENXIO) {
-                       ssi->irq_rt = platform_get_irq_byname(pdev, "dma_rt");
-                       if (ssi->irq_rt < 0)
-                               return ssi->irq_rt;
-
-                       ret = devm_request_irq(&pdev->dev, ssi->irq_rt,
-                                              &rz_ssi_interrupt, 0,
-                                              dev_name(&pdev->dev), ssi);
-                       if (ret < 0)
-                               return dev_err_probe(&pdev->dev, ret,
-                                                    "irq request error (dma_rt)\n");
-               } else {
-                       if (ssi->irq_tx < 0)
-                               return ssi->irq_tx;
-
-                       if (ssi->irq_rx < 0)
-                               return ssi->irq_rx;
-
-                       ret = devm_request_irq(&pdev->dev, ssi->irq_tx,
-                                              &rz_ssi_interrupt, 0,
-                                              dev_name(&pdev->dev), ssi);
-                       if (ret < 0)
-                               return dev_err_probe(&pdev->dev, ret,
-                                               "irq request error (dma_tx)\n");
-
-                       ret = devm_request_irq(&pdev->dev, ssi->irq_rx,
-                                              &rz_ssi_interrupt, 0,
-                                              dev_name(&pdev->dev), ssi);
-                       if (ret < 0)
-                               return dev_err_probe(&pdev->dev, ret,
-                                               "irq request error (dma_rx)\n");
-               }
-       }
-
-       ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
-       if (IS_ERR(ssi->rstc)) {
-               ret = PTR_ERR(ssi->rstc);
-               goto err_reset;
-       }
-
-       reset_control_deassert(ssi->rstc);
-       pm_runtime_enable(&pdev->dev);
-       ret = pm_runtime_resume_and_get(&pdev->dev);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n");
-               goto err_pm;
-       }
-
-       ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component,
-                                             rz_ssi_soc_dai,
-                                             ARRAY_SIZE(rz_ssi_soc_dai));
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to register snd component\n");
-               goto err_snd_soc;
-       }
-
-       return 0;
-
-err_snd_soc:
-       pm_runtime_put(ssi->dev);
-err_pm:
-       pm_runtime_disable(ssi->dev);
-       reset_control_assert(ssi->rstc);
-err_reset:
-       rz_ssi_release_dma_channels(ssi);
-
-       return ret;
-}
-
-static void rz_ssi_remove(struct platform_device *pdev)
-{
-       struct rz_ssi_priv *ssi = dev_get_drvdata(&pdev->dev);
-
-       rz_ssi_release_dma_channels(ssi);
-
-       pm_runtime_put(ssi->dev);
-       pm_runtime_disable(ssi->dev);
-       reset_control_assert(ssi->rstc);
-}
-
-static const struct of_device_id rz_ssi_of_match[] = {
-       { .compatible = "renesas,rz-ssi", },
-       {/* Sentinel */},
-};
-MODULE_DEVICE_TABLE(of, rz_ssi_of_match);
-
-static struct platform_driver rz_ssi_driver = {
-       .driver = {
-               .name   = "rz-ssi-pcm-audio",
-               .of_match_table = rz_ssi_of_match,
-       },
-       .probe          = rz_ssi_probe,
-       .remove         = rz_ssi_remove,
-};
-
-module_platform_driver(rz_ssi_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Renesas RZ/G2L ASoC Serial Sound Interface Driver");
-MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
deleted file mode 100644 (file)
index d267243..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Generic AC97 sound support for SH7760
-//
-// (c) 2007 Manuel Lauss
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/io.h>
-
-#define IPSEL 0xFE400034
-
-SND_SOC_DAILINK_DEFS(ac97,
-       DAILINK_COMP_ARRAY(COMP_CPU("hac-dai.0")),      /* HAC0 */
-       DAILINK_COMP_ARRAY(COMP_CODEC("ac97-codec", "ac97-hifi")),
-       DAILINK_COMP_ARRAY(COMP_PLATFORM("sh7760-pcm-audio")));
-
-static struct snd_soc_dai_link sh7760_ac97_dai = {
-       .name = "AC97",
-       .stream_name = "AC97 HiFi",
-       SND_SOC_DAILINK_REG(ac97),
-};
-
-static struct snd_soc_card sh7760_ac97_soc_machine  = {
-       .name = "SH7760 AC97",
-       .owner = THIS_MODULE,
-       .dai_link = &sh7760_ac97_dai,
-       .num_links = 1,
-};
-
-static struct platform_device *sh7760_ac97_snd_device;
-
-static int __init sh7760_ac97_init(void)
-{
-       int ret;
-       unsigned short ipsel;
-
-       /* enable both AC97 controllers in pinmux reg */
-       ipsel = __raw_readw(IPSEL);
-       __raw_writew(ipsel | (3 << 10), IPSEL);
-
-       ret = -ENOMEM;
-       sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!sh7760_ac97_snd_device)
-               goto out;
-
-       platform_set_drvdata(sh7760_ac97_snd_device,
-                            &sh7760_ac97_soc_machine);
-       ret = platform_device_add(sh7760_ac97_snd_device);
-
-       if (ret)
-               platform_device_put(sh7760_ac97_snd_device);
-
-out:
-       return ret;
-}
-
-static void __exit sh7760_ac97_exit(void)
-{
-       platform_device_unregister(sh7760_ac97_snd_device);
-}
-
-module_init(sh7760_ac97_init);
-module_exit(sh7760_ac97_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine");
-MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h
deleted file mode 100644 (file)
index a675c36..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
-//
-// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
-// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
-
-#ifndef SIU_H
-#define SIU_H
-
-/* Common kernel and user-space firmware-building defines and types */
-
-#define YRAM0_SIZE             (0x0040 / 4)            /* 16 */
-#define YRAM1_SIZE             (0x0080 / 4)            /* 32 */
-#define YRAM2_SIZE             (0x0040 / 4)            /* 16 */
-#define YRAM3_SIZE             (0x0080 / 4)            /* 32 */
-#define YRAM4_SIZE             (0x0080 / 4)            /* 32 */
-#define YRAM_DEF_SIZE          (YRAM0_SIZE + YRAM1_SIZE + YRAM2_SIZE + \
-                                YRAM3_SIZE + YRAM4_SIZE)
-#define YRAM_FIR_SIZE          (0x0400 / 4)            /* 256 */
-#define YRAM_IIR_SIZE          (0x0200 / 4)            /* 128 */
-
-#define XRAM0_SIZE             (0x0400 / 4)            /* 256 */
-#define XRAM1_SIZE             (0x0200 / 4)            /* 128 */
-#define XRAM2_SIZE             (0x0200 / 4)            /* 128 */
-
-/* PRAM program array size */
-#define PRAM0_SIZE             (0x0100 / 4)            /* 64 */
-#define PRAM1_SIZE             ((0x2000 - 0x0100) / 4) /* 1984 */
-
-#include <linux/types.h>
-
-struct siu_spb_param {
-       __u32   ab1a;   /* input FIFO address */
-       __u32   ab0a;   /* output FIFO address */
-       __u32   dir;    /* 0=the ather except CPUOUTPUT, 1=CPUINPUT */
-       __u32   event;  /* SPB program starting conditions */
-       __u32   stfifo; /* STFIFO register setting value */
-       __u32   trdat;  /* TRDAT register setting value */
-};
-
-struct siu_firmware {
-       __u32                   yram_fir_coeff[YRAM_FIR_SIZE];
-       __u32                   pram0[PRAM0_SIZE];
-       __u32                   pram1[PRAM1_SIZE];
-       __u32                   yram0[YRAM0_SIZE];
-       __u32                   yram1[YRAM1_SIZE];
-       __u32                   yram2[YRAM2_SIZE];
-       __u32                   yram3[YRAM3_SIZE];
-       __u32                   yram4[YRAM4_SIZE];
-       __u32                   spbpar_num;
-       struct siu_spb_param    spbpar[32];
-};
-
-#ifdef __KERNEL__
-
-#include <linux/dmaengine.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/sh_dma.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#define SIU_PERIOD_BYTES_MAX   8192            /* DMA transfer/period size */
-#define SIU_PERIOD_BYTES_MIN   256             /* DMA transfer/period size */
-#define SIU_PERIODS_MAX                64              /* Max periods in buffer */
-#define SIU_PERIODS_MIN                4               /* Min periods in buffer */
-#define SIU_BUFFER_BYTES_MAX   (SIU_PERIOD_BYTES_MAX * SIU_PERIODS_MAX)
-
-/* SIU ports: only one can be used at a time */
-enum {
-       SIU_PORT_A,
-       SIU_PORT_B,
-       SIU_PORT_NUM,
-};
-
-/* SIU clock configuration */
-enum {
-       SIU_CLKA_PLL,
-       SIU_CLKA_EXT,
-       SIU_CLKB_PLL,
-       SIU_CLKB_EXT
-};
-
-struct device;
-struct siu_info {
-       struct device           *dev;
-       int                     port_id;
-       u32 __iomem             *pram;
-       u32 __iomem             *xram;
-       u32 __iomem             *yram;
-       u32 __iomem             *reg;
-       struct siu_firmware     fw;
-};
-
-struct siu_stream {
-       struct work_struct              work;
-       struct snd_pcm_substream        *substream;
-       snd_pcm_format_t                format;
-       size_t                          buf_bytes;
-       size_t                          period_bytes;
-       int                             cur_period;     /* Period currently in dma */
-       u32                             volume;
-       snd_pcm_sframes_t               xfer_cnt;       /* Number of frames */
-       u8                              rw_flg;         /* transfer status */
-       /* DMA status */
-       struct dma_chan                 *chan;          /* DMA channel */
-       struct dma_async_tx_descriptor  *tx_desc;
-       dma_cookie_t                    cookie;
-       struct sh_dmae_slave            param;
-};
-
-struct siu_port {
-       unsigned long           play_cap;       /* Used to track full duplex */
-       struct snd_pcm          *pcm;
-       struct siu_stream       playback;
-       struct siu_stream       capture;
-       u32                     stfifo;         /* STFIFO value from firmware */
-       u32                     trdat;          /* TRDAT value from firmware */
-};
-
-extern struct siu_port *siu_ports[SIU_PORT_NUM];
-
-static inline struct siu_port *siu_port_info(struct snd_pcm_substream *substream)
-{
-       struct platform_device *pdev =
-               to_platform_device(substream->pcm->card->dev);
-       return siu_ports[pdev->id];
-}
-
-/* Register access */
-static inline void siu_write32(u32 __iomem *addr, u32 val)
-{
-       __raw_writel(val, addr);
-}
-
-static inline u32 siu_read32(u32 __iomem *addr)
-{
-       return __raw_readl(addr);
-}
-
-/* SIU registers */
-#define SIU_IFCTL      (0x000 / sizeof(u32))
-#define SIU_SRCTL      (0x004 / sizeof(u32))
-#define SIU_SFORM      (0x008 / sizeof(u32))
-#define SIU_CKCTL      (0x00c / sizeof(u32))
-#define SIU_TRDAT      (0x010 / sizeof(u32))
-#define SIU_STFIFO     (0x014 / sizeof(u32))
-#define SIU_DPAK       (0x01c / sizeof(u32))
-#define SIU_CKREV      (0x020 / sizeof(u32))
-#define SIU_EVNTC      (0x028 / sizeof(u32))
-#define SIU_SBCTL      (0x040 / sizeof(u32))
-#define SIU_SBPSET     (0x044 / sizeof(u32))
-#define SIU_SBFSTS     (0x068 / sizeof(u32))
-#define SIU_SBDVCA     (0x06c / sizeof(u32))
-#define SIU_SBDVCB     (0x070 / sizeof(u32))
-#define SIU_SBACTIV    (0x074 / sizeof(u32))
-#define SIU_DMAIA      (0x090 / sizeof(u32))
-#define SIU_DMAIB      (0x094 / sizeof(u32))
-#define SIU_DMAOA      (0x098 / sizeof(u32))
-#define SIU_DMAOB      (0x09c / sizeof(u32))
-#define SIU_DMAML      (0x0a0 / sizeof(u32))
-#define SIU_SPSTS      (0x0cc / sizeof(u32))
-#define SIU_SPCTL      (0x0d0 / sizeof(u32))
-#define SIU_BRGASEL    (0x100 / sizeof(u32))
-#define SIU_BRRA       (0x104 / sizeof(u32))
-#define SIU_BRGBSEL    (0x108 / sizeof(u32))
-#define SIU_BRRB       (0x10c / sizeof(u32))
-
-extern const struct snd_soc_component_driver siu_component;
-extern struct siu_info *siu_i2s_data;
-
-int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
-void siu_free_port(struct siu_port *port_info);
-
-#endif
-
-#endif /* SIU_H */
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
deleted file mode 100644 (file)
index 7e771a1..0000000
+++ /dev/null
@@ -1,800 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
-//
-// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
-// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
-
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#include <asm/clock.h>
-#include <asm/siu.h>
-
-#include <sound/control.h>
-#include <sound/soc.h>
-
-#include "siu.h"
-
-/* Board specifics */
-#if defined(CONFIG_CPU_SUBTYPE_SH7722)
-# define SIU_MAX_VOLUME                0x1000
-#else
-# define SIU_MAX_VOLUME                0x7fff
-#endif
-
-#define PRAM_SIZE      0x2000
-#define XRAM_SIZE      0x800
-#define YRAM_SIZE      0x800
-
-#define XRAM_OFFSET    0x4000
-#define YRAM_OFFSET    0x6000
-#define REG_OFFSET     0xc000
-
-#define PLAYBACK_ENABLED       1
-#define CAPTURE_ENABLED                2
-
-#define VOLUME_CAPTURE         0
-#define VOLUME_PLAYBACK                1
-#define DFLT_VOLUME_LEVEL      0x08000800
-
-/*
- * SPDIF is only available on port A and on some SIU implementations it is only
- * available for input. Due to the lack of hardware to test it, SPDIF is left
- * disabled in this driver version
- */
-struct format_flag {
-       u32     i2s;
-       u32     pcm;
-       u32     spdif;
-       u32     mask;
-};
-
-struct port_flag {
-       struct format_flag      playback;
-       struct format_flag      capture;
-};
-
-struct siu_info *siu_i2s_data;
-
-static struct port_flag siu_flags[SIU_PORT_NUM] = {
-       [SIU_PORT_A] = {
-               .playback = {
-                       .i2s    = 0x50000000,
-                       .pcm    = 0x40000000,
-                       .spdif  = 0x80000000,   /* not on all SIU versions */
-                       .mask   = 0xd0000000,
-               },
-               .capture = {
-                       .i2s    = 0x05000000,
-                       .pcm    = 0x04000000,
-                       .spdif  = 0x08000000,
-                       .mask   = 0x0d000000,
-               },
-       },
-       [SIU_PORT_B] = {
-               .playback = {
-                       .i2s    = 0x00500000,
-                       .pcm    = 0x00400000,
-                       .spdif  = 0,            /* impossible - turn off */
-                       .mask   = 0x00500000,
-               },
-               .capture = {
-                       .i2s    = 0x00050000,
-                       .pcm    = 0x00040000,
-                       .spdif  = 0,            /* impossible - turn off */
-                       .mask   = 0x00050000,
-               },
-       },
-};
-
-static void siu_dai_start(struct siu_port *port_info)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-
-       dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
-
-       /* Issue software reset to siu */
-       siu_write32(base + SIU_SRCTL, 0);
-
-       /* Wait for the reset to take effect */
-       udelay(1);
-
-       port_info->stfifo = 0;
-       port_info->trdat = 0;
-
-       /* portA, portB, SIU operate */
-       siu_write32(base + SIU_SRCTL, 0x301);
-
-       /* portA=256fs, portB=256fs */
-       siu_write32(base + SIU_CKCTL, 0x40400000);
-
-       /* portA's BRG does not divide SIUCKA */
-       siu_write32(base + SIU_BRGASEL, 0);
-       siu_write32(base + SIU_BRRA, 0);
-
-       /* portB's BRG divides SIUCKB by half */
-       siu_write32(base + SIU_BRGBSEL, 1);
-       siu_write32(base + SIU_BRRB, 0);
-
-       siu_write32(base + SIU_IFCTL, 0x44440000);
-
-       /* portA: 32 bit/fs, master; portB: 32 bit/fs, master */
-       siu_write32(base + SIU_SFORM, 0x0c0c0000);
-
-       /*
-        * Volume levels: looks like the DSP firmware implements volume controls
-        * differently from what's described in the datasheet
-        */
-       siu_write32(base + SIU_SBDVCA, port_info->playback.volume);
-       siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
-}
-
-static void siu_dai_stop(struct siu_port *port_info)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-
-       /* SIU software reset */
-       siu_write32(base + SIU_SRCTL, 0);
-}
-
-static void siu_dai_spbAselect(struct siu_port *port_info)
-{
-       struct siu_info *info = siu_i2s_data;
-       struct siu_firmware *fw = &info->fw;
-       u32 *ydef = fw->yram0;
-       u32 idx;
-
-       /* path A use */
-       if (!info->port_id)
-               idx = 1;                /* portA */
-       else
-               idx = 2;                /* portB */
-
-       ydef[0] = (fw->spbpar[idx].ab1a << 16) |
-               (fw->spbpar[idx].ab0a << 8) |
-               (fw->spbpar[idx].dir << 7) | 3;
-       ydef[1] = fw->yram0[1]; /* 0x03000300 */
-       ydef[2] = (16 / 2) << 24;
-       ydef[3] = fw->yram0[3]; /* 0 */
-       ydef[4] = fw->yram0[4]; /* 0 */
-       ydef[7] = fw->spbpar[idx].event;
-       port_info->stfifo |= fw->spbpar[idx].stfifo;
-       port_info->trdat |= fw->spbpar[idx].trdat;
-}
-
-static void siu_dai_spbBselect(struct siu_port *port_info)
-{
-       struct siu_info *info = siu_i2s_data;
-       struct siu_firmware *fw = &info->fw;
-       u32 *ydef = fw->yram0;
-       u32 idx;
-
-       /* path B use */
-       if (!info->port_id)
-               idx = 7;                /* portA */
-       else
-               idx = 8;                /* portB */
-
-       ydef[5] = (fw->spbpar[idx].ab1a << 16) |
-               (fw->spbpar[idx].ab0a << 8) | 1;
-       ydef[6] = fw->spbpar[idx].event;
-       port_info->stfifo |= fw->spbpar[idx].stfifo;
-       port_info->trdat |= fw->spbpar[idx].trdat;
-}
-
-static void siu_dai_open(struct siu_stream *siu_stream)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-       u32 srctl, ifctl;
-
-       srctl = siu_read32(base + SIU_SRCTL);
-       ifctl = siu_read32(base + SIU_IFCTL);
-
-       switch (info->port_id) {
-       case SIU_PORT_A:
-               /* portA operates */
-               srctl |= 0x200;
-               ifctl &= ~0xc2;
-               break;
-       case SIU_PORT_B:
-               /* portB operates */
-               srctl |= 0x100;
-               ifctl &= ~0x31;
-               break;
-       }
-
-       siu_write32(base + SIU_SRCTL, srctl);
-       /* Unmute and configure portA */
-       siu_write32(base + SIU_IFCTL, ifctl);
-}
-
-/*
- * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower
- * packing is supported
- */
-static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-       u32 dpak;
-
-       dpak = siu_read32(base + SIU_DPAK);
-
-       switch (info->port_id) {
-       case SIU_PORT_A:
-               dpak &= ~0xc0000000;
-               break;
-       case SIU_PORT_B:
-               dpak &= ~0x00c00000;
-               break;
-       }
-
-       siu_write32(base + SIU_DPAK, dpak);
-}
-
-static int siu_dai_spbstart(struct siu_port *port_info)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-       struct siu_firmware *fw = &info->fw;
-       u32 *ydef = fw->yram0;
-       int cnt;
-       u32 __iomem *add;
-       u32 *ptr;
-
-       /* Load SPB Program in PRAM */
-       ptr = fw->pram0;
-       add = info->pram;
-       for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++)
-               siu_write32(add, *ptr);
-
-       ptr = fw->pram1;
-       add = info->pram + (0x0100 / sizeof(u32));
-       for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++)
-               siu_write32(add, *ptr);
-
-       /* XRAM initialization */
-       add = info->xram;
-       for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++)
-               siu_write32(add, 0);
-
-       /* YRAM variable area initialization */
-       add = info->yram;
-       for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++)
-               siu_write32(add, ydef[cnt]);
-
-       /* YRAM FIR coefficient area initialization */
-       add = info->yram + (0x0200 / sizeof(u32));
-       for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++)
-               siu_write32(add, fw->yram_fir_coeff[cnt]);
-
-       /* YRAM IIR coefficient area initialization */
-       add = info->yram + (0x0600 / sizeof(u32));
-       for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++)
-               siu_write32(add, 0);
-
-       siu_write32(base + SIU_TRDAT, port_info->trdat);
-       port_info->trdat = 0x0;
-
-
-       /* SPB start condition: software */
-       siu_write32(base + SIU_SBACTIV, 0);
-       /* Start SPB */
-       siu_write32(base + SIU_SBCTL, 0xc0000000);
-       /* Wait for program to halt */
-       cnt = 0x10000;
-       while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000)
-               cpu_relax();
-
-       if (!cnt)
-               return -EBUSY;
-
-       /* SPB program start address setting */
-       siu_write32(base + SIU_SBPSET, 0x00400000);
-       /* SPB hardware start(FIFOCTL source) */
-       siu_write32(base + SIU_SBACTIV, 0xc0000000);
-
-       return 0;
-}
-
-static void siu_dai_spbstop(struct siu_port *port_info)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-
-       siu_write32(base + SIU_SBACTIV, 0);
-       /* SPB stop */
-       siu_write32(base + SIU_SBCTL, 0);
-
-       port_info->stfifo = 0;
-}
-
-/*             API functions           */
-
-/* Playback and capture hardware properties are identical */
-static const struct snd_pcm_hardware siu_dai_pcm_hw = {
-       .info                   = SNDRV_PCM_INFO_INTERLEAVED,
-       .formats                = SNDRV_PCM_FMTBIT_S16,
-       .rates                  = SNDRV_PCM_RATE_8000_48000,
-       .rate_min               = 8000,
-       .rate_max               = 48000,
-       .channels_min           = 2,
-       .channels_max           = 2,
-       .buffer_bytes_max       = SIU_BUFFER_BYTES_MAX,
-       .period_bytes_min       = SIU_PERIOD_BYTES_MIN,
-       .period_bytes_max       = SIU_PERIOD_BYTES_MAX,
-       .periods_min            = SIU_PERIODS_MIN,
-       .periods_max            = SIU_PERIODS_MAX,
-};
-
-static int siu_dai_info_volume(struct snd_kcontrol *kctrl,
-                              struct snd_ctl_elem_info *uinfo)
-{
-       struct siu_port *port_info = snd_kcontrol_chip(kctrl);
-
-       dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = SIU_MAX_VOLUME;
-
-       return 0;
-}
-
-static int siu_dai_get_volume(struct snd_kcontrol *kctrl,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct siu_port *port_info = snd_kcontrol_chip(kctrl);
-       struct device *dev = port_info->pcm->card->dev;
-       u32 vol;
-
-       dev_dbg(dev, "%s\n", __func__);
-
-       switch (kctrl->private_value) {
-       case VOLUME_PLAYBACK:
-               /* Playback is always on port 0 */
-               vol = port_info->playback.volume;
-               ucontrol->value.integer.value[0] = vol & 0xffff;
-               ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
-               break;
-       case VOLUME_CAPTURE:
-               /* Capture is always on port 1 */
-               vol = port_info->capture.volume;
-               ucontrol->value.integer.value[0] = vol & 0xffff;
-               ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
-               break;
-       default:
-               dev_err(dev, "%s() invalid private_value=%ld\n",
-                       __func__, kctrl->private_value);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int siu_dai_put_volume(struct snd_kcontrol *kctrl,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct siu_port *port_info = snd_kcontrol_chip(kctrl);
-       struct device *dev = port_info->pcm->card->dev;
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-       u32 new_vol;
-       u32 cur_vol;
-
-       dev_dbg(dev, "%s\n", __func__);
-
-       if (ucontrol->value.integer.value[0] < 0 ||
-           ucontrol->value.integer.value[0] > SIU_MAX_VOLUME ||
-           ucontrol->value.integer.value[1] < 0 ||
-           ucontrol->value.integer.value[1] > SIU_MAX_VOLUME)
-               return -EINVAL;
-
-       new_vol = ucontrol->value.integer.value[0] |
-               ucontrol->value.integer.value[1] << 16;
-
-       /* See comment above - DSP firmware implementation */
-       switch (kctrl->private_value) {
-       case VOLUME_PLAYBACK:
-               /* Playback is always on port 0 */
-               cur_vol = port_info->playback.volume;
-               siu_write32(base + SIU_SBDVCA, new_vol);
-               port_info->playback.volume = new_vol;
-               break;
-       case VOLUME_CAPTURE:
-               /* Capture is always on port 1 */
-               cur_vol = port_info->capture.volume;
-               siu_write32(base + SIU_SBDVCB, new_vol);
-               port_info->capture.volume = new_vol;
-               break;
-       default:
-               dev_err(dev, "%s() invalid private_value=%ld\n",
-                       __func__, kctrl->private_value);
-               return -EINVAL;
-       }
-
-       if (cur_vol != new_vol)
-               return 1;
-
-       return 0;
-}
-
-static const struct snd_kcontrol_new playback_controls = {
-       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name           = "PCM Playback Volume",
-       .index          = 0,
-       .info           = siu_dai_info_volume,
-       .get            = siu_dai_get_volume,
-       .put            = siu_dai_put_volume,
-       .private_value  = VOLUME_PLAYBACK,
-};
-
-static const struct snd_kcontrol_new capture_controls = {
-       .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name           = "PCM Capture Volume",
-       .index          = 0,
-       .info           = siu_dai_info_volume,
-       .get            = siu_dai_get_volume,
-       .put            = siu_dai_put_volume,
-       .private_value  = VOLUME_CAPTURE,
-};
-
-int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card)
-{
-       struct device *dev = card->dev;
-       struct snd_kcontrol *kctrl;
-       int ret;
-
-       *port_info = kzalloc(sizeof(**port_info), GFP_KERNEL);
-       if (!*port_info)
-               return -ENOMEM;
-
-       dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info);
-
-       (*port_info)->playback.volume = DFLT_VOLUME_LEVEL;
-       (*port_info)->capture.volume = DFLT_VOLUME_LEVEL;
-
-       /*
-        * Add mixer support. The SPB is used to change the volume. Both
-        * ports use the same SPB. Therefore, we only register one
-        * control instance since it will be used by both channels.
-        * In error case we continue without controls.
-        */
-       kctrl = snd_ctl_new1(&playback_controls, *port_info);
-       ret = snd_ctl_add(card, kctrl);
-       if (ret < 0)
-               dev_err(dev,
-                       "failed to add playback controls %p port=%d err=%d\n",
-                       kctrl, port, ret);
-
-       kctrl = snd_ctl_new1(&capture_controls, *port_info);
-       ret = snd_ctl_add(card, kctrl);
-       if (ret < 0)
-               dev_err(dev,
-                       "failed to add capture controls %p port=%d err=%d\n",
-                       kctrl, port, ret);
-
-       return 0;
-}
-
-void siu_free_port(struct siu_port *port_info)
-{
-       kfree(port_info);
-}
-
-static int siu_dai_startup(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
-{
-       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
-       struct snd_pcm_runtime *rt = substream->runtime;
-       struct siu_port *port_info = siu_port_info(substream);
-       int ret;
-
-       dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
-               info->port_id, port_info);
-
-       snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw);
-
-       ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
-       if (unlikely(ret < 0))
-               return ret;
-
-       siu_dai_start(port_info);
-
-       return 0;
-}
-
-static void siu_dai_shutdown(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
-{
-       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
-       struct siu_port *port_info = siu_port_info(substream);
-
-       dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
-               info->port_id, port_info);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               port_info->play_cap &= ~PLAYBACK_ENABLED;
-       else
-               port_info->play_cap &= ~CAPTURE_ENABLED;
-
-       /* Stop the siu if the other stream is not using it */
-       if (!port_info->play_cap) {
-               /* during stmread or stmwrite ? */
-               if (WARN_ON(port_info->playback.rw_flg || port_info->capture.rw_flg))
-                       return;
-               siu_dai_spbstop(port_info);
-               siu_dai_stop(port_info);
-       }
-}
-
-/* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */
-static int siu_dai_prepare(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
-{
-       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
-       struct snd_pcm_runtime *rt = substream->runtime;
-       struct siu_port *port_info = siu_port_info(substream);
-       struct siu_stream *siu_stream;
-       int self, ret;
-
-       dev_dbg(substream->pcm->card->dev,
-               "%s: port %d, active streams %lx, %d channels\n",
-               __func__, info->port_id, port_info->play_cap, rt->channels);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               self = PLAYBACK_ENABLED;
-               siu_stream = &port_info->playback;
-       } else {
-               self = CAPTURE_ENABLED;
-               siu_stream = &port_info->capture;
-       }
-
-       /* Set up the siu if not already done */
-       if (!port_info->play_cap) {
-               siu_stream->rw_flg = 0; /* stream-data transfer flag */
-
-               siu_dai_spbAselect(port_info);
-               siu_dai_spbBselect(port_info);
-
-               siu_dai_open(siu_stream);
-
-               siu_dai_pcmdatapack(siu_stream);
-
-               ret = siu_dai_spbstart(port_info);
-               if (ret < 0)
-                       goto fail;
-       } else {
-               ret = 0;
-       }
-
-       port_info->play_cap |= self;
-
-fail:
-       return ret;
-}
-
-/*
- * SIU can set bus format to I2S / PCM / SPDIF independently for playback and
- * capture, however, the current API sets the bus format globally for a DAI.
- */
-static int siu_dai_set_fmt(struct snd_soc_dai *dai,
-                          unsigned int fmt)
-{
-       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
-       u32 __iomem *base = info->reg;
-       u32 ifctl;
-
-       dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n",
-               __func__, fmt, info->port_id);
-
-       if (info->port_id < 0)
-               return -ENODEV;
-
-       /* Here select between I2S / PCM / SPDIF */
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               ifctl = siu_flags[info->port_id].playback.i2s |
-                       siu_flags[info->port_id].capture.i2s;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               ifctl = siu_flags[info->port_id].playback.pcm |
-                       siu_flags[info->port_id].capture.pcm;
-               break;
-       /* SPDIF disabled - see comment at the top */
-       default:
-               return -EINVAL;
-       }
-
-       ifctl |= ~(siu_flags[info->port_id].playback.mask |
-                  siu_flags[info->port_id].capture.mask) &
-               siu_read32(base + SIU_IFCTL);
-       siu_write32(base + SIU_IFCTL, ifctl);
-
-       return 0;
-}
-
-static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
-                             unsigned int freq, int dir)
-{
-       struct clk *siu_clk, *parent_clk;
-       char *siu_name, *parent_name;
-       int ret;
-
-       if (dir != SND_SOC_CLOCK_IN)
-               return -EINVAL;
-
-       dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id);
-
-       switch (clk_id) {
-       case SIU_CLKA_PLL:
-               siu_name = "siua_clk";
-               parent_name = "pll_clk";
-               break;
-       case SIU_CLKA_EXT:
-               siu_name = "siua_clk";
-               parent_name = "siumcka_clk";
-               break;
-       case SIU_CLKB_PLL:
-               siu_name = "siub_clk";
-               parent_name = "pll_clk";
-               break;
-       case SIU_CLKB_EXT:
-               siu_name = "siub_clk";
-               parent_name = "siumckb_clk";
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       siu_clk = clk_get(dai->dev, siu_name);
-       if (IS_ERR(siu_clk)) {
-               dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__,
-                       PTR_ERR(siu_clk));
-               return PTR_ERR(siu_clk);
-       }
-
-       parent_clk = clk_get(dai->dev, parent_name);
-       if (IS_ERR(parent_clk)) {
-               ret = PTR_ERR(parent_clk);
-               dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret);
-               goto epclkget;
-       }
-
-       ret = clk_set_parent(siu_clk, parent_clk);
-       if (ret < 0) {
-               dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret);
-               goto eclksetp;
-       }
-
-       ret = clk_set_rate(siu_clk, freq);
-       if (ret < 0)
-               dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret);
-
-       /* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */
-eclksetp:
-       clk_put(parent_clk);
-epclkget:
-       clk_put(siu_clk);
-
-       return ret;
-}
-
-static const struct snd_soc_dai_ops siu_dai_ops = {
-       .startup        = siu_dai_startup,
-       .shutdown       = siu_dai_shutdown,
-       .prepare        = siu_dai_prepare,
-       .set_sysclk     = siu_dai_set_sysclk,
-       .set_fmt        = siu_dai_set_fmt,
-};
-
-static struct snd_soc_dai_driver siu_i2s_dai = {
-       .name   = "siu-i2s-dai",
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .formats = SNDRV_PCM_FMTBIT_S16,
-               .rates = SNDRV_PCM_RATE_8000_48000,
-       },
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .formats = SNDRV_PCM_FMTBIT_S16,
-               .rates = SNDRV_PCM_RATE_8000_48000,
-        },
-       .ops = &siu_dai_ops,
-};
-
-static int siu_probe(struct platform_device *pdev)
-{
-       const struct firmware *fw_entry;
-       struct resource *res, *region;
-       struct siu_info *info;
-       int ret;
-
-       info = devm_kmalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-       siu_i2s_data = info;
-       info->dev = &pdev->dev;
-
-       ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
-       if (ret)
-               return ret;
-
-       /*
-        * Loaded firmware is "const" - read only, but we have to modify it in
-        * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect()
-        */
-       memcpy(&info->fw, fw_entry->data, fw_entry->size);
-
-       release_firmware(fw_entry);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       region = devm_request_mem_region(&pdev->dev, res->start,
-                                        resource_size(res), pdev->name);
-       if (!region) {
-               dev_err(&pdev->dev, "SIU region already claimed\n");
-               return -EBUSY;
-       }
-
-       info->pram = devm_ioremap(&pdev->dev, res->start, PRAM_SIZE);
-       if (!info->pram)
-               return -ENOMEM;
-       info->xram = devm_ioremap(&pdev->dev, res->start + XRAM_OFFSET,
-                                 XRAM_SIZE);
-       if (!info->xram)
-               return -ENOMEM;
-       info->yram = devm_ioremap(&pdev->dev, res->start + YRAM_OFFSET,
-                                 YRAM_SIZE);
-       if (!info->yram)
-               return -ENOMEM;
-       info->reg = devm_ioremap(&pdev->dev, res->start + REG_OFFSET,
-                           resource_size(res) - REG_OFFSET);
-       if (!info->reg)
-               return -ENOMEM;
-
-       dev_set_drvdata(&pdev->dev, info);
-
-       /* register using ARRAY version so we can keep dai name */
-       ret = devm_snd_soc_register_component(&pdev->dev, &siu_component,
-                                             &siu_i2s_dai, 1);
-       if (ret < 0)
-               return ret;
-
-       pm_runtime_enable(&pdev->dev);
-
-       return 0;
-}
-
-static void siu_remove(struct platform_device *pdev)
-{
-       pm_runtime_disable(&pdev->dev);
-}
-
-static struct platform_driver siu_driver = {
-       .driver         = {
-               .name   = "siu-pcm-audio",
-       },
-       .probe          = siu_probe,
-       .remove         = siu_remove,
-};
-
-module_platform_driver(siu_driver);
-
-MODULE_AUTHOR("Carlos Munoz <carlos@kenati.com>");
-MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver");
-MODULE_LICENSE("GPL");
-
-MODULE_FIRMWARE("siu_spb.bin");
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
deleted file mode 100644 (file)
index f15ff36..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
-//
-// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
-// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
-
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <sound/control.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/siu.h>
-
-#include "siu.h"
-
-#define DRV_NAME "siu-i2s"
-#define GET_MAX_PERIODS(buf_bytes, period_bytes) \
-                               ((buf_bytes) / (period_bytes))
-#define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \
-                               ((buf_addr) + ((period_num) * (period_bytes)))
-
-#define RWF_STM_RD             0x01            /* Read in progress */
-#define RWF_STM_WT             0x02            /* Write in progress */
-
-struct siu_port *siu_ports[SIU_PORT_NUM];
-
-/* transfersize is number of u32 dma transfers per period */
-static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-       struct siu_stream *siu_stream = &port_info->playback;
-       u32 stfifo;
-
-       if (!siu_stream->rw_flg)
-               return -EPERM;
-
-       /* output FIFO disable */
-       stfifo = siu_read32(base + SIU_STFIFO);
-       siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18);
-       pr_debug("%s: STFIFO %x -> %x\n", __func__,
-                stfifo, stfifo & ~0x0c180c18);
-
-       /* during stmwrite clear */
-       siu_stream->rw_flg = 0;
-
-       return 0;
-}
-
-static int siu_pcm_stmwrite_start(struct siu_port *port_info)
-{
-       struct siu_stream *siu_stream = &port_info->playback;
-
-       if (siu_stream->rw_flg)
-               return -EPERM;
-
-       /* Current period in buffer */
-       port_info->playback.cur_period = 0;
-
-       /* during stmwrite flag set */
-       siu_stream->rw_flg = RWF_STM_WT;
-
-       /* DMA transfer start */
-       queue_work(system_highpri_wq, &siu_stream->work);
-
-       return 0;
-}
-
-static void siu_dma_tx_complete(void *arg)
-{
-       struct siu_stream *siu_stream = arg;
-
-       if (!siu_stream->rw_flg)
-               return;
-
-       /* Update completed period count */
-       if (++siu_stream->cur_period >=
-           GET_MAX_PERIODS(siu_stream->buf_bytes,
-                           siu_stream->period_bytes))
-               siu_stream->cur_period = 0;
-
-       pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n",
-               __func__, siu_stream->cur_period,
-               siu_stream->cur_period * siu_stream->period_bytes,
-               siu_stream->buf_bytes, siu_stream->cookie);
-
-       queue_work(system_highpri_wq, &siu_stream->work);
-
-       /* Notify alsa: a period is done */
-       snd_pcm_period_elapsed(siu_stream->substream);
-}
-
-static int siu_pcm_wr_set(struct siu_port *port_info,
-                         dma_addr_t buff, u32 size)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-       struct siu_stream *siu_stream = &port_info->playback;
-       struct snd_pcm_substream *substream = siu_stream->substream;
-       struct device *dev = substream->pcm->card->dev;
-       struct dma_async_tx_descriptor *desc;
-       dma_cookie_t cookie;
-       struct scatterlist sg;
-       u32 stfifo;
-
-       sg_init_table(&sg, 1);
-       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
-                   size, offset_in_page(buff));
-       sg_dma_len(&sg) = size;
-       sg_dma_address(&sg) = buff;
-
-       desc = dmaengine_prep_slave_sg(siu_stream->chan,
-               &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               dev_err(dev, "Failed to allocate a dma descriptor\n");
-               return -ENOMEM;
-       }
-
-       desc->callback = siu_dma_tx_complete;
-       desc->callback_param = siu_stream;
-       cookie = dmaengine_submit(desc);
-       if (cookie < 0) {
-               dev_err(dev, "Failed to submit a dma transfer\n");
-               return cookie;
-       }
-
-       siu_stream->tx_desc = desc;
-       siu_stream->cookie = cookie;
-
-       dma_async_issue_pending(siu_stream->chan);
-
-       /* only output FIFO enable */
-       stfifo = siu_read32(base + SIU_STFIFO);
-       siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18));
-       dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
-               stfifo, stfifo | (port_info->stfifo & 0x0c180c18));
-
-       return 0;
-}
-
-static int siu_pcm_rd_set(struct siu_port *port_info,
-                         dma_addr_t buff, size_t size)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-       struct siu_stream *siu_stream = &port_info->capture;
-       struct snd_pcm_substream *substream = siu_stream->substream;
-       struct device *dev = substream->pcm->card->dev;
-       struct dma_async_tx_descriptor *desc;
-       dma_cookie_t cookie;
-       struct scatterlist sg;
-       u32 stfifo;
-
-       dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff);
-
-       sg_init_table(&sg, 1);
-       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
-                   size, offset_in_page(buff));
-       sg_dma_len(&sg) = size;
-       sg_dma_address(&sg) = buff;
-
-       desc = dmaengine_prep_slave_sg(siu_stream->chan,
-               &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               dev_err(dev, "Failed to allocate dma descriptor\n");
-               return -ENOMEM;
-       }
-
-       desc->callback = siu_dma_tx_complete;
-       desc->callback_param = siu_stream;
-       cookie = dmaengine_submit(desc);
-       if (cookie < 0) {
-               dev_err(dev, "Failed to submit dma descriptor\n");
-               return cookie;
-       }
-
-       siu_stream->tx_desc = desc;
-       siu_stream->cookie = cookie;
-
-       dma_async_issue_pending(siu_stream->chan);
-
-       /* only input FIFO enable */
-       stfifo = siu_read32(base + SIU_STFIFO);
-       siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) |
-                   (port_info->stfifo & 0x13071307));
-       dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
-               stfifo, stfifo | (port_info->stfifo & 0x13071307));
-
-       return 0;
-}
-
-static void siu_io_work(struct work_struct *work)
-{
-       struct siu_stream *siu_stream = container_of(work, struct siu_stream,
-                                                    work);
-       struct snd_pcm_substream *substream = siu_stream->substream;
-       struct device *dev = substream->pcm->card->dev;
-       struct snd_pcm_runtime *rt = substream->runtime;
-       struct siu_port *port_info = siu_port_info(substream);
-
-       dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg);
-
-       if (!siu_stream->rw_flg) {
-               dev_dbg(dev, "%s: stream inactive\n", __func__);
-               return;
-       }
-
-       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               dma_addr_t buff;
-               size_t count;
-
-               buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
-                                               siu_stream->cur_period,
-                                               siu_stream->period_bytes);
-               count = siu_stream->period_bytes;
-
-               /* DMA transfer start */
-               siu_pcm_rd_set(port_info, buff, count);
-       } else {
-               siu_pcm_wr_set(port_info,
-                              (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
-                                               siu_stream->cur_period,
-                                               siu_stream->period_bytes),
-                              siu_stream->period_bytes);
-       }
-}
-
-/* Capture */
-static int siu_pcm_stmread_start(struct siu_port *port_info)
-{
-       struct siu_stream *siu_stream = &port_info->capture;
-
-       if (siu_stream->xfer_cnt > 0x1000000)
-               return -EINVAL;
-       if (siu_stream->rw_flg)
-               return -EPERM;
-
-       /* Current period in buffer */
-       siu_stream->cur_period = 0;
-
-       /* during stmread flag set */
-       siu_stream->rw_flg = RWF_STM_RD;
-
-       queue_work(system_highpri_wq, &siu_stream->work);
-
-       return 0;
-}
-
-static int siu_pcm_stmread_stop(struct siu_port *port_info)
-{
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-       struct siu_stream *siu_stream = &port_info->capture;
-       struct device *dev = siu_stream->substream->pcm->card->dev;
-       u32 stfifo;
-
-       if (!siu_stream->rw_flg)
-               return -EPERM;
-
-       /* input FIFO disable */
-       stfifo = siu_read32(base + SIU_STFIFO);
-       siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307);
-       dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
-               stfifo, stfifo & ~0x13071307);
-
-       /* during stmread flag clear */
-       siu_stream->rw_flg = 0;
-
-       return 0;
-}
-
-static bool filter(struct dma_chan *chan, void *secondary)
-{
-       struct sh_dmae_slave *param = secondary;
-
-       pr_debug("%s: secondary ID %d\n", __func__, param->shdma_slave.slave_id);
-
-       chan->private = &param->shdma_slave;
-       return true;
-}
-
-static int siu_pcm_open(struct snd_soc_component *component,
-                       struct snd_pcm_substream *ss)
-{
-       /* Playback / Capture */
-       struct siu_platform *pdata = component->dev->platform_data;
-       struct siu_info *info = siu_i2s_data;
-       struct siu_port *port_info = siu_port_info(ss);
-       struct siu_stream *siu_stream;
-       u32 port = info->port_id;
-       struct device *dev = ss->pcm->card->dev;
-       dma_cap_mask_t mask;
-       struct sh_dmae_slave *param;
-
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info);
-
-       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               siu_stream = &port_info->playback;
-               param = &siu_stream->param;
-               param->shdma_slave.slave_id = port ? pdata->dma_slave_tx_b :
-                       pdata->dma_slave_tx_a;
-       } else {
-               siu_stream = &port_info->capture;
-               param = &siu_stream->param;
-               param->shdma_slave.slave_id = port ? pdata->dma_slave_rx_b :
-                       pdata->dma_slave_rx_a;
-       }
-
-       /* Get DMA channel */
-       siu_stream->chan = dma_request_channel(mask, filter, param);
-       if (!siu_stream->chan) {
-               dev_err(dev, "DMA channel allocation failed!\n");
-               return -EBUSY;
-       }
-
-       siu_stream->substream = ss;
-
-       return 0;
-}
-
-static int siu_pcm_close(struct snd_soc_component *component,
-                        struct snd_pcm_substream *ss)
-{
-       struct siu_info *info = siu_i2s_data;
-       struct device *dev = ss->pcm->card->dev;
-       struct siu_port *port_info = siu_port_info(ss);
-       struct siu_stream *siu_stream;
-
-       dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
-
-       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               siu_stream = &port_info->playback;
-       else
-               siu_stream = &port_info->capture;
-
-       dma_release_channel(siu_stream->chan);
-       siu_stream->chan = NULL;
-
-       siu_stream->substream = NULL;
-
-       return 0;
-}
-
-static int siu_pcm_prepare(struct snd_soc_component *component,
-                          struct snd_pcm_substream *ss)
-{
-       struct siu_info *info = siu_i2s_data;
-       struct siu_port *port_info = siu_port_info(ss);
-       struct device *dev = ss->pcm->card->dev;
-       struct snd_pcm_runtime *rt;
-       struct siu_stream *siu_stream;
-       snd_pcm_sframes_t xfer_cnt;
-
-       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               siu_stream = &port_info->playback;
-       else
-               siu_stream = &port_info->capture;
-
-       rt = siu_stream->substream->runtime;
-
-       siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss);
-       siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss);
-
-       dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__,
-               info->port_id, rt->channels, siu_stream->period_bytes);
-
-       /* We only support buffers that are multiples of the period */
-       if (siu_stream->buf_bytes % siu_stream->period_bytes) {
-               dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n",
-                      __func__, siu_stream->buf_bytes,
-                      siu_stream->period_bytes);
-               return -EINVAL;
-       }
-
-       xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes);
-       if (!xfer_cnt || xfer_cnt > 0x1000000)
-               return -EINVAL;
-
-       siu_stream->format = rt->format;
-       siu_stream->xfer_cnt = xfer_cnt;
-
-       dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d "
-               "format=%d channels=%d xfer_cnt=%d\n", info->port_id,
-               (unsigned long)rt->dma_addr, siu_stream->buf_bytes,
-               siu_stream->period_bytes,
-               siu_stream->format, rt->channels, (int)xfer_cnt);
-
-       return 0;
-}
-
-static int siu_pcm_trigger(struct snd_soc_component *component,
-                          struct snd_pcm_substream *ss, int cmd)
-{
-       struct siu_info *info = siu_i2s_data;
-       struct device *dev = ss->pcm->card->dev;
-       struct siu_port *port_info = siu_port_info(ss);
-       int ret;
-
-       dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__,
-               info->port_id, port_info, cmd);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       ret = siu_pcm_stmwrite_start(port_info);
-               else
-                       ret = siu_pcm_stmread_start(port_info);
-
-               if (ret < 0)
-                       dev_warn(dev, "%s: start failed on port=%d\n",
-                                __func__, info->port_id);
-
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       siu_pcm_stmwrite_stop(port_info);
-               else
-                       siu_pcm_stmread_stop(port_info);
-               ret = 0;
-
-               break;
-       default:
-               dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd);
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-/*
- * So far only resolution of one period is supported, subject to extending the
- * dmangine API
- */
-static snd_pcm_uframes_t
-siu_pcm_pointer_dma(struct snd_soc_component *component,
-                   struct snd_pcm_substream *ss)
-{
-       struct device *dev = ss->pcm->card->dev;
-       struct siu_info *info = siu_i2s_data;
-       u32 __iomem *base = info->reg;
-       struct siu_port *port_info = siu_port_info(ss);
-       struct snd_pcm_runtime *rt = ss->runtime;
-       size_t ptr;
-       struct siu_stream *siu_stream;
-
-       if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               siu_stream = &port_info->playback;
-       else
-               siu_stream = &port_info->capture;
-
-       /*
-        * ptr is the offset into the buffer where the dma is currently at. We
-        * check if the dma buffer has just wrapped.
-        */
-       ptr = PERIOD_OFFSET(rt->dma_addr,
-                           siu_stream->cur_period,
-                           siu_stream->period_bytes) - rt->dma_addr;
-
-       dev_dbg(dev,
-               "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n",
-               __func__, info->port_id, siu_read32(base + SIU_EVNTC),
-               siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes,
-               siu_stream->cookie);
-
-       if (ptr >= siu_stream->buf_bytes)
-               ptr = 0;
-
-       return bytes_to_frames(ss->runtime, ptr);
-}
-
-static int siu_pcm_new(struct snd_soc_component *component,
-                      struct snd_soc_pcm_runtime *rtd)
-{
-       /* card->dev == socdev->dev, see snd_soc_new_pcms() */
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       struct siu_info *info = siu_i2s_data;
-       struct platform_device *pdev = to_platform_device(card->dev);
-       int ret;
-       int i;
-
-       /* pdev->id selects between SIUA and SIUB */
-       if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM)
-               return -EINVAL;
-
-       info->port_id = pdev->id;
-
-       /*
-        * While the siu has 2 ports, only one port can be on at a time (only 1
-        * SPB). So far all the boards using the siu had only one of the ports
-        * wired to a codec. To simplify things, we only register one port with
-        * alsa. In case both ports are needed, it should be changed here
-        */
-       for (i = pdev->id; i < pdev->id + 1; i++) {
-               struct siu_port **port_info = &siu_ports[i];
-
-               ret = siu_init_port(i, port_info, card);
-               if (ret < 0)
-                       return ret;
-
-               snd_pcm_set_managed_buffer_all(pcm,
-                               SNDRV_DMA_TYPE_DEV, card->dev,
-                               SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX);
-
-               (*port_info)->pcm = pcm;
-
-               /* IO works */
-               INIT_WORK(&(*port_info)->playback.work, siu_io_work);
-               INIT_WORK(&(*port_info)->capture.work, siu_io_work);
-       }
-
-       dev_info(card->dev, "SuperH SIU driver initialized.\n");
-       return 0;
-}
-
-static void siu_pcm_free(struct snd_soc_component *component,
-                        struct snd_pcm *pcm)
-{
-       struct platform_device *pdev = to_platform_device(pcm->card->dev);
-       struct siu_port *port_info = siu_ports[pdev->id];
-
-       cancel_work_sync(&port_info->capture.work);
-       cancel_work_sync(&port_info->playback.work);
-
-       siu_free_port(port_info);
-
-       dev_dbg(pcm->card->dev, "%s\n", __func__);
-}
-
-const struct snd_soc_component_driver siu_component = {
-       .name                   = DRV_NAME,
-       .open                   = siu_pcm_open,
-       .close                  = siu_pcm_close,
-       .prepare                = siu_pcm_prepare,
-       .trigger                = siu_pcm_trigger,
-       .pointer                = siu_pcm_pointer_dma,
-       .pcm_construct          = siu_pcm_new,
-       .pcm_destruct           = siu_pcm_free,
-       .legacy_dai_naming      = 1,
-};
-EXPORT_SYMBOL_GPL(siu_component);
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
deleted file mode 100644 (file)
index 96cf523..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Serial Sound Interface (I2S) support for SH7760/SH7780
-//
-// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
-//
-// dont forget to set IPSEL/OMSEL register bits (in your board code) to
-// enable SSI output pins!
-
-/*
- * LIMITATIONS:
- *     The SSI unit has only one physical data line, so full duplex is
- *     impossible.  This can be remedied  on the  SH7760 by  using the
- *     other SSI unit for recording; however the SH7780 has only 1 SSI
- *     unit, and its pins are shared with the AC97 unit,  among others.
- *
- * FEATURES:
- *     The SSI features "compressed mode": in this mode it continuously
- *     streams PCM data over the I2S lines and uses LRCK as a handshake
- *     signal.  Can be used to send compressed data (AC3/DTS) to a DSP.
- *     The number of bits sent over the wire in a frame can be adjusted
- *     and can be independent from the actual sample bit depth. This is
- *     useful to support TDM mode codecs like the AD1939 which have a
- *     fixed TDM slot size, regardless of sample resolution.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <asm/io.h>
-
-#define SSICR  0x00
-#define SSISR  0x04
-
-#define CR_DMAEN       (1 << 28)
-#define CR_CHNL_SHIFT  22
-#define CR_CHNL_MASK   (3 << CR_CHNL_SHIFT)
-#define CR_DWL_SHIFT   19
-#define CR_DWL_MASK    (7 << CR_DWL_SHIFT)
-#define CR_SWL_SHIFT   16
-#define CR_SWL_MASK    (7 << CR_SWL_SHIFT)
-#define CR_SCK_MASTER  (1 << 15)       /* bitclock master bit */
-#define CR_SWS_MASTER  (1 << 14)       /* wordselect master bit */
-#define CR_SCKP                (1 << 13)       /* I2Sclock polarity */
-#define CR_SWSP                (1 << 12)       /* LRCK polarity */
-#define CR_SPDP                (1 << 11)
-#define CR_SDTA                (1 << 10)       /* i2s alignment (msb/lsb) */
-#define CR_PDTA                (1 << 9)        /* fifo data alignment */
-#define CR_DEL         (1 << 8)        /* delay data by 1 i2sclk */
-#define CR_BREN                (1 << 7)        /* clock gating in burst mode */
-#define CR_CKDIV_SHIFT 4
-#define CR_CKDIV_MASK  (7 << CR_CKDIV_SHIFT)   /* bitclock divider */
-#define CR_MUTE                (1 << 3)        /* SSI mute */
-#define CR_CPEN                (1 << 2)        /* compressed mode */
-#define CR_TRMD                (1 << 1)        /* transmit/receive select */
-#define CR_EN          (1 << 0)        /* enable SSI */
-
-#define SSIREG(reg)    (*(unsigned long *)(ssi->mmio + (reg)))
-
-struct ssi_priv {
-       unsigned long mmio;
-       unsigned long sysclk;
-       int inuse;
-} ssi_cpu_data[] = {
-#if defined(CONFIG_CPU_SUBTYPE_SH7760)
-       {
-               .mmio   = 0xFE680000,
-       },
-       {
-               .mmio   = 0xFE690000,
-       },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-       {
-               .mmio   = 0xFFE70000,
-       },
-#else
-#error "Unsupported SuperH SoC"
-#endif
-};
-
-/*
- * track usage of the SSI; it is simplex-only so prevent attempts of
- * concurrent playback + capture. FIXME: any locking required?
- */
-static int ssi_startup(struct snd_pcm_substream *substream,
-                      struct snd_soc_dai *dai)
-{
-       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
-       if (ssi->inuse) {
-               pr_debug("ssi: already in use!\n");
-               return -EBUSY;
-       } else
-               ssi->inuse = 1;
-       return 0;
-}
-
-static void ssi_shutdown(struct snd_pcm_substream *substream,
-                        struct snd_soc_dai *dai)
-{
-       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
-
-       ssi->inuse = 0;
-}
-
-static int ssi_trigger(struct snd_pcm_substream *substream, int cmd,
-                      struct snd_soc_dai *dai)
-{
-       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               SSIREG(SSICR) |= CR_DMAEN | CR_EN;
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int ssi_hw_params(struct snd_pcm_substream *substream,
-                        struct snd_pcm_hw_params *params,
-                        struct snd_soc_dai *dai)
-{
-       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
-       unsigned long ssicr = SSIREG(SSICR);
-       unsigned int bits, channels, swl, recv, i;
-
-       channels = params_channels(params);
-       bits = params->msbits;
-       recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
-
-       pr_debug("ssi_hw_params() enter\nssicr was    %08lx\n", ssicr);
-       pr_debug("bits: %u channels: %u\n", bits, channels);
-
-       ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
-                  CR_SWL_MASK);
-
-       /* direction (send/receive) */
-       if (!recv)
-               ssicr |= CR_TRMD;       /* transmit */
-
-       /* channels */
-       if ((channels < 2) || (channels > 8) || (channels & 1)) {
-               pr_debug("ssi: invalid number of channels\n");
-               return -EINVAL;
-       }
-       ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT;
-
-       /* DATA WORD LENGTH (DWL): databits in audio sample */
-       i = 0;
-       switch (bits) {
-       case 32: ++i;
-       case 24: ++i;
-       case 22: ++i;
-       case 20: ++i;
-       case 18: ++i;
-       case 16: ++i;
-                ssicr |= i << CR_DWL_SHIFT;
-       case 8:  break;
-       default:
-               pr_debug("ssi: invalid sample width\n");
-               return -EINVAL;
-       }
-
-       /*
-        * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S
-        * wires. This is usually bits_per_sample x channels/2;  i.e. in
-        * Stereo mode  the SWL equals DWL.  SWL can  be bigger than the
-        * product of (channels_per_slot x samplebits), e.g.  for codecs
-        * like the AD1939 which  only accept 32bit wide TDM slots.  For
-        * "standard" I2S operation we set SWL = chans / 2 * DWL here.
-        * Waiting for ASoC to get TDM support ;-)
-        */
-       if ((bits > 16) && (bits <= 24)) {
-               bits = 24;      /* these are padded by the SSI */
-               /*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */
-       }
-       i = 0;
-       swl = (bits * channels) / 2;
-       switch (swl) {
-       case 256: ++i;
-       case 128: ++i;
-       case 64:  ++i;
-       case 48:  ++i;
-       case 32:  ++i;
-       case 16:  ++i;
-                 ssicr |= i << CR_SWL_SHIFT;
-       case 8:   break;
-       default:
-               pr_debug("ssi: invalid system word length computed\n");
-               return -EINVAL;
-       }
-
-       SSIREG(SSICR) = ssicr;
-
-       pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr);
-       return 0;
-}
-
-static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
-                         unsigned int freq, int dir)
-{
-       struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
-
-       ssi->sysclk = freq;
-
-       return 0;
-}
-
-/*
- * This divider is used to generate the SSI_SCK (I2S bitclock) from the
- * clock at the HAC_BIT_CLK ("oversampling clock") pin.
- */
-static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div)
-{
-       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
-       unsigned long ssicr;
-       int i;
-
-       i = 0;
-       ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK;
-       switch (div) {
-       case 16: ++i;
-       case 8:  ++i;
-       case 4:  ++i;
-       case 2:  ++i;
-                SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT);
-       case 1:  break;
-       default:
-               pr_debug("ssi: invalid sck divider %d\n", div);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
-       unsigned long ssicr = SSIREG(SSICR);
-
-       pr_debug("ssi_set_fmt()\nssicr was    0x%08lx\n", ssicr);
-
-       ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP |
-                  CR_SWS_MASTER | CR_SCK_MASTER);
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_I2S:
-               break;
-       case SND_SOC_DAIFMT_RIGHT_J:
-               ssicr |= CR_DEL | CR_PDTA;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               ssicr |= CR_DEL;
-               break;
-       default:
-               pr_debug("ssi: unsupported format\n");
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
-       case SND_SOC_DAIFMT_CONT:
-               break;
-       case SND_SOC_DAIFMT_GATED:
-               ssicr |= CR_BREN;
-               break;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               ssicr |= CR_SCKP;       /* sample data at low clkedge */
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               ssicr |= CR_SCKP | CR_SWSP;
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               break;
-       case SND_SOC_DAIFMT_IB_IF:
-               ssicr |= CR_SWSP;       /* word select starts low */
-               break;
-       default:
-               pr_debug("ssi: invalid inversion\n");
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_BC_FC:
-               break;
-       case SND_SOC_DAIFMT_BP_FC:
-               ssicr |= CR_SCK_MASTER;
-               break;
-       case SND_SOC_DAIFMT_BC_FP:
-               ssicr |= CR_SWS_MASTER;
-               break;
-       case SND_SOC_DAIFMT_BP_FP:
-               ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
-               break;
-       default:
-               pr_debug("ssi: invalid master/secondary configuration\n");
-               return -EINVAL;
-       }
-
-       SSIREG(SSICR) = ssicr;
-       pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr);
-
-       return 0;
-}
-
-/* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in
- * Master mode,  so really this is board specific;  the SSI can do any
- * rate with the right bitclk and divider settings.
- */
-#define SSI_RATES      \
-       SNDRV_PCM_RATE_8000_192000
-
-/* the SSI can do 8-32 bit samples, with 8 possible channels */
-#define SSI_FMTS       \
-       (SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |  \
-        SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |  \
-        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |  \
-        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |  \
-        SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
-
-static const struct snd_soc_dai_ops ssi_dai_ops = {
-       .startup        = ssi_startup,
-       .shutdown       = ssi_shutdown,
-       .trigger        = ssi_trigger,
-       .hw_params      = ssi_hw_params,
-       .set_sysclk     = ssi_set_sysclk,
-       .set_clkdiv     = ssi_set_clkdiv,
-       .set_fmt        = ssi_set_fmt,
-};
-
-static struct snd_soc_dai_driver sh4_ssi_dai[] = {
-{
-       .name                   = "ssi-dai.0",
-       .playback = {
-               .rates          = SSI_RATES,
-               .formats        = SSI_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 8,
-       },
-       .capture = {
-               .rates          = SSI_RATES,
-               .formats        = SSI_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 8,
-       },
-       .ops = &ssi_dai_ops,
-},
-#ifdef CONFIG_CPU_SUBTYPE_SH7760
-{
-       .name                   = "ssi-dai.1",
-       .playback = {
-               .rates          = SSI_RATES,
-               .formats        = SSI_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 8,
-       },
-       .capture = {
-               .rates          = SSI_RATES,
-               .formats        = SSI_FMTS,
-               .channels_min   = 2,
-               .channels_max   = 8,
-       },
-       .ops = &ssi_dai_ops,
-},
-#endif
-};
-
-static const struct snd_soc_component_driver sh4_ssi_component = {
-       .name                   = "sh4-ssi",
-       .legacy_dai_naming      = 1,
-};
-
-static int sh4_soc_dai_probe(struct platform_device *pdev)
-{
-       return devm_snd_soc_register_component(&pdev->dev, &sh4_ssi_component,
-                                              sh4_ssi_dai,
-                                              ARRAY_SIZE(sh4_ssi_dai));
-}
-
-static struct platform_driver sh4_ssi_driver = {
-       .driver = {
-                       .name = "sh4-ssi-dai",
-       },
-
-       .probe = sh4_soc_dai_probe,
-};
-
-module_platform_driver(sh4_ssi_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
-MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");