sound/soc/renesas/dma-sh7760.c

Source file repositories/reference/linux-study-clean/sound/soc/renesas/dma-sh7760.c

File Facts

System
Linux kernel
Corpus path
sound/soc/renesas/dma-sh7760.c
Extension
.c
Size
9548 bytes
Lines
336
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

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;
};

static struct camelot_pcm 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);

Annotation

Implementation Notes