192dfa619SBo Shen /* 292dfa619SBo Shen * atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC. 392dfa619SBo Shen * 492dfa619SBo Shen * Copyright (C) 2005 SAN People 592dfa619SBo Shen * Copyright (C) 2008 Atmel 692dfa619SBo Shen * 792dfa619SBo Shen * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> 892dfa619SBo Shen * 992dfa619SBo Shen * Based on at91-pcm. by: 1092dfa619SBo Shen * Frank Mandarino <fmandarino@endrelia.com> 1192dfa619SBo Shen * Copyright 2006 Endrelia Technologies Inc. 1292dfa619SBo Shen * 1392dfa619SBo Shen * Based on pxa2xx-pcm.c by: 1492dfa619SBo Shen * 1592dfa619SBo Shen * Author: Nicolas Pitre 1692dfa619SBo Shen * Created: Nov 30, 2004 1792dfa619SBo Shen * Copyright: (C) 2004 MontaVista Software, Inc. 1892dfa619SBo Shen * 1992dfa619SBo Shen * This program is free software; you can redistribute it and/or modify 2092dfa619SBo Shen * it under the terms of the GNU General Public License as published by 2192dfa619SBo Shen * the Free Software Foundation; either version 2 of the License, or 2292dfa619SBo Shen * (at your option) any later version. 2392dfa619SBo Shen * 2492dfa619SBo Shen * This program is distributed in the hope that it will be useful, 2592dfa619SBo Shen * but WITHOUT ANY WARRANTY; without even the implied warranty of 2692dfa619SBo Shen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2792dfa619SBo Shen * GNU General Public License for more details. 2892dfa619SBo Shen * 2992dfa619SBo Shen * You should have received a copy of the GNU General Public License 3092dfa619SBo Shen * along with this program; if not, write to the Free Software 3192dfa619SBo Shen * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 3292dfa619SBo Shen */ 3392dfa619SBo Shen 3492dfa619SBo Shen #include <linux/module.h> 3592dfa619SBo Shen #include <linux/init.h> 3692dfa619SBo Shen #include <linux/platform_device.h> 3792dfa619SBo Shen #include <linux/slab.h> 3892dfa619SBo Shen #include <linux/dma-mapping.h> 3992dfa619SBo Shen #include <linux/atmel_pdc.h> 4092dfa619SBo Shen #include <linux/atmel-ssc.h> 4192dfa619SBo Shen 4292dfa619SBo Shen #include <sound/core.h> 4392dfa619SBo Shen #include <sound/pcm.h> 4492dfa619SBo Shen #include <sound/pcm_params.h> 4592dfa619SBo Shen #include <sound/soc.h> 4692dfa619SBo Shen 4792dfa619SBo Shen #include "atmel-pcm.h" 4892dfa619SBo Shen 4992dfa619SBo Shen 50488cb533SAlexandre Belloni static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, 51488cb533SAlexandre Belloni int stream) 52488cb533SAlexandre Belloni { 53488cb533SAlexandre Belloni struct snd_pcm_substream *substream = pcm->streams[stream].substream; 54488cb533SAlexandre Belloni struct snd_dma_buffer *buf = &substream->dma_buffer; 55488cb533SAlexandre Belloni size_t size = ATMEL_SSC_DMABUF_SIZE; 56488cb533SAlexandre Belloni 57488cb533SAlexandre Belloni buf->dev.type = SNDRV_DMA_TYPE_DEV; 58488cb533SAlexandre Belloni buf->dev.dev = pcm->card->dev; 59488cb533SAlexandre Belloni buf->private_data = NULL; 60488cb533SAlexandre Belloni buf->area = dma_alloc_coherent(pcm->card->dev, size, 61488cb533SAlexandre Belloni &buf->addr, GFP_KERNEL); 62488cb533SAlexandre Belloni pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n", 63488cb533SAlexandre Belloni (void *)buf->area, (void *)(long)buf->addr, size); 64488cb533SAlexandre Belloni 65488cb533SAlexandre Belloni if (!buf->area) 66488cb533SAlexandre Belloni return -ENOMEM; 67488cb533SAlexandre Belloni 68488cb533SAlexandre Belloni buf->bytes = size; 69488cb533SAlexandre Belloni return 0; 70488cb533SAlexandre Belloni } 71488cb533SAlexandre Belloni 72488cb533SAlexandre Belloni static int atmel_pcm_mmap(struct snd_pcm_substream *substream, 73488cb533SAlexandre Belloni struct vm_area_struct *vma) 74488cb533SAlexandre Belloni { 75488cb533SAlexandre Belloni return remap_pfn_range(vma, vma->vm_start, 76488cb533SAlexandre Belloni substream->dma_buffer.addr >> PAGE_SHIFT, 77488cb533SAlexandre Belloni vma->vm_end - vma->vm_start, vma->vm_page_prot); 78488cb533SAlexandre Belloni } 79488cb533SAlexandre Belloni 80488cb533SAlexandre Belloni static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) 81488cb533SAlexandre Belloni { 82488cb533SAlexandre Belloni struct snd_card *card = rtd->card->snd_card; 83488cb533SAlexandre Belloni struct snd_pcm *pcm = rtd->pcm; 84488cb533SAlexandre Belloni int ret; 85488cb533SAlexandre Belloni 86488cb533SAlexandre Belloni ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); 87488cb533SAlexandre Belloni if (ret) 88488cb533SAlexandre Belloni return ret; 89488cb533SAlexandre Belloni 90488cb533SAlexandre Belloni if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 91488cb533SAlexandre Belloni pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n"); 92488cb533SAlexandre Belloni ret = atmel_pcm_preallocate_dma_buffer(pcm, 93488cb533SAlexandre Belloni SNDRV_PCM_STREAM_PLAYBACK); 94488cb533SAlexandre Belloni if (ret) 95488cb533SAlexandre Belloni goto out; 96488cb533SAlexandre Belloni } 97488cb533SAlexandre Belloni 98488cb533SAlexandre Belloni if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 99488cb533SAlexandre Belloni pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n"); 100488cb533SAlexandre Belloni ret = atmel_pcm_preallocate_dma_buffer(pcm, 101488cb533SAlexandre Belloni SNDRV_PCM_STREAM_CAPTURE); 102488cb533SAlexandre Belloni if (ret) 103488cb533SAlexandre Belloni goto out; 104488cb533SAlexandre Belloni } 105488cb533SAlexandre Belloni out: 106488cb533SAlexandre Belloni return ret; 107488cb533SAlexandre Belloni } 108488cb533SAlexandre Belloni 109488cb533SAlexandre Belloni static void atmel_pcm_free(struct snd_pcm *pcm) 110488cb533SAlexandre Belloni { 111488cb533SAlexandre Belloni struct snd_pcm_substream *substream; 112488cb533SAlexandre Belloni struct snd_dma_buffer *buf; 113488cb533SAlexandre Belloni int stream; 114488cb533SAlexandre Belloni 115488cb533SAlexandre Belloni for (stream = 0; stream < 2; stream++) { 116488cb533SAlexandre Belloni substream = pcm->streams[stream].substream; 117488cb533SAlexandre Belloni if (!substream) 118488cb533SAlexandre Belloni continue; 119488cb533SAlexandre Belloni 120488cb533SAlexandre Belloni buf = &substream->dma_buffer; 121488cb533SAlexandre Belloni if (!buf->area) 122488cb533SAlexandre Belloni continue; 123488cb533SAlexandre Belloni dma_free_coherent(pcm->card->dev, buf->bytes, 124488cb533SAlexandre Belloni buf->area, buf->addr); 125488cb533SAlexandre Belloni buf->area = NULL; 126488cb533SAlexandre Belloni } 127488cb533SAlexandre Belloni } 128488cb533SAlexandre Belloni 12992dfa619SBo Shen /*--------------------------------------------------------------------------*\ 13092dfa619SBo Shen * Hardware definition 13192dfa619SBo Shen \*--------------------------------------------------------------------------*/ 13292dfa619SBo Shen /* TODO: These values were taken from the AT91 platform driver, check 13392dfa619SBo Shen * them against real values for AT32 13492dfa619SBo Shen */ 13592dfa619SBo Shen static const struct snd_pcm_hardware atmel_pcm_hardware = { 13692dfa619SBo Shen .info = SNDRV_PCM_INFO_MMAP | 13792dfa619SBo Shen SNDRV_PCM_INFO_MMAP_VALID | 13892dfa619SBo Shen SNDRV_PCM_INFO_INTERLEAVED | 13992dfa619SBo Shen SNDRV_PCM_INFO_PAUSE, 14092dfa619SBo Shen .period_bytes_min = 32, 14192dfa619SBo Shen .period_bytes_max = 8192, 14292dfa619SBo Shen .periods_min = 2, 14392dfa619SBo Shen .periods_max = 1024, 14492dfa619SBo Shen .buffer_bytes_max = ATMEL_SSC_DMABUF_SIZE, 14592dfa619SBo Shen }; 14692dfa619SBo Shen 14792dfa619SBo Shen 14892dfa619SBo Shen /*--------------------------------------------------------------------------*\ 14992dfa619SBo Shen * Data types 15092dfa619SBo Shen \*--------------------------------------------------------------------------*/ 15192dfa619SBo Shen struct atmel_runtime_data { 15292dfa619SBo Shen struct atmel_pcm_dma_params *params; 15392dfa619SBo Shen dma_addr_t dma_buffer; /* physical address of dma buffer */ 15492dfa619SBo Shen dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ 15592dfa619SBo Shen size_t period_size; 15692dfa619SBo Shen 15792dfa619SBo Shen dma_addr_t period_ptr; /* physical address of next period */ 15892dfa619SBo Shen }; 15992dfa619SBo Shen 16092dfa619SBo Shen /*--------------------------------------------------------------------------*\ 16192dfa619SBo Shen * ISR 16292dfa619SBo Shen \*--------------------------------------------------------------------------*/ 16392dfa619SBo Shen static void atmel_pcm_dma_irq(u32 ssc_sr, 16492dfa619SBo Shen struct snd_pcm_substream *substream) 16592dfa619SBo Shen { 16692dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 16792dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 16892dfa619SBo Shen static int count; 16992dfa619SBo Shen 17092dfa619SBo Shen count++; 17192dfa619SBo Shen 17292dfa619SBo Shen if (ssc_sr & params->mask->ssc_endbuf) { 17392dfa619SBo Shen pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", 17492dfa619SBo Shen substream->stream == SNDRV_PCM_STREAM_PLAYBACK 17592dfa619SBo Shen ? "underrun" : "overrun", 17692dfa619SBo Shen params->name, ssc_sr, count); 17792dfa619SBo Shen 17892dfa619SBo Shen /* re-start the PDC */ 17992dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 18092dfa619SBo Shen params->mask->pdc_disable); 18192dfa619SBo Shen prtd->period_ptr += prtd->period_size; 18292dfa619SBo Shen if (prtd->period_ptr >= prtd->dma_buffer_end) 18392dfa619SBo Shen prtd->period_ptr = prtd->dma_buffer; 18492dfa619SBo Shen 18592dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xpr, 18692dfa619SBo Shen prtd->period_ptr); 18792dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xcr, 18892dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 18992dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 19092dfa619SBo Shen params->mask->pdc_enable); 19192dfa619SBo Shen } 19292dfa619SBo Shen 19392dfa619SBo Shen if (ssc_sr & params->mask->ssc_endx) { 19492dfa619SBo Shen /* Load the PDC next pointer and counter registers */ 19592dfa619SBo Shen prtd->period_ptr += prtd->period_size; 19692dfa619SBo Shen if (prtd->period_ptr >= prtd->dma_buffer_end) 19792dfa619SBo Shen prtd->period_ptr = prtd->dma_buffer; 19892dfa619SBo Shen 19992dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xnpr, 20092dfa619SBo Shen prtd->period_ptr); 20192dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xncr, 20292dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 20392dfa619SBo Shen } 20492dfa619SBo Shen 20592dfa619SBo Shen snd_pcm_period_elapsed(substream); 20692dfa619SBo Shen } 20792dfa619SBo Shen 20892dfa619SBo Shen 20992dfa619SBo Shen /*--------------------------------------------------------------------------*\ 21092dfa619SBo Shen * PCM operations 21192dfa619SBo Shen \*--------------------------------------------------------------------------*/ 21292dfa619SBo Shen static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, 21392dfa619SBo Shen struct snd_pcm_hw_params *params) 21492dfa619SBo Shen { 21592dfa619SBo Shen struct snd_pcm_runtime *runtime = substream->runtime; 21692dfa619SBo Shen struct atmel_runtime_data *prtd = runtime->private_data; 21792dfa619SBo Shen struct snd_soc_pcm_runtime *rtd = substream->private_data; 21892dfa619SBo Shen 21992dfa619SBo Shen /* this may get called several times by oss emulation 22092dfa619SBo Shen * with different params */ 22192dfa619SBo Shen 22292dfa619SBo Shen snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 22392dfa619SBo Shen runtime->dma_bytes = params_buffer_bytes(params); 22492dfa619SBo Shen 22592dfa619SBo Shen prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); 22692dfa619SBo Shen prtd->params->dma_intr_handler = atmel_pcm_dma_irq; 22792dfa619SBo Shen 22892dfa619SBo Shen prtd->dma_buffer = runtime->dma_addr; 22992dfa619SBo Shen prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; 23092dfa619SBo Shen prtd->period_size = params_period_bytes(params); 23192dfa619SBo Shen 23292dfa619SBo Shen pr_debug("atmel-pcm: " 23392dfa619SBo Shen "hw_params: DMA for %s initialized " 234153f5a18SJoachim Eastwood "(dma_bytes=%zu, period_size=%zu)\n", 23592dfa619SBo Shen prtd->params->name, 23692dfa619SBo Shen runtime->dma_bytes, 23792dfa619SBo Shen prtd->period_size); 23892dfa619SBo Shen return 0; 23992dfa619SBo Shen } 24092dfa619SBo Shen 24192dfa619SBo Shen static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) 24292dfa619SBo Shen { 24392dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 24492dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 24592dfa619SBo Shen 24692dfa619SBo Shen if (params != NULL) { 24792dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_PDC_PTCR, 24892dfa619SBo Shen params->mask->pdc_disable); 24992dfa619SBo Shen prtd->params->dma_intr_handler = NULL; 25092dfa619SBo Shen } 25192dfa619SBo Shen 25292dfa619SBo Shen return 0; 25392dfa619SBo Shen } 25492dfa619SBo Shen 25592dfa619SBo Shen static int atmel_pcm_prepare(struct snd_pcm_substream *substream) 25692dfa619SBo Shen { 25792dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 25892dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 25992dfa619SBo Shen 26092dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_IDR, 26192dfa619SBo Shen params->mask->ssc_endx | params->mask->ssc_endbuf); 26292dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 26392dfa619SBo Shen params->mask->pdc_disable); 26492dfa619SBo Shen return 0; 26592dfa619SBo Shen } 26692dfa619SBo Shen 26792dfa619SBo Shen static int atmel_pcm_trigger(struct snd_pcm_substream *substream, 26892dfa619SBo Shen int cmd) 26992dfa619SBo Shen { 27092dfa619SBo Shen struct snd_pcm_runtime *rtd = substream->runtime; 27192dfa619SBo Shen struct atmel_runtime_data *prtd = rtd->private_data; 27292dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 27392dfa619SBo Shen int ret = 0; 27492dfa619SBo Shen 27592dfa619SBo Shen pr_debug("atmel-pcm:buffer_size = %ld," 276153f5a18SJoachim Eastwood "dma_area = %p, dma_bytes = %zu\n", 27792dfa619SBo Shen rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); 27892dfa619SBo Shen 27992dfa619SBo Shen switch (cmd) { 28092dfa619SBo Shen case SNDRV_PCM_TRIGGER_START: 28192dfa619SBo Shen prtd->period_ptr = prtd->dma_buffer; 28292dfa619SBo Shen 28392dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xpr, 28492dfa619SBo Shen prtd->period_ptr); 28592dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xcr, 28692dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 28792dfa619SBo Shen 28892dfa619SBo Shen prtd->period_ptr += prtd->period_size; 28992dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xnpr, 29092dfa619SBo Shen prtd->period_ptr); 29192dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xncr, 29292dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 29392dfa619SBo Shen 29492dfa619SBo Shen pr_debug("atmel-pcm: trigger: " 29592dfa619SBo Shen "period_ptr=%lx, xpr=%u, " 29692dfa619SBo Shen "xcr=%u, xnpr=%u, xncr=%u\n", 29792dfa619SBo Shen (unsigned long)prtd->period_ptr, 29892dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xpr), 29992dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xcr), 30092dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xnpr), 30192dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xncr)); 30292dfa619SBo Shen 30392dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_IER, 30492dfa619SBo Shen params->mask->ssc_endx | params->mask->ssc_endbuf); 30592dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_PDC_PTCR, 30692dfa619SBo Shen params->mask->pdc_enable); 30792dfa619SBo Shen 30892dfa619SBo Shen pr_debug("sr=%u imr=%u\n", 30992dfa619SBo Shen ssc_readx(params->ssc->regs, SSC_SR), 31092dfa619SBo Shen ssc_readx(params->ssc->regs, SSC_IER)); 31192dfa619SBo Shen break; /* SNDRV_PCM_TRIGGER_START */ 31292dfa619SBo Shen 31392dfa619SBo Shen case SNDRV_PCM_TRIGGER_STOP: 31492dfa619SBo Shen case SNDRV_PCM_TRIGGER_SUSPEND: 31592dfa619SBo Shen case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 31692dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 31792dfa619SBo Shen params->mask->pdc_disable); 31892dfa619SBo Shen break; 31992dfa619SBo Shen 32092dfa619SBo Shen case SNDRV_PCM_TRIGGER_RESUME: 32192dfa619SBo Shen case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 32292dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 32392dfa619SBo Shen params->mask->pdc_enable); 32492dfa619SBo Shen break; 32592dfa619SBo Shen 32692dfa619SBo Shen default: 32792dfa619SBo Shen ret = -EINVAL; 32892dfa619SBo Shen } 32992dfa619SBo Shen 33092dfa619SBo Shen return ret; 33192dfa619SBo Shen } 33292dfa619SBo Shen 33392dfa619SBo Shen static snd_pcm_uframes_t atmel_pcm_pointer( 33492dfa619SBo Shen struct snd_pcm_substream *substream) 33592dfa619SBo Shen { 33692dfa619SBo Shen struct snd_pcm_runtime *runtime = substream->runtime; 33792dfa619SBo Shen struct atmel_runtime_data *prtd = runtime->private_data; 33892dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 33992dfa619SBo Shen dma_addr_t ptr; 34092dfa619SBo Shen snd_pcm_uframes_t x; 34192dfa619SBo Shen 34292dfa619SBo Shen ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); 34392dfa619SBo Shen x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); 34492dfa619SBo Shen 34592dfa619SBo Shen if (x == runtime->buffer_size) 34692dfa619SBo Shen x = 0; 34792dfa619SBo Shen 34892dfa619SBo Shen return x; 34992dfa619SBo Shen } 35092dfa619SBo Shen 35192dfa619SBo Shen static int atmel_pcm_open(struct snd_pcm_substream *substream) 35292dfa619SBo Shen { 35392dfa619SBo Shen struct snd_pcm_runtime *runtime = substream->runtime; 35492dfa619SBo Shen struct atmel_runtime_data *prtd; 35592dfa619SBo Shen int ret = 0; 35692dfa619SBo Shen 35792dfa619SBo Shen snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); 35892dfa619SBo Shen 35992dfa619SBo Shen /* ensure that buffer size is a multiple of period size */ 36092dfa619SBo Shen ret = snd_pcm_hw_constraint_integer(runtime, 36192dfa619SBo Shen SNDRV_PCM_HW_PARAM_PERIODS); 36292dfa619SBo Shen if (ret < 0) 36392dfa619SBo Shen goto out; 36492dfa619SBo Shen 36592dfa619SBo Shen prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); 36692dfa619SBo Shen if (prtd == NULL) { 36792dfa619SBo Shen ret = -ENOMEM; 36892dfa619SBo Shen goto out; 36992dfa619SBo Shen } 37092dfa619SBo Shen runtime->private_data = prtd; 37192dfa619SBo Shen 37292dfa619SBo Shen out: 37392dfa619SBo Shen return ret; 37492dfa619SBo Shen } 37592dfa619SBo Shen 37692dfa619SBo Shen static int atmel_pcm_close(struct snd_pcm_substream *substream) 37792dfa619SBo Shen { 37892dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 37992dfa619SBo Shen 38092dfa619SBo Shen kfree(prtd); 38192dfa619SBo Shen return 0; 38292dfa619SBo Shen } 38392dfa619SBo Shen 384115c7254SJulia Lawall static const struct snd_pcm_ops atmel_pcm_ops = { 38592dfa619SBo Shen .open = atmel_pcm_open, 38692dfa619SBo Shen .close = atmel_pcm_close, 38792dfa619SBo Shen .ioctl = snd_pcm_lib_ioctl, 38892dfa619SBo Shen .hw_params = atmel_pcm_hw_params, 38992dfa619SBo Shen .hw_free = atmel_pcm_hw_free, 39092dfa619SBo Shen .prepare = atmel_pcm_prepare, 39192dfa619SBo Shen .trigger = atmel_pcm_trigger, 39292dfa619SBo Shen .pointer = atmel_pcm_pointer, 39392dfa619SBo Shen .mmap = atmel_pcm_mmap, 39492dfa619SBo Shen }; 39592dfa619SBo Shen 396*6dea9df8SKuninori Morimoto static struct snd_soc_component_driver atmel_soc_platform = { 39792dfa619SBo Shen .ops = &atmel_pcm_ops, 39892dfa619SBo Shen .pcm_new = atmel_pcm_new, 39992dfa619SBo Shen .pcm_free = atmel_pcm_free, 40092dfa619SBo Shen }; 40192dfa619SBo Shen 40292dfa619SBo Shen int atmel_pcm_pdc_platform_register(struct device *dev) 40392dfa619SBo Shen { 404*6dea9df8SKuninori Morimoto return devm_snd_soc_register_component(dev, &atmel_soc_platform, 405*6dea9df8SKuninori Morimoto NULL, 0); 40692dfa619SBo Shen } 40792dfa619SBo Shen EXPORT_SYMBOL(atmel_pcm_pdc_platform_register); 40892dfa619SBo Shen 40992dfa619SBo Shen void atmel_pcm_pdc_platform_unregister(struct device *dev) 41092dfa619SBo Shen { 41192dfa619SBo Shen } 41292dfa619SBo Shen EXPORT_SYMBOL(atmel_pcm_pdc_platform_unregister); 41392dfa619SBo Shen 41492dfa619SBo Shen MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); 41592dfa619SBo Shen MODULE_DESCRIPTION("Atmel PCM module"); 41692dfa619SBo Shen MODULE_LICENSE("GPL"); 417