18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// SH7760 ("camelot") DMABRG audio DMA unit support
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
68c2ecf20Sopenharmony_ci//
78c2ecf20Sopenharmony_ci// The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
88c2ecf20Sopenharmony_ci// trigger an interrupt when one half of the programmed transfer size
98c2ecf20Sopenharmony_ci// has been xmitted.
108c2ecf20Sopenharmony_ci//
118c2ecf20Sopenharmony_ci// FIXME: little-endian only for now
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/gfp.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
188c2ecf20Sopenharmony_ci#include <sound/core.h>
198c2ecf20Sopenharmony_ci#include <sound/pcm.h>
208c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
218c2ecf20Sopenharmony_ci#include <sound/soc.h>
228c2ecf20Sopenharmony_ci#include <asm/dmabrg.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* registers and bits */
268c2ecf20Sopenharmony_ci#define BRGATXSAR	0x00
278c2ecf20Sopenharmony_ci#define BRGARXDAR	0x04
288c2ecf20Sopenharmony_ci#define BRGATXTCR	0x08
298c2ecf20Sopenharmony_ci#define BRGARXTCR	0x0C
308c2ecf20Sopenharmony_ci#define BRGACR		0x10
318c2ecf20Sopenharmony_ci#define BRGATXTCNT	0x14
328c2ecf20Sopenharmony_ci#define BRGARXTCNT	0x18
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define ACR_RAR		(1 << 18)
358c2ecf20Sopenharmony_ci#define ACR_RDS		(1 << 17)
368c2ecf20Sopenharmony_ci#define ACR_RDE		(1 << 16)
378c2ecf20Sopenharmony_ci#define ACR_TAR		(1 << 2)
388c2ecf20Sopenharmony_ci#define ACR_TDS		(1 << 1)
398c2ecf20Sopenharmony_ci#define ACR_TDE		(1 << 0)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* receiver/transmitter data alignment */
428c2ecf20Sopenharmony_ci#define ACR_RAM_NONE	(0 << 24)
438c2ecf20Sopenharmony_ci#define ACR_RAM_4BYTE	(1 << 24)
448c2ecf20Sopenharmony_ci#define ACR_RAM_2WORD	(2 << 24)
458c2ecf20Sopenharmony_ci#define ACR_TAM_NONE	(0 << 8)
468c2ecf20Sopenharmony_ci#define ACR_TAM_4BYTE	(1 << 8)
478c2ecf20Sopenharmony_ci#define ACR_TAM_2WORD	(2 << 8)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistruct camelot_pcm {
518c2ecf20Sopenharmony_ci	unsigned long mmio;  /* DMABRG audio channel control reg MMIO */
528c2ecf20Sopenharmony_ci	unsigned int txid;    /* ID of first DMABRG IRQ for this unit */
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	struct snd_pcm_substream *tx_ss;
558c2ecf20Sopenharmony_ci	unsigned long tx_period_size;
568c2ecf20Sopenharmony_ci	unsigned int  tx_period;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	struct snd_pcm_substream *rx_ss;
598c2ecf20Sopenharmony_ci	unsigned long rx_period_size;
608c2ecf20Sopenharmony_ci	unsigned int  rx_period;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci} cam_pcm_data[2] = {
638c2ecf20Sopenharmony_ci	{
648c2ecf20Sopenharmony_ci		.mmio	=	0xFE3C0040,
658c2ecf20Sopenharmony_ci		.txid	=	DMABRGIRQ_A0TXF,
668c2ecf20Sopenharmony_ci	},
678c2ecf20Sopenharmony_ci	{
688c2ecf20Sopenharmony_ci		.mmio	=	0xFE3C0060,
698c2ecf20Sopenharmony_ci		.txid	=	DMABRGIRQ_A1TXF,
708c2ecf20Sopenharmony_ci	},
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define BRGREG(x)	(*(unsigned long *)(cam->mmio + (x)))
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/*
768c2ecf20Sopenharmony_ci * set a minimum of 16kb per period, to avoid interrupt-"storm" and
778c2ecf20Sopenharmony_ci * resulting skipping. In general, the bigger the minimum size, the
788c2ecf20Sopenharmony_ci * better for overall system performance. (The SH7760 is a puny CPU
798c2ecf20Sopenharmony_ci * with a slow SDRAM interface and poor internal bus bandwidth,
808c2ecf20Sopenharmony_ci * *especially* when the LCDC is active).  The minimum for the DMAC
818c2ecf20Sopenharmony_ci * is 8 bytes; 16kbytes are enough to get skip-free playback of a
828c2ecf20Sopenharmony_ci * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain
838c2ecf20Sopenharmony_ci * reasonable responsiveness in MPlayer.
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_ci#define DMABRG_PERIOD_MIN		16 * 1024
868c2ecf20Sopenharmony_ci#define DMABRG_PERIOD_MAX		0x03fffffc
878c2ecf20Sopenharmony_ci#define DMABRG_PREALLOC_BUFFER		32 * 1024
888c2ecf20Sopenharmony_ci#define DMABRG_PREALLOC_BUFFER_MAX	32 * 1024
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware camelot_pcm_hardware = {
918c2ecf20Sopenharmony_ci	.info = (SNDRV_PCM_INFO_MMAP |
928c2ecf20Sopenharmony_ci		SNDRV_PCM_INFO_INTERLEAVED |
938c2ecf20Sopenharmony_ci		SNDRV_PCM_INFO_BLOCK_TRANSFER |
948c2ecf20Sopenharmony_ci		SNDRV_PCM_INFO_MMAP_VALID |
958c2ecf20Sopenharmony_ci		SNDRV_PCM_INFO_BATCH),
968c2ecf20Sopenharmony_ci	.buffer_bytes_max =	DMABRG_PERIOD_MAX,
978c2ecf20Sopenharmony_ci	.period_bytes_min =	DMABRG_PERIOD_MIN,
988c2ecf20Sopenharmony_ci	.period_bytes_max =	DMABRG_PERIOD_MAX / 2,
998c2ecf20Sopenharmony_ci	.periods_min =		2,
1008c2ecf20Sopenharmony_ci	.periods_max =		2,
1018c2ecf20Sopenharmony_ci	.fifo_size =		128,
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic void camelot_txdma(void *data)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct camelot_pcm *cam = data;
1078c2ecf20Sopenharmony_ci	cam->tx_period ^= 1;
1088c2ecf20Sopenharmony_ci	snd_pcm_period_elapsed(cam->tx_ss);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic void camelot_rxdma(void *data)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct camelot_pcm *cam = data;
1148c2ecf20Sopenharmony_ci	cam->rx_period ^= 1;
1158c2ecf20Sopenharmony_ci	snd_pcm_period_elapsed(cam->rx_ss);
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic int camelot_pcm_open(struct snd_soc_component *component,
1198c2ecf20Sopenharmony_ci			    struct snd_pcm_substream *substream)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
1228c2ecf20Sopenharmony_ci	struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
1238c2ecf20Sopenharmony_ci	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
1248c2ecf20Sopenharmony_ci	int ret, dmairq;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	/* DMABRG buffer half/full events */
1298c2ecf20Sopenharmony_ci	dmairq = (recv) ? cam->txid + 2 : cam->txid;
1308c2ecf20Sopenharmony_ci	if (recv) {
1318c2ecf20Sopenharmony_ci		cam->rx_ss = substream;
1328c2ecf20Sopenharmony_ci		ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
1338c2ecf20Sopenharmony_ci		if (unlikely(ret)) {
1348c2ecf20Sopenharmony_ci			pr_debug("audio unit %d irqs already taken!\n",
1358c2ecf20Sopenharmony_ci			     asoc_rtd_to_cpu(rtd, 0)->id);
1368c2ecf20Sopenharmony_ci			return -EBUSY;
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci		(void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
1398c2ecf20Sopenharmony_ci	} else {
1408c2ecf20Sopenharmony_ci		cam->tx_ss = substream;
1418c2ecf20Sopenharmony_ci		ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
1428c2ecf20Sopenharmony_ci		if (unlikely(ret)) {
1438c2ecf20Sopenharmony_ci			pr_debug("audio unit %d irqs already taken!\n",
1448c2ecf20Sopenharmony_ci			     asoc_rtd_to_cpu(rtd, 0)->id);
1458c2ecf20Sopenharmony_ci			return -EBUSY;
1468c2ecf20Sopenharmony_ci		}
1478c2ecf20Sopenharmony_ci		(void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci	return 0;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int camelot_pcm_close(struct snd_soc_component *component,
1538c2ecf20Sopenharmony_ci			     struct snd_pcm_substream *substream)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
1568c2ecf20Sopenharmony_ci	struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
1578c2ecf20Sopenharmony_ci	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
1588c2ecf20Sopenharmony_ci	int dmairq;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	dmairq = (recv) ? cam->txid + 2 : cam->txid;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (recv)
1638c2ecf20Sopenharmony_ci		cam->rx_ss = NULL;
1648c2ecf20Sopenharmony_ci	else
1658c2ecf20Sopenharmony_ci		cam->tx_ss = NULL;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	dmabrg_free_irq(dmairq + 1);
1688c2ecf20Sopenharmony_ci	dmabrg_free_irq(dmairq);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int camelot_hw_params(struct snd_soc_component *component,
1748c2ecf20Sopenharmony_ci			     struct snd_pcm_substream *substream,
1758c2ecf20Sopenharmony_ci			     struct snd_pcm_hw_params *hw_params)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
1788c2ecf20Sopenharmony_ci	struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
1798c2ecf20Sopenharmony_ci	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
1808c2ecf20Sopenharmony_ci	int ret;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (recv) {
1838c2ecf20Sopenharmony_ci		cam->rx_period_size = params_period_bytes(hw_params);
1848c2ecf20Sopenharmony_ci		cam->rx_period = 0;
1858c2ecf20Sopenharmony_ci	} else {
1868c2ecf20Sopenharmony_ci		cam->tx_period_size = params_period_bytes(hw_params);
1878c2ecf20Sopenharmony_ci		cam->tx_period = 0;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci	return 0;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic int camelot_prepare(struct snd_soc_component *component,
1938c2ecf20Sopenharmony_ci			   struct snd_pcm_substream *substream)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
1968c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
1978c2ecf20Sopenharmony_ci	struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	pr_debug("PCM data: addr 0x%08lx len %d\n",
2008c2ecf20Sopenharmony_ci		 (u32)runtime->dma_addr, runtime->dma_bytes);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
2038c2ecf20Sopenharmony_ci		BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
2048c2ecf20Sopenharmony_ci		BRGREG(BRGATXTCR) = runtime->dma_bytes;
2058c2ecf20Sopenharmony_ci	} else {
2068c2ecf20Sopenharmony_ci		BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area;
2078c2ecf20Sopenharmony_ci		BRGREG(BRGARXTCR) = runtime->dma_bytes;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	return 0;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic inline void dmabrg_play_dma_start(struct camelot_pcm *cam)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
2168c2ecf20Sopenharmony_ci	/* start DMABRG engine: XFER start, auto-addr-reload */
2178c2ecf20Sopenharmony_ci	BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic inline void dmabrg_play_dma_stop(struct camelot_pcm *cam)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
2238c2ecf20Sopenharmony_ci	/* forcibly terminate data transmission */
2248c2ecf20Sopenharmony_ci	BRGREG(BRGACR) = acr | ACR_TDS;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic inline void dmabrg_rec_dma_start(struct camelot_pcm *cam)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
2308c2ecf20Sopenharmony_ci	/* start DMABRG engine: recv start, auto-reload */
2318c2ecf20Sopenharmony_ci	BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
2378c2ecf20Sopenharmony_ci	/* forcibly terminate data receiver */
2388c2ecf20Sopenharmony_ci	BRGREG(BRGACR) = acr | ACR_RDS;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int camelot_trigger(struct snd_soc_component *component,
2428c2ecf20Sopenharmony_ci			   struct snd_pcm_substream *substream, int cmd)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
2458c2ecf20Sopenharmony_ci	struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
2468c2ecf20Sopenharmony_ci	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	switch (cmd) {
2498c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
2508c2ecf20Sopenharmony_ci		if (recv)
2518c2ecf20Sopenharmony_ci			dmabrg_rec_dma_start(cam);
2528c2ecf20Sopenharmony_ci		else
2538c2ecf20Sopenharmony_ci			dmabrg_play_dma_start(cam);
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
2568c2ecf20Sopenharmony_ci		if (recv)
2578c2ecf20Sopenharmony_ci			dmabrg_rec_dma_stop(cam);
2588c2ecf20Sopenharmony_ci		else
2598c2ecf20Sopenharmony_ci			dmabrg_play_dma_stop(cam);
2608c2ecf20Sopenharmony_ci		break;
2618c2ecf20Sopenharmony_ci	default:
2628c2ecf20Sopenharmony_ci		return -EINVAL;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return 0;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t camelot_pos(struct snd_soc_component *component,
2698c2ecf20Sopenharmony_ci				     struct snd_pcm_substream *substream)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
2728c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
2738c2ecf20Sopenharmony_ci	struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
2748c2ecf20Sopenharmony_ci	int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
2758c2ecf20Sopenharmony_ci	unsigned long pos;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* cannot use the DMABRG pointer register: under load, by the
2788c2ecf20Sopenharmony_ci	 * time ALSA comes around to read the register, it is already
2798c2ecf20Sopenharmony_ci	 * far ahead (or worse, already done with the fragment) of the
2808c2ecf20Sopenharmony_ci	 * position at the time the IRQ was triggered, which results in
2818c2ecf20Sopenharmony_ci	 * fast-playback sound in my test application (ScummVM)
2828c2ecf20Sopenharmony_ci	 */
2838c2ecf20Sopenharmony_ci	if (recv)
2848c2ecf20Sopenharmony_ci		pos = cam->rx_period ? cam->rx_period_size : 0;
2858c2ecf20Sopenharmony_ci	else
2868c2ecf20Sopenharmony_ci		pos = cam->tx_period ? cam->tx_period_size : 0;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return bytes_to_frames(runtime, pos);
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic int camelot_pcm_new(struct snd_soc_component *component,
2928c2ecf20Sopenharmony_ci			   struct snd_soc_pcm_runtime *rtd)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct snd_pcm *pcm = rtd->pcm;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
2978c2ecf20Sopenharmony_ci	 * in MMAP mode (i.e. aplay -M)
2988c2ecf20Sopenharmony_ci	 */
2998c2ecf20Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm,
3008c2ecf20Sopenharmony_ci		SNDRV_DMA_TYPE_CONTINUOUS,
3018c2ecf20Sopenharmony_ci		NULL,
3028c2ecf20Sopenharmony_ci		DMABRG_PREALLOC_BUFFER,	DMABRG_PREALLOC_BUFFER_MAX);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	return 0;
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sh7760_soc_component = {
3088c2ecf20Sopenharmony_ci	.open		= camelot_pcm_open,
3098c2ecf20Sopenharmony_ci	.close		= camelot_pcm_close,
3108c2ecf20Sopenharmony_ci	.hw_params	= camelot_hw_params,
3118c2ecf20Sopenharmony_ci	.prepare	= camelot_prepare,
3128c2ecf20Sopenharmony_ci	.trigger	= camelot_trigger,
3138c2ecf20Sopenharmony_ci	.pointer	= camelot_pos,
3148c2ecf20Sopenharmony_ci	.pcm_construct	= camelot_pcm_new,
3158c2ecf20Sopenharmony_ci};
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic int sh7760_soc_platform_probe(struct platform_device *pdev)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	return devm_snd_soc_register_component(&pdev->dev, &sh7760_soc_component,
3208c2ecf20Sopenharmony_ci					       NULL, 0);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic struct platform_driver sh7760_pcm_driver = {
3248c2ecf20Sopenharmony_ci	.driver = {
3258c2ecf20Sopenharmony_ci			.name = "sh7760-pcm-audio",
3268c2ecf20Sopenharmony_ci	},
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	.probe = sh7760_soc_platform_probe,
3298c2ecf20Sopenharmony_ci};
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cimodule_platform_driver(sh7760_pcm_driver);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
3348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
3358c2ecf20Sopenharmony_ciMODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
336