11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 292dfa619SBo Shen /* 392dfa619SBo Shen * atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC. 492dfa619SBo Shen * 592dfa619SBo Shen * Copyright (C) 2005 SAN People 692dfa619SBo Shen * Copyright (C) 2008 Atmel 792dfa619SBo Shen * 892dfa619SBo Shen * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> 992dfa619SBo Shen * 1092dfa619SBo Shen * Based on at91-pcm. by: 1192dfa619SBo Shen * Frank Mandarino <fmandarino@endrelia.com> 1292dfa619SBo Shen * Copyright 2006 Endrelia Technologies Inc. 1392dfa619SBo Shen * 1492dfa619SBo Shen * Based on pxa2xx-pcm.c by: 1592dfa619SBo Shen * 1692dfa619SBo Shen * Author: Nicolas Pitre 1792dfa619SBo Shen * Created: Nov 30, 2004 1892dfa619SBo Shen * Copyright: (C) 2004 MontaVista Software, Inc. 1992dfa619SBo Shen */ 2092dfa619SBo Shen 2192dfa619SBo Shen #include <linux/module.h> 2292dfa619SBo Shen #include <linux/init.h> 2392dfa619SBo Shen #include <linux/platform_device.h> 2492dfa619SBo Shen #include <linux/slab.h> 2592dfa619SBo Shen #include <linux/dma-mapping.h> 2692dfa619SBo Shen #include <linux/atmel_pdc.h> 2792dfa619SBo Shen #include <linux/atmel-ssc.h> 2892dfa619SBo Shen 2992dfa619SBo Shen #include <sound/core.h> 3092dfa619SBo Shen #include <sound/pcm.h> 3192dfa619SBo Shen #include <sound/pcm_params.h> 3292dfa619SBo Shen #include <sound/soc.h> 3392dfa619SBo Shen 3492dfa619SBo Shen #include "atmel-pcm.h" 3592dfa619SBo Shen 3692dfa619SBo Shen 37488cb533SAlexandre Belloni static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, 38488cb533SAlexandre Belloni int stream) 39488cb533SAlexandre Belloni { 40488cb533SAlexandre Belloni struct snd_pcm_substream *substream = pcm->streams[stream].substream; 41488cb533SAlexandre Belloni struct snd_dma_buffer *buf = &substream->dma_buffer; 42488cb533SAlexandre Belloni size_t size = ATMEL_SSC_DMABUF_SIZE; 43488cb533SAlexandre Belloni 44488cb533SAlexandre Belloni buf->dev.type = SNDRV_DMA_TYPE_DEV; 45488cb533SAlexandre Belloni buf->dev.dev = pcm->card->dev; 46488cb533SAlexandre Belloni buf->private_data = NULL; 47488cb533SAlexandre Belloni buf->area = dma_alloc_coherent(pcm->card->dev, size, 48488cb533SAlexandre Belloni &buf->addr, GFP_KERNEL); 49488cb533SAlexandre Belloni pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n", 50488cb533SAlexandre Belloni (void *)buf->area, (void *)(long)buf->addr, size); 51488cb533SAlexandre Belloni 52488cb533SAlexandre Belloni if (!buf->area) 53488cb533SAlexandre Belloni return -ENOMEM; 54488cb533SAlexandre Belloni 55488cb533SAlexandre Belloni buf->bytes = size; 56488cb533SAlexandre Belloni return 0; 57488cb533SAlexandre Belloni } 58488cb533SAlexandre Belloni 59a94e3f2dSKuninori Morimoto static int atmel_pcm_mmap(struct snd_soc_component *component, 60a94e3f2dSKuninori Morimoto struct snd_pcm_substream *substream, 61488cb533SAlexandre Belloni struct vm_area_struct *vma) 62488cb533SAlexandre Belloni { 63488cb533SAlexandre Belloni return remap_pfn_range(vma, vma->vm_start, 64488cb533SAlexandre Belloni substream->dma_buffer.addr >> PAGE_SHIFT, 65488cb533SAlexandre Belloni vma->vm_end - vma->vm_start, vma->vm_page_prot); 66488cb533SAlexandre Belloni } 67488cb533SAlexandre Belloni 68a94e3f2dSKuninori Morimoto static int atmel_pcm_new(struct snd_soc_component *component, 69a94e3f2dSKuninori Morimoto struct snd_soc_pcm_runtime *rtd) 70488cb533SAlexandre Belloni { 71488cb533SAlexandre Belloni struct snd_card *card = rtd->card->snd_card; 72488cb533SAlexandre Belloni struct snd_pcm *pcm = rtd->pcm; 73488cb533SAlexandre Belloni int ret; 74488cb533SAlexandre Belloni 75488cb533SAlexandre Belloni ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); 76488cb533SAlexandre Belloni if (ret) 77488cb533SAlexandre Belloni return ret; 78488cb533SAlexandre Belloni 79488cb533SAlexandre Belloni if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 80488cb533SAlexandre Belloni pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n"); 81488cb533SAlexandre Belloni ret = atmel_pcm_preallocate_dma_buffer(pcm, 82488cb533SAlexandre Belloni SNDRV_PCM_STREAM_PLAYBACK); 83488cb533SAlexandre Belloni if (ret) 84488cb533SAlexandre Belloni goto out; 85488cb533SAlexandre Belloni } 86488cb533SAlexandre Belloni 87488cb533SAlexandre Belloni if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 88488cb533SAlexandre Belloni pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n"); 89488cb533SAlexandre Belloni ret = atmel_pcm_preallocate_dma_buffer(pcm, 90488cb533SAlexandre Belloni SNDRV_PCM_STREAM_CAPTURE); 91488cb533SAlexandre Belloni if (ret) 92488cb533SAlexandre Belloni goto out; 93488cb533SAlexandre Belloni } 94488cb533SAlexandre Belloni out: 95488cb533SAlexandre Belloni return ret; 96488cb533SAlexandre Belloni } 97488cb533SAlexandre Belloni 98a94e3f2dSKuninori Morimoto static void atmel_pcm_free(struct snd_soc_component *component, 99a94e3f2dSKuninori Morimoto struct snd_pcm *pcm) 100488cb533SAlexandre Belloni { 101488cb533SAlexandre Belloni struct snd_pcm_substream *substream; 102488cb533SAlexandre Belloni struct snd_dma_buffer *buf; 103488cb533SAlexandre Belloni int stream; 104488cb533SAlexandre Belloni 105488cb533SAlexandre Belloni for (stream = 0; stream < 2; stream++) { 106488cb533SAlexandre Belloni substream = pcm->streams[stream].substream; 107488cb533SAlexandre Belloni if (!substream) 108488cb533SAlexandre Belloni continue; 109488cb533SAlexandre Belloni 110488cb533SAlexandre Belloni buf = &substream->dma_buffer; 111488cb533SAlexandre Belloni if (!buf->area) 112488cb533SAlexandre Belloni continue; 113488cb533SAlexandre Belloni dma_free_coherent(pcm->card->dev, buf->bytes, 114488cb533SAlexandre Belloni buf->area, buf->addr); 115488cb533SAlexandre Belloni buf->area = NULL; 116488cb533SAlexandre Belloni } 117488cb533SAlexandre Belloni } 118488cb533SAlexandre Belloni 11992dfa619SBo Shen /*--------------------------------------------------------------------------*\ 12092dfa619SBo Shen * Hardware definition 12192dfa619SBo Shen \*--------------------------------------------------------------------------*/ 12292dfa619SBo Shen /* TODO: These values were taken from the AT91 platform driver, check 12392dfa619SBo Shen * them against real values for AT32 12492dfa619SBo Shen */ 12592dfa619SBo Shen static const struct snd_pcm_hardware atmel_pcm_hardware = { 12692dfa619SBo Shen .info = SNDRV_PCM_INFO_MMAP | 12792dfa619SBo Shen SNDRV_PCM_INFO_MMAP_VALID | 12892dfa619SBo Shen SNDRV_PCM_INFO_INTERLEAVED | 12992dfa619SBo Shen SNDRV_PCM_INFO_PAUSE, 13092dfa619SBo Shen .period_bytes_min = 32, 13192dfa619SBo Shen .period_bytes_max = 8192, 13292dfa619SBo Shen .periods_min = 2, 13392dfa619SBo Shen .periods_max = 1024, 13492dfa619SBo Shen .buffer_bytes_max = ATMEL_SSC_DMABUF_SIZE, 13592dfa619SBo Shen }; 13692dfa619SBo Shen 13792dfa619SBo Shen 13892dfa619SBo Shen /*--------------------------------------------------------------------------*\ 13992dfa619SBo Shen * Data types 14092dfa619SBo Shen \*--------------------------------------------------------------------------*/ 14192dfa619SBo Shen struct atmel_runtime_data { 14292dfa619SBo Shen struct atmel_pcm_dma_params *params; 14392dfa619SBo Shen dma_addr_t dma_buffer; /* physical address of dma buffer */ 14492dfa619SBo Shen dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ 14592dfa619SBo Shen size_t period_size; 14692dfa619SBo Shen 14792dfa619SBo Shen dma_addr_t period_ptr; /* physical address of next period */ 14892dfa619SBo Shen }; 14992dfa619SBo Shen 15092dfa619SBo Shen /*--------------------------------------------------------------------------*\ 15192dfa619SBo Shen * ISR 15292dfa619SBo Shen \*--------------------------------------------------------------------------*/ 15392dfa619SBo Shen static void atmel_pcm_dma_irq(u32 ssc_sr, 15492dfa619SBo Shen struct snd_pcm_substream *substream) 15592dfa619SBo Shen { 15692dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 15792dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 15892dfa619SBo Shen static int count; 15992dfa619SBo Shen 16092dfa619SBo Shen count++; 16192dfa619SBo Shen 16292dfa619SBo Shen if (ssc_sr & params->mask->ssc_endbuf) { 16392dfa619SBo Shen pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", 16492dfa619SBo Shen substream->stream == SNDRV_PCM_STREAM_PLAYBACK 16592dfa619SBo Shen ? "underrun" : "overrun", 16692dfa619SBo Shen params->name, ssc_sr, count); 16792dfa619SBo Shen 16892dfa619SBo Shen /* re-start the PDC */ 16992dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 17092dfa619SBo Shen params->mask->pdc_disable); 17192dfa619SBo Shen prtd->period_ptr += prtd->period_size; 17292dfa619SBo Shen if (prtd->period_ptr >= prtd->dma_buffer_end) 17392dfa619SBo Shen prtd->period_ptr = prtd->dma_buffer; 17492dfa619SBo Shen 17592dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xpr, 17692dfa619SBo Shen prtd->period_ptr); 17792dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xcr, 17892dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 17992dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 18092dfa619SBo Shen params->mask->pdc_enable); 18192dfa619SBo Shen } 18292dfa619SBo Shen 18392dfa619SBo Shen if (ssc_sr & params->mask->ssc_endx) { 18492dfa619SBo Shen /* Load the PDC next pointer and counter registers */ 18592dfa619SBo Shen prtd->period_ptr += prtd->period_size; 18692dfa619SBo Shen if (prtd->period_ptr >= prtd->dma_buffer_end) 18792dfa619SBo Shen prtd->period_ptr = prtd->dma_buffer; 18892dfa619SBo Shen 18992dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xnpr, 19092dfa619SBo Shen prtd->period_ptr); 19192dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xncr, 19292dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 19392dfa619SBo Shen } 19492dfa619SBo Shen 19592dfa619SBo Shen snd_pcm_period_elapsed(substream); 19692dfa619SBo Shen } 19792dfa619SBo Shen 19892dfa619SBo Shen 19992dfa619SBo Shen /*--------------------------------------------------------------------------*\ 20092dfa619SBo Shen * PCM operations 20192dfa619SBo Shen \*--------------------------------------------------------------------------*/ 202a94e3f2dSKuninori Morimoto static int atmel_pcm_hw_params(struct snd_soc_component *component, 203a94e3f2dSKuninori Morimoto struct snd_pcm_substream *substream, 20492dfa619SBo Shen struct snd_pcm_hw_params *params) 20592dfa619SBo Shen { 20692dfa619SBo Shen struct snd_pcm_runtime *runtime = substream->runtime; 20792dfa619SBo Shen struct atmel_runtime_data *prtd = runtime->private_data; 20892dfa619SBo Shen struct snd_soc_pcm_runtime *rtd = substream->private_data; 20992dfa619SBo Shen 21092dfa619SBo Shen /* this may get called several times by oss emulation 21192dfa619SBo Shen * with different params */ 21292dfa619SBo Shen 21392dfa619SBo Shen snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 21492dfa619SBo Shen runtime->dma_bytes = params_buffer_bytes(params); 21592dfa619SBo Shen 216*b434d707SKuninori Morimoto prtd->params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 21792dfa619SBo Shen prtd->params->dma_intr_handler = atmel_pcm_dma_irq; 21892dfa619SBo Shen 21992dfa619SBo Shen prtd->dma_buffer = runtime->dma_addr; 22092dfa619SBo Shen prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; 22192dfa619SBo Shen prtd->period_size = params_period_bytes(params); 22292dfa619SBo Shen 22392dfa619SBo Shen pr_debug("atmel-pcm: " 22492dfa619SBo Shen "hw_params: DMA for %s initialized " 225153f5a18SJoachim Eastwood "(dma_bytes=%zu, period_size=%zu)\n", 22692dfa619SBo Shen prtd->params->name, 22792dfa619SBo Shen runtime->dma_bytes, 22892dfa619SBo Shen prtd->period_size); 22992dfa619SBo Shen return 0; 23092dfa619SBo Shen } 23192dfa619SBo Shen 232a94e3f2dSKuninori Morimoto static int atmel_pcm_hw_free(struct snd_soc_component *component, 233a94e3f2dSKuninori Morimoto struct snd_pcm_substream *substream) 23492dfa619SBo Shen { 23592dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 23692dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 23792dfa619SBo Shen 23892dfa619SBo Shen if (params != NULL) { 23992dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_PDC_PTCR, 24092dfa619SBo Shen params->mask->pdc_disable); 24192dfa619SBo Shen prtd->params->dma_intr_handler = NULL; 24292dfa619SBo Shen } 24392dfa619SBo Shen 24492dfa619SBo Shen return 0; 24592dfa619SBo Shen } 24692dfa619SBo Shen 247a94e3f2dSKuninori Morimoto static int atmel_pcm_prepare(struct snd_soc_component *component, 248a94e3f2dSKuninori Morimoto struct snd_pcm_substream *substream) 24992dfa619SBo Shen { 25092dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 25192dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 25292dfa619SBo Shen 25392dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_IDR, 25492dfa619SBo Shen params->mask->ssc_endx | params->mask->ssc_endbuf); 25592dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 25692dfa619SBo Shen params->mask->pdc_disable); 25792dfa619SBo Shen return 0; 25892dfa619SBo Shen } 25992dfa619SBo Shen 260a94e3f2dSKuninori Morimoto static int atmel_pcm_trigger(struct snd_soc_component *component, 261a94e3f2dSKuninori Morimoto struct snd_pcm_substream *substream, int cmd) 26292dfa619SBo Shen { 26392dfa619SBo Shen struct snd_pcm_runtime *rtd = substream->runtime; 26492dfa619SBo Shen struct atmel_runtime_data *prtd = rtd->private_data; 26592dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 26692dfa619SBo Shen int ret = 0; 26792dfa619SBo Shen 26892dfa619SBo Shen pr_debug("atmel-pcm:buffer_size = %ld," 269153f5a18SJoachim Eastwood "dma_area = %p, dma_bytes = %zu\n", 27092dfa619SBo Shen rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); 27192dfa619SBo Shen 27292dfa619SBo Shen switch (cmd) { 27392dfa619SBo Shen case SNDRV_PCM_TRIGGER_START: 27492dfa619SBo Shen prtd->period_ptr = prtd->dma_buffer; 27592dfa619SBo Shen 27692dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xpr, 27792dfa619SBo Shen prtd->period_ptr); 27892dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xcr, 27992dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 28092dfa619SBo Shen 28192dfa619SBo Shen prtd->period_ptr += prtd->period_size; 28292dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xnpr, 28392dfa619SBo Shen prtd->period_ptr); 28492dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xncr, 28592dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 28692dfa619SBo Shen 28792dfa619SBo Shen pr_debug("atmel-pcm: trigger: " 28892dfa619SBo Shen "period_ptr=%lx, xpr=%u, " 28992dfa619SBo Shen "xcr=%u, xnpr=%u, xncr=%u\n", 29092dfa619SBo Shen (unsigned long)prtd->period_ptr, 29192dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xpr), 29292dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xcr), 29392dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xnpr), 29492dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xncr)); 29592dfa619SBo Shen 29692dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_IER, 29792dfa619SBo Shen params->mask->ssc_endx | params->mask->ssc_endbuf); 29892dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_PDC_PTCR, 29992dfa619SBo Shen params->mask->pdc_enable); 30092dfa619SBo Shen 30192dfa619SBo Shen pr_debug("sr=%u imr=%u\n", 30292dfa619SBo Shen ssc_readx(params->ssc->regs, SSC_SR), 30392dfa619SBo Shen ssc_readx(params->ssc->regs, SSC_IER)); 30492dfa619SBo Shen break; /* SNDRV_PCM_TRIGGER_START */ 30592dfa619SBo Shen 30692dfa619SBo Shen case SNDRV_PCM_TRIGGER_STOP: 30792dfa619SBo Shen case SNDRV_PCM_TRIGGER_SUSPEND: 30892dfa619SBo Shen case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 30992dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 31092dfa619SBo Shen params->mask->pdc_disable); 31192dfa619SBo Shen break; 31292dfa619SBo Shen 31392dfa619SBo Shen case SNDRV_PCM_TRIGGER_RESUME: 31492dfa619SBo Shen case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 31592dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 31692dfa619SBo Shen params->mask->pdc_enable); 31792dfa619SBo Shen break; 31892dfa619SBo Shen 31992dfa619SBo Shen default: 32092dfa619SBo Shen ret = -EINVAL; 32192dfa619SBo Shen } 32292dfa619SBo Shen 32392dfa619SBo Shen return ret; 32492dfa619SBo Shen } 32592dfa619SBo Shen 326a94e3f2dSKuninori Morimoto static snd_pcm_uframes_t atmel_pcm_pointer(struct snd_soc_component *component, 32792dfa619SBo Shen struct snd_pcm_substream *substream) 32892dfa619SBo Shen { 32992dfa619SBo Shen struct snd_pcm_runtime *runtime = substream->runtime; 33092dfa619SBo Shen struct atmel_runtime_data *prtd = runtime->private_data; 33192dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 33292dfa619SBo Shen dma_addr_t ptr; 33392dfa619SBo Shen snd_pcm_uframes_t x; 33492dfa619SBo Shen 33592dfa619SBo Shen ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); 33692dfa619SBo Shen x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); 33792dfa619SBo Shen 33892dfa619SBo Shen if (x == runtime->buffer_size) 33992dfa619SBo Shen x = 0; 34092dfa619SBo Shen 34192dfa619SBo Shen return x; 34292dfa619SBo Shen } 34392dfa619SBo Shen 344a94e3f2dSKuninori Morimoto static int atmel_pcm_open(struct snd_soc_component *component, 345a94e3f2dSKuninori Morimoto struct snd_pcm_substream *substream) 34692dfa619SBo Shen { 34792dfa619SBo Shen struct snd_pcm_runtime *runtime = substream->runtime; 34892dfa619SBo Shen struct atmel_runtime_data *prtd; 34992dfa619SBo Shen int ret = 0; 35092dfa619SBo Shen 35192dfa619SBo Shen snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); 35292dfa619SBo Shen 35392dfa619SBo Shen /* ensure that buffer size is a multiple of period size */ 35492dfa619SBo Shen ret = snd_pcm_hw_constraint_integer(runtime, 35592dfa619SBo Shen SNDRV_PCM_HW_PARAM_PERIODS); 35692dfa619SBo Shen if (ret < 0) 35792dfa619SBo Shen goto out; 35892dfa619SBo Shen 35992dfa619SBo Shen prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); 36092dfa619SBo Shen if (prtd == NULL) { 36192dfa619SBo Shen ret = -ENOMEM; 36292dfa619SBo Shen goto out; 36392dfa619SBo Shen } 36492dfa619SBo Shen runtime->private_data = prtd; 36592dfa619SBo Shen 36692dfa619SBo Shen out: 36792dfa619SBo Shen return ret; 36892dfa619SBo Shen } 36992dfa619SBo Shen 370a94e3f2dSKuninori Morimoto static int atmel_pcm_close(struct snd_soc_component *component, 371a94e3f2dSKuninori Morimoto struct snd_pcm_substream *substream) 37292dfa619SBo Shen { 37392dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 37492dfa619SBo Shen 37592dfa619SBo Shen kfree(prtd); 37692dfa619SBo Shen return 0; 37792dfa619SBo Shen } 37892dfa619SBo Shen 379a94e3f2dSKuninori Morimoto static const struct snd_soc_component_driver atmel_soc_platform = { 38092dfa619SBo Shen .open = atmel_pcm_open, 38192dfa619SBo Shen .close = atmel_pcm_close, 38292dfa619SBo Shen .hw_params = atmel_pcm_hw_params, 38392dfa619SBo Shen .hw_free = atmel_pcm_hw_free, 38492dfa619SBo Shen .prepare = atmel_pcm_prepare, 38592dfa619SBo Shen .trigger = atmel_pcm_trigger, 38692dfa619SBo Shen .pointer = atmel_pcm_pointer, 38792dfa619SBo Shen .mmap = atmel_pcm_mmap, 388a94e3f2dSKuninori Morimoto .pcm_construct = atmel_pcm_new, 389a94e3f2dSKuninori Morimoto .pcm_destruct = atmel_pcm_free, 39092dfa619SBo Shen }; 39192dfa619SBo Shen 39292dfa619SBo Shen int atmel_pcm_pdc_platform_register(struct device *dev) 39392dfa619SBo Shen { 3946dea9df8SKuninori Morimoto return devm_snd_soc_register_component(dev, &atmel_soc_platform, 3956dea9df8SKuninori Morimoto NULL, 0); 39692dfa619SBo Shen } 39792dfa619SBo Shen EXPORT_SYMBOL(atmel_pcm_pdc_platform_register); 39892dfa619SBo Shen 39992dfa619SBo Shen MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); 40092dfa619SBo Shen MODULE_DESCRIPTION("Atmel PCM module"); 40192dfa619SBo Shen MODULE_LICENSE("GPL"); 402