diff options
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/Kconfig | 75 | ||||
-rw-r--r-- | sound/soc/sh/Makefile | 28 | ||||
-rw-r--r-- | sound/soc/sh/dma-sh7760.c | 334 | ||||
-rw-r--r-- | sound/soc/sh/fsi.c | 2119 | ||||
-rw-r--r-- | sound/soc/sh/hac.c | 344 | ||||
-rw-r--r-- | sound/soc/sh/migor.c | 205 | ||||
-rw-r--r-- | sound/soc/sh/rcar/Makefile | 3 | ||||
-rw-r--r-- | sound/soc/sh/rcar/adg.c | 775 | ||||
-rw-r--r-- | sound/soc/sh/rcar/cmd.c | 195 | ||||
-rw-r--r-- | sound/soc/sh/rcar/core.c | 2114 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ctu.c | 393 | ||||
-rw-r--r-- | sound/soc/sh/rcar/debugfs.c | 96 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dma.c | 946 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dvc.c | 396 | ||||
-rw-r--r-- | sound/soc/sh/rcar/gen.c | 562 | ||||
-rw-r--r-- | sound/soc/sh/rcar/mix.c | 360 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 916 | ||||
-rw-r--r-- | sound/soc/sh/rcar/src.c | 736 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 1260 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssiu.c | 609 | ||||
-rw-r--r-- | sound/soc/sh/rz-ssi.c | 1107 | ||||
-rw-r--r-- | sound/soc/sh/sh7760-ac97.c | 72 | ||||
-rw-r--r-- | sound/soc/sh/siu.h | 180 | ||||
-rw-r--r-- | sound/soc/sh/siu_dai.c | 800 | ||||
-rw-r--r-- | sound/soc/sh/siu_pcm.c | 553 | ||||
-rw-r--r-- | sound/soc/sh/ssi.c | 403 |
26 files changed, 0 insertions, 15581 deletions
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig deleted file mode 100644 index 7bddfd5e38d6..000000000000 --- a/sound/soc/sh/Kconfig +++ /dev/null @@ -1,75 +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 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 index f6fd79948f6a..000000000000 --- a/sound/soc/sh/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -## DMA engines -snd-soc-dma-sh7760-objs := dma-sh7760.o -obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o - -## audio units found on some SH-4 -snd-soc-hac-objs := hac.o -snd-soc-ssi-objs := ssi.o -snd-soc-fsi-objs := fsi.o -snd-soc-siu-objs := 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-objs := sh7760-ac97.o -snd-soc-migor-objs := 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-objs := 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 index c53539482c20..000000000000 --- a/sound/soc/sh/dma-sh7760.c +++ /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 index 84601ba43b7d..000000000000 --- a/sound/soc/sh/fsi.c +++ /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 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_new = 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 index cc200f45826c..000000000000 --- a/sound/soc/sh/hac.c +++ /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_new = 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 index 5a0bc6edac0a..000000000000 --- a/sound/soc/sh/migor.c +++ /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 index d07eccfa3ac2..000000000000 --- a/sound/soc/sh/rcar/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -snd-soc-rcar-objs := 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 index afd69c6eb654..000000000000 --- a/sound/soc/sh/rcar/adg.c +++ /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_confirm_src(src_mod); - - 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_confirm_ssi(ssi_mod); - - 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 index 329e6ab1b222..000000000000 --- a/sound/soc/sh/rcar/cmd.c +++ /dev/null @@ -1,195 +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_GEN2_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; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - /* 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 index 0b1aa23c1189..000000000000 --- a/sound/soc/sh/rcar/core.c +++ /dev/null @@ -1,2114 +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); -} - -/* - * rsnd_soc_dai functions - */ -void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) -{ - struct snd_pcm_substream *substream = io->substream; - - /* - * this function should be called... - * - * - if rsnd_dai_pointer_update() returns true - * - without spin lock - */ - - snd_pcm_period_elapsed(substream); -} - -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 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 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) { - if (!of_node_name_eq(ports, "ports") && - !of_node_name_eq(ports, "port")) - continue; - priv->component_dais[i] = of_graph_get_endpoint_count(ports); - 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 *ports; - struct device_node *dai_np; - - for_each_child_of_node(np, ports) { - if (!of_node_name_eq(ports, "ports") && - !of_node_name_eq(ports, "port")) - continue; - for_each_endpoint_of_node(ports, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(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_gen3(priv) || rsnd_is_gen4(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_new = 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 index e39eb2ac7e95..000000000000 --- a/sound/soc/sh/rcar/ctu.c +++ /dev/null @@ -1,393 +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_GEN2_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; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - 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 index 26d3b310b9db..000000000000 --- a/sound/soc/sh/rcar/debugfs.c +++ /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 index 1c494e521463..000000000000 --- a/sound/soc/sh/rcar/dma.c +++ /dev/null @@ -1,946 +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 "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; - dma_cookie_t cookie; - unsigned int dma_len; -}; - -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 void __rsnd_dmaen_complete(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - if (rsnd_io_is_working(io)) - rsnd_dai_period_elapsed(io); -} - -static void rsnd_dmaen_complete(void *data) -{ - struct rsnd_mod *mod = data; - - rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); -} - -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) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - if (dmaen->chan) - dmaengine_terminate_async(dmaen->chan); - - return 0; -} - -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) - dma_release_channel(dmaen->chan); - - 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 0; -} - -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 snd_pcm_substream *substream = io->substream; - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_async_tx_descriptor *desc; - struct dma_slave_config cfg = {}; - enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; - int is_play = rsnd_io_is_play(io); - 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 = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - 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; - - desc = dmaengine_prep_dma_cyclic(dmaen->chan, - substream->runtime->dma_addr, - snd_pcm_lib_buffer_bytes(substream), - snd_pcm_lib_period_bytes(substream), - is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - - if (!desc) { - dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); - return -EIO; - } - - desc->callback = rsnd_dmaen_complete; - desc->callback_param = rsnd_mod_get(dma); - - dmaen->dma_len = snd_pcm_lib_buffer_bytes(substream); - - dmaen->cookie = dmaengine_submit(desc); - if (dmaen->cookie < 0) { - dev_err(dev, "dmaengine_submit() fail\n"); - return -EIO; - } - - dma_async_issue_pending(dmaen->chan); - - return 0; -} - -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) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct dma_tx_state state; - enum dma_status status; - unsigned int pos = 0; - - status = dmaengine_tx_status(dmaen->chan, dmaen->cookie, &state); - if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) { - if (state.residue > 0 && state.residue <= dmaen->dma_len) - pos = dmaen->dma_len - state.residue; - } - *pointer = bytes_to_frames(runtime, pos); - - 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_GEN2_SSI); - phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_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_GEN4_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 index 16befcbc312c..000000000000 --- a/sound/soc/sh/rcar/dvc.c +++ /dev/null @@ -1,396 +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_GEN2_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; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - 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 index 86bdecc24956..000000000000 --- a/sound/soc/sh/rcar/gen.c +++ /dev/null @@ -1,562 +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(®c, 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) - res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id); - 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, ®c); - 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; -} - -/* - * Gen4 - */ -static int rsnd_gen4_probe(struct rsnd_priv *priv) -{ - static const struct rsnd_regmap_field_conf conf_ssiu[] = { - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898), - RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840), - RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848), - RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880), - RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), - - RSND_GEN_S_REG(SSI_BUSIF0_MODE, 0x0), - RSND_GEN_S_REG(SSI_BUSIF0_ADINR, 0x4), - RSND_GEN_S_REG(SSI_BUSIF0_DALIGN, 0x8), - RSND_GEN_S_REG(SSI_BUSIF1_MODE, 0x20), - RSND_GEN_S_REG(SSI_BUSIF1_ADINR, 0x24), - RSND_GEN_S_REG(SSI_BUSIF1_DALIGN, 0x28), - RSND_GEN_S_REG(SSI_BUSIF2_MODE, 0x40), - RSND_GEN_S_REG(SSI_BUSIF2_ADINR, 0x44), - RSND_GEN_S_REG(SSI_BUSIF2_DALIGN, 0x48), - RSND_GEN_S_REG(SSI_BUSIF3_MODE, 0x60), - RSND_GEN_S_REG(SSI_BUSIF3_ADINR, 0x64), - RSND_GEN_S_REG(SSI_BUSIF3_DALIGN, 0x68), - RSND_GEN_S_REG(SSI_BUSIF4_MODE, 0x500), - RSND_GEN_S_REG(SSI_BUSIF4_ADINR, 0x504), - RSND_GEN_S_REG(SSI_BUSIF4_DALIGN, 0x508), - RSND_GEN_S_REG(SSI_BUSIF5_MODE, 0x520), - RSND_GEN_S_REG(SSI_BUSIF5_ADINR, 0x524), - RSND_GEN_S_REG(SSI_BUSIF5_DALIGN, 0x528), - RSND_GEN_S_REG(SSI_BUSIF6_MODE, 0x540), - RSND_GEN_S_REG(SSI_BUSIF6_ADINR, 0x544), - RSND_GEN_S_REG(SSI_BUSIF6_DALIGN, 0x548), - RSND_GEN_S_REG(SSI_BUSIF7_MODE, 0x560), - RSND_GEN_S_REG(SSI_BUSIF7_ADINR, 0x564), - RSND_GEN_S_REG(SSI_BUSIF7_DALIGN, 0x568), - RSND_GEN_S_REG(SSI_CTRL, 0x010), - RSND_GEN_S_REG(SSI_INT_ENABLE, 0x018), - RSND_GEN_S_REG(SSI_MODE, 0x00c), - RSND_GEN_S_REG(SSI_MODE2, 0xa0c), - }; - static const struct rsnd_regmap_field_conf conf_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), - }; - static const struct rsnd_regmap_field_conf conf_ssi[] = { - RSND_GEN_S_REG(SSICR, 0x00), - RSND_GEN_S_REG(SSISR, 0x04), - RSND_GEN_S_REG(SSITDR, 0x08), - RSND_GEN_S_REG(SSIRDR, 0x0c), - RSND_GEN_S_REG(SSIWSR, 0x20), - }; - static const struct rsnd_regmap_field_conf conf_sdmc[] = { - RSND_GEN_M_REG(SSI_BUSIF, 0x0, 0x8000), - }; - int ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_ADG, "adg", conf_adg); - int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSIU, "ssiu", conf_ssiu); - int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSI, "ssi", conf_ssi); - int ret_sdmc = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SDMC, "sdmc", conf_sdmc); - - return ret_adg | ret_ssiu | ret_ssi | ret_sdmc; -} - -/* - * Gen2 - */ -static int rsnd_gen2_probe(struct rsnd_priv *priv) -{ - static const struct rsnd_regmap_field_conf conf_ssiu[] = { - RSND_GEN_S_REG(SSI_MODE0, 0x800), - RSND_GEN_S_REG(SSI_MODE1, 0x804), - RSND_GEN_S_REG(SSI_MODE2, 0x808), - 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), - - /* FIXME: it needs SSI_MODE2/3 in the future */ - 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_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_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_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), - }; - int ret_ssiu; - int ret_scu; - int ret_adg; - int ret_ssi; - - ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, "ssiu", conf_ssiu); - ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, "scu", conf_scu); - ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, "adg", conf_adg); - ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI, "ssi", conf_ssi); - if (ret_ssiu < 0 || - ret_scu < 0 || - ret_adg < 0 || - ret_ssi < 0) - return ret_ssiu | ret_scu | ret_adg | ret_ssi; - - return 0; -} - -/* - * Gen1 - */ - -static int rsnd_gen1_probe(struct rsnd_priv *priv) -{ - static const struct rsnd_regmap_field_conf conf_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), - }; - static const struct rsnd_regmap_field_conf conf_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), - }; - int ret_adg; - int ret_ssi; - - ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg); - ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi); - if (ret_adg < 0 || - ret_ssi < 0) - return ret_adg | ret_ssi; - - return 0; -} - -/* - * 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 index 1de0e085804c..000000000000 --- a/sound/soc/sh/rcar/mix.c +++ /dev/null @@ -1,360 +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_GEN2_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; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - 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 index da716b1f52e4..000000000000 --- a/sound/soc/sh/rcar/rsnd.h +++ /dev/null @@ -1,916 +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_GEN1_SRU 0 -#define RSND_GEN1_ADG 1 -#define RSND_GEN1_SSI 2 - -#define RSND_GEN2_SCU 0 -#define RSND_GEN2_ADG 1 -#define RSND_GEN2_SSIU 2 -#define RSND_GEN2_SSI 3 - -#define RSND_GEN4_ADG 0 -#define RSND_GEN4_SSIU 1 -#define RSND_GEN4_SSI 2 -#define RSND_GEN4_SDMC 3 - -#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, - SSI_BUSIF, - 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); -void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); -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_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); -#ifdef DEBUG -#define rsnd_mod_confirm_ssi(mssi) rsnd_mod_make_sure(mssi, RSND_MOD_SSI) -#define rsnd_mod_confirm_src(msrc) rsnd_mod_make_sure(msrc, RSND_MOD_SRC) -#define rsnd_mod_confirm_dvc(mdvc) rsnd_mod_make_sure(mdvc, RSND_MOD_DVC) -#else -#define rsnd_mod_confirm_ssi(mssi) -#define rsnd_mod_confirm_src(msrc) -#define rsnd_mod_confirm_dvc(mdvc) -#endif - -/* - * 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 index 3241a1bdc9ea..000000000000 --- a/sound/soc/sh/rcar/src.c +++ /dev/null @@ -1,736 +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_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_GEN2_SCU, - rsnd_mod_id(mod) * 0x20, 0x20); - seq_puts(m, "\n"); - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, - 0x1c0, 0x20); - seq_puts(m, "\n"); - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_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; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - 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 index 0a46aa1975fa..000000000000 --- a/sound/soc/sh/rcar/ssi.c +++ /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) - rsnd_dai_period_elapsed(io); - - 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_GEN2_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 index 17bd8cc86dd0..000000000000 --- a/sound/soc/sh/rcar/ssiu.c +++ /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_GEN2_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 index 9d103646973a..000000000000 --- a/sound/soc/sh/rz-ssi.c +++ /dev/null @@ -1,1107 +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 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; -}; - -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 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_TFRST | SSIFCR_RFRST)); - - return 0; -} - -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); - u32 ssicr, ssifcr; - - ssicr = rz_ssi_reg_readl(ssi, SSICR); - ssifcr = rz_ssi_reg_readl(ssi, SSIFCR) & ~0xF; - - /* 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 | SSIFCR_RFRST; - } else { - ssicr |= SSICR_RUIEN | SSICR_ROIEN; - ssifcr |= SSIFCR_RIE | 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; - 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) -{ - int timeout; - - strm->running = 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); - - /* 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_TFRST | SSIFCR_RFRST); - - 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 = NULL; - struct rz_ssi_priv *ssi = data; - u32 ssisr = rz_ssi_reg_readl(ssi, SSISR); - - if (ssi->playback.substream) - strm = &ssi->playback; - else if (ssi->capture.substream) - strm = &ssi->capture; - else - return IRQ_HANDLED; /* Left over TX/RX interrupt */ - - if (irq == ssi->irq_int) { /* error or idle */ - if (ssisr & SSISR_TUIRQ) - strm->uerr_num++; - if (ssisr & SSISR_TOIRQ) - strm->oerr_num++; - if (ssisr & SSISR_RUIRQ) - strm->uerr_num++; - if (ssisr & SSISR_ROIRQ) - strm->oerr_num++; - - if (ssisr & (SSISR_TUIRQ | SSISR_TOIRQ | SSISR_RUIRQ | - SSISR_ROIRQ)) { - /* Error handling */ - /* You must reset (stop/restart) after each interrupt */ - rz_ssi_stop(ssi, strm); - - /* Clear all flags */ - rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | - SSISR_TUIRQ | SSISR_ROIRQ | - SSISR_RUIRQ, 0); - - /* Add/remove more data */ - strm->transfer(ssi, strm); - - /* Resume */ - rz_ssi_start(ssi, strm); - } - } - - if (!strm->running) - return IRQ_HANDLED; - - /* tx data empty */ - if (irq == ssi->irq_tx) - strm->transfer(ssi, &ssi->playback); - - /* rx data full */ - if (irq == ssi->irq_rx) { - strm->transfer(ssi, &ssi->capture); - rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); - } - - if (irq == ssi->irq_rt) { - struct snd_pcm_substream *substream = strm->substream; - - if (rz_ssi_stream_is_play(ssi, substream)) { - strm->transfer(ssi, &ssi->playback); - } else { - strm->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 */ - 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 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); - unsigned int sample_bits = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; - unsigned int channels = params_channels(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; - } - - return rz_ssi_clk_setup(ssi, params_rate(params), - params_channels(params)); -} - -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_new = 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 index d267243a159b..000000000000 --- a/sound/soc/sh/sh7760-ac97.c +++ /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 index a675c36fc9d9..000000000000 --- a/sound/soc/sh/siu.h +++ /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 index d0b5c543fd2f..000000000000 --- a/sound/soc/sh/siu_dai.c +++ /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_new = 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 index f15ff36e7934..000000000000 --- a/sound/soc/sh/siu_pcm.c +++ /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 = ¶m->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 index 96cf523c2273..000000000000 --- a/sound/soc/sh/ssi.c +++ /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>"); |