^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");