Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * atmel-pcm.c  --  ALSA PCM interface for the Atmel atmel SoC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *  Copyright (C) 2005 SAN People
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *  Copyright (C) 2008 Atmel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * Based on at91-pcm. by:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * Frank Mandarino <fmandarino@endrelia.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * Copyright 2006 Endrelia Technologies Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  * Based on pxa2xx-pcm.c by:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  * Author:	Nicolas Pitre
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  * Created:	Nov 30, 2004
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  * Copyright:	(C) 2004 MontaVista Software, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/atmel_pdc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <linux/atmel-ssc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #include "atmel-pcm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	int stream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	struct snd_dma_buffer *buf = &substream->dma_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	size_t size = ATMEL_SSC_DMABUF_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	buf->dev.type = SNDRV_DMA_TYPE_DEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	buf->dev.dev = pcm->card->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	buf->private_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	buf->area = dma_alloc_coherent(pcm->card->dev, size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 			&buf->addr, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 			(void *)buf->area, (void *)(long)buf->addr, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	if (!buf->area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	buf->bytes = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) static int atmel_pcm_mmap(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 			  struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 			  struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	return remap_pfn_range(vma, vma->vm_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		       substream->dma_buffer.addr >> PAGE_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		       vma->vm_end - vma->vm_start, vma->vm_page_prot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) static int atmel_pcm_new(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 			 struct snd_soc_pcm_runtime *rtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	struct snd_card *card = rtd->card->snd_card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	struct snd_pcm *pcm = rtd->pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 		ret = atmel_pcm_preallocate_dma_buffer(pcm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 			SNDRV_PCM_STREAM_PLAYBACK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 		pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 		ret = atmel_pcm_preallocate_dma_buffer(pcm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 			SNDRV_PCM_STREAM_CAPTURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94)  out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) static void atmel_pcm_free(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 			   struct snd_pcm *pcm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	struct snd_pcm_substream *substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	struct snd_dma_buffer *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	int stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	for (stream = 0; stream < 2; stream++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		substream = pcm->streams[stream].substream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		if (!substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		buf = &substream->dma_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		if (!buf->area)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		dma_free_coherent(pcm->card->dev, buf->bytes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 				  buf->area, buf->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 		buf->area = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /*--------------------------------------------------------------------------*\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)  * Hardware definition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) \*--------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /* TODO: These values were taken from the AT91 platform driver, check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)  *	 them against real values for AT32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static const struct snd_pcm_hardware atmel_pcm_hardware = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	.info			= SNDRV_PCM_INFO_MMAP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 				  SNDRV_PCM_INFO_MMAP_VALID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 				  SNDRV_PCM_INFO_INTERLEAVED |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 				  SNDRV_PCM_INFO_PAUSE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	.period_bytes_min	= 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	.period_bytes_max	= 8192,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	.periods_min		= 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	.periods_max		= 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	.buffer_bytes_max	= ATMEL_SSC_DMABUF_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /*--------------------------------------------------------------------------*\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)  * Data types
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) \*--------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct atmel_runtime_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	struct atmel_pcm_dma_params *params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	dma_addr_t dma_buffer;		/* physical address of dma buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	dma_addr_t dma_buffer_end;	/* first address beyond DMA buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	size_t period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	dma_addr_t period_ptr;		/* physical address of next period */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /*--------------------------------------------------------------------------*\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)  * ISR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) \*--------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static void atmel_pcm_dma_irq(u32 ssc_sr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	struct atmel_runtime_data *prtd = substream->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	struct atmel_pcm_dma_params *params = prtd->params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	static int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	if (ssc_sr & params->mask->ssc_endbuf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 				substream->stream == SNDRV_PCM_STREAM_PLAYBACK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 				? "underrun" : "overrun",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 				params->name, ssc_sr, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		/* re-start the PDC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 			   params->mask->pdc_disable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		prtd->period_ptr += prtd->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		if (prtd->period_ptr >= prtd->dma_buffer_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 			prtd->period_ptr = prtd->dma_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		ssc_writex(params->ssc->regs, params->pdc->xpr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 			   prtd->period_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		ssc_writex(params->ssc->regs, params->pdc->xcr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 			   prtd->period_size / params->pdc_xfer_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 			   params->mask->pdc_enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	if (ssc_sr & params->mask->ssc_endx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		/* Load the PDC next pointer and counter registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 		prtd->period_ptr += prtd->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		if (prtd->period_ptr >= prtd->dma_buffer_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 			prtd->period_ptr = prtd->dma_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		ssc_writex(params->ssc->regs, params->pdc->xnpr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 			   prtd->period_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 		ssc_writex(params->ssc->regs, params->pdc->xncr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 			   prtd->period_size / params->pdc_xfer_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	snd_pcm_period_elapsed(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) /*--------------------------------------------------------------------------*\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)  * PCM operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) \*--------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static int atmel_pcm_hw_params(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 			       struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 			       struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	struct atmel_runtime_data *prtd = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	/* this may get called several times by oss emulation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	 * with different params */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	runtime->dma_bytes = params_buffer_bytes(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	prtd->params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	prtd->dma_buffer = runtime->dma_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	prtd->period_size = params_period_bytes(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	pr_debug("atmel-pcm: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 		"hw_params: DMA for %s initialized "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 		"(dma_bytes=%zu, period_size=%zu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 		prtd->params->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 		runtime->dma_bytes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 		prtd->period_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) static int atmel_pcm_hw_free(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 			     struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	struct atmel_runtime_data *prtd = substream->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	struct atmel_pcm_dma_params *params = prtd->params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	if (params != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 		ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 			   params->mask->pdc_disable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 		prtd->params->dma_intr_handler = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static int atmel_pcm_prepare(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 			     struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	struct atmel_runtime_data *prtd = substream->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	struct atmel_pcm_dma_params *params = prtd->params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	ssc_writex(params->ssc->regs, SSC_IDR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 		   params->mask->ssc_endx | params->mask->ssc_endbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		   params->mask->pdc_disable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) static int atmel_pcm_trigger(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 			     struct snd_pcm_substream *substream, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	struct snd_pcm_runtime *rtd = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	struct atmel_runtime_data *prtd = rtd->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	struct atmel_pcm_dma_params *params = prtd->params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	pr_debug("atmel-pcm:buffer_size = %ld,"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 		"dma_area = %p, dma_bytes = %zu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 		rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 		prtd->period_ptr = prtd->dma_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 		ssc_writex(params->ssc->regs, params->pdc->xpr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 			   prtd->period_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 		ssc_writex(params->ssc->regs, params->pdc->xcr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 			   prtd->period_size / params->pdc_xfer_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 		prtd->period_ptr += prtd->period_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		ssc_writex(params->ssc->regs, params->pdc->xnpr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 			   prtd->period_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		ssc_writex(params->ssc->regs, params->pdc->xncr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 			   prtd->period_size / params->pdc_xfer_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		pr_debug("atmel-pcm: trigger: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 			"period_ptr=%lx, xpr=%u, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 			"xcr=%u, xnpr=%u, xncr=%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 			(unsigned long)prtd->period_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 			ssc_readx(params->ssc->regs, params->pdc->xpr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 			ssc_readx(params->ssc->regs, params->pdc->xcr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 			ssc_readx(params->ssc->regs, params->pdc->xnpr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 			ssc_readx(params->ssc->regs, params->pdc->xncr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 		ssc_writex(params->ssc->regs, SSC_IER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 			   params->mask->ssc_endx | params->mask->ssc_endbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 			   params->mask->pdc_enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 		pr_debug("sr=%u imr=%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 			ssc_readx(params->ssc->regs, SSC_SR),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 			ssc_readx(params->ssc->regs, SSC_IER));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 		break;		/* SNDRV_PCM_TRIGGER_START */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 			   params->mask->pdc_disable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	case SNDRV_PCM_TRIGGER_RESUME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 			   params->mask->pdc_enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 		ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static snd_pcm_uframes_t atmel_pcm_pointer(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 					   struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	struct atmel_runtime_data *prtd = runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	struct atmel_pcm_dma_params *params = prtd->params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	dma_addr_t ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	snd_pcm_uframes_t x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	if (x == runtime->buffer_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 		x = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	return x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static int atmel_pcm_open(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 			  struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	struct snd_pcm_runtime *runtime = substream->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	struct atmel_runtime_data *prtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	/* ensure that buffer size is a multiple of period size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	ret = snd_pcm_hw_constraint_integer(runtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 						SNDRV_PCM_HW_PARAM_PERIODS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 	if (prtd == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 		ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 	runtime->private_data = prtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)  out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) static int atmel_pcm_close(struct snd_soc_component *component,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 			   struct snd_pcm_substream *substream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 	struct atmel_runtime_data *prtd = substream->runtime->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	kfree(prtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static const struct snd_soc_component_driver atmel_soc_platform = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 	.open		= atmel_pcm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 	.close		= atmel_pcm_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	.hw_params	= atmel_pcm_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	.hw_free	= atmel_pcm_hw_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 	.prepare	= atmel_pcm_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	.trigger	= atmel_pcm_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	.pointer	= atmel_pcm_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	.mmap		= atmel_pcm_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	.pcm_construct	= atmel_pcm_new,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 	.pcm_destruct	= atmel_pcm_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) int atmel_pcm_pdc_platform_register(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	return devm_snd_soc_register_component(dev, &atmel_soc_platform,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 					       NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) EXPORT_SYMBOL(atmel_pcm_pdc_platform_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) MODULE_DESCRIPTION("Atmel PCM module");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) MODULE_LICENSE("GPL");