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 5092dfa619SBo Shen /*--------------------------------------------------------------------------*\ 5192dfa619SBo Shen * Hardware definition 5292dfa619SBo Shen \*--------------------------------------------------------------------------*/ 5392dfa619SBo Shen /* TODO: These values were taken from the AT91 platform driver, check 5492dfa619SBo Shen * them against real values for AT32 5592dfa619SBo Shen */ 5692dfa619SBo Shen static const struct snd_pcm_hardware atmel_pcm_hardware = { 5792dfa619SBo Shen .info = SNDRV_PCM_INFO_MMAP | 5892dfa619SBo Shen SNDRV_PCM_INFO_MMAP_VALID | 5992dfa619SBo Shen SNDRV_PCM_INFO_INTERLEAVED | 6092dfa619SBo Shen SNDRV_PCM_INFO_PAUSE, 6192dfa619SBo Shen .formats = SNDRV_PCM_FMTBIT_S16_LE, 6292dfa619SBo Shen .period_bytes_min = 32, 6392dfa619SBo Shen .period_bytes_max = 8192, 6492dfa619SBo Shen .periods_min = 2, 6592dfa619SBo Shen .periods_max = 1024, 6692dfa619SBo Shen .buffer_bytes_max = ATMEL_SSC_DMABUF_SIZE, 6792dfa619SBo Shen }; 6892dfa619SBo Shen 6992dfa619SBo Shen 7092dfa619SBo Shen /*--------------------------------------------------------------------------*\ 7192dfa619SBo Shen * Data types 7292dfa619SBo Shen \*--------------------------------------------------------------------------*/ 7392dfa619SBo Shen struct atmel_runtime_data { 7492dfa619SBo Shen struct atmel_pcm_dma_params *params; 7592dfa619SBo Shen dma_addr_t dma_buffer; /* physical address of dma buffer */ 7692dfa619SBo Shen dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ 7792dfa619SBo Shen size_t period_size; 7892dfa619SBo Shen 7992dfa619SBo Shen dma_addr_t period_ptr; /* physical address of next period */ 8092dfa619SBo Shen 8192dfa619SBo Shen /* PDC register save */ 8292dfa619SBo Shen u32 pdc_xpr_save; 8392dfa619SBo Shen u32 pdc_xcr_save; 8492dfa619SBo Shen u32 pdc_xnpr_save; 8592dfa619SBo Shen u32 pdc_xncr_save; 8692dfa619SBo Shen }; 8792dfa619SBo Shen 8892dfa619SBo Shen /*--------------------------------------------------------------------------*\ 8992dfa619SBo Shen * ISR 9092dfa619SBo Shen \*--------------------------------------------------------------------------*/ 9192dfa619SBo Shen static void atmel_pcm_dma_irq(u32 ssc_sr, 9292dfa619SBo Shen struct snd_pcm_substream *substream) 9392dfa619SBo Shen { 9492dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 9592dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 9692dfa619SBo Shen static int count; 9792dfa619SBo Shen 9892dfa619SBo Shen count++; 9992dfa619SBo Shen 10092dfa619SBo Shen if (ssc_sr & params->mask->ssc_endbuf) { 10192dfa619SBo Shen pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", 10292dfa619SBo Shen substream->stream == SNDRV_PCM_STREAM_PLAYBACK 10392dfa619SBo Shen ? "underrun" : "overrun", 10492dfa619SBo Shen params->name, ssc_sr, count); 10592dfa619SBo Shen 10692dfa619SBo Shen /* re-start the PDC */ 10792dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 10892dfa619SBo Shen params->mask->pdc_disable); 10992dfa619SBo Shen prtd->period_ptr += prtd->period_size; 11092dfa619SBo Shen if (prtd->period_ptr >= prtd->dma_buffer_end) 11192dfa619SBo Shen prtd->period_ptr = prtd->dma_buffer; 11292dfa619SBo Shen 11392dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xpr, 11492dfa619SBo Shen prtd->period_ptr); 11592dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xcr, 11692dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 11792dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 11892dfa619SBo Shen params->mask->pdc_enable); 11992dfa619SBo Shen } 12092dfa619SBo Shen 12192dfa619SBo Shen if (ssc_sr & params->mask->ssc_endx) { 12292dfa619SBo Shen /* Load the PDC next pointer and counter registers */ 12392dfa619SBo Shen prtd->period_ptr += prtd->period_size; 12492dfa619SBo Shen if (prtd->period_ptr >= prtd->dma_buffer_end) 12592dfa619SBo Shen prtd->period_ptr = prtd->dma_buffer; 12692dfa619SBo Shen 12792dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xnpr, 12892dfa619SBo Shen prtd->period_ptr); 12992dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xncr, 13092dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 13192dfa619SBo Shen } 13292dfa619SBo Shen 13392dfa619SBo Shen snd_pcm_period_elapsed(substream); 13492dfa619SBo Shen } 13592dfa619SBo Shen 13692dfa619SBo Shen 13792dfa619SBo Shen /*--------------------------------------------------------------------------*\ 13892dfa619SBo Shen * PCM operations 13992dfa619SBo Shen \*--------------------------------------------------------------------------*/ 14092dfa619SBo Shen static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, 14192dfa619SBo Shen struct snd_pcm_hw_params *params) 14292dfa619SBo Shen { 14392dfa619SBo Shen struct snd_pcm_runtime *runtime = substream->runtime; 14492dfa619SBo Shen struct atmel_runtime_data *prtd = runtime->private_data; 14592dfa619SBo Shen struct snd_soc_pcm_runtime *rtd = substream->private_data; 14692dfa619SBo Shen 14792dfa619SBo Shen /* this may get called several times by oss emulation 14892dfa619SBo Shen * with different params */ 14992dfa619SBo Shen 15092dfa619SBo Shen snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 15192dfa619SBo Shen runtime->dma_bytes = params_buffer_bytes(params); 15292dfa619SBo Shen 15392dfa619SBo Shen prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); 15492dfa619SBo Shen prtd->params->dma_intr_handler = atmel_pcm_dma_irq; 15592dfa619SBo Shen 15692dfa619SBo Shen prtd->dma_buffer = runtime->dma_addr; 15792dfa619SBo Shen prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; 15892dfa619SBo Shen prtd->period_size = params_period_bytes(params); 15992dfa619SBo Shen 16092dfa619SBo Shen pr_debug("atmel-pcm: " 16192dfa619SBo Shen "hw_params: DMA for %s initialized " 162*153f5a18SJoachim Eastwood "(dma_bytes=%zu, period_size=%zu)\n", 16392dfa619SBo Shen prtd->params->name, 16492dfa619SBo Shen runtime->dma_bytes, 16592dfa619SBo Shen prtd->period_size); 16692dfa619SBo Shen return 0; 16792dfa619SBo Shen } 16892dfa619SBo Shen 16992dfa619SBo Shen static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) 17092dfa619SBo Shen { 17192dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 17292dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 17392dfa619SBo Shen 17492dfa619SBo Shen if (params != NULL) { 17592dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_PDC_PTCR, 17692dfa619SBo Shen params->mask->pdc_disable); 17792dfa619SBo Shen prtd->params->dma_intr_handler = NULL; 17892dfa619SBo Shen } 17992dfa619SBo Shen 18092dfa619SBo Shen return 0; 18192dfa619SBo Shen } 18292dfa619SBo Shen 18392dfa619SBo Shen static int atmel_pcm_prepare(struct snd_pcm_substream *substream) 18492dfa619SBo Shen { 18592dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 18692dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 18792dfa619SBo Shen 18892dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_IDR, 18992dfa619SBo Shen params->mask->ssc_endx | params->mask->ssc_endbuf); 19092dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 19192dfa619SBo Shen params->mask->pdc_disable); 19292dfa619SBo Shen return 0; 19392dfa619SBo Shen } 19492dfa619SBo Shen 19592dfa619SBo Shen static int atmel_pcm_trigger(struct snd_pcm_substream *substream, 19692dfa619SBo Shen int cmd) 19792dfa619SBo Shen { 19892dfa619SBo Shen struct snd_pcm_runtime *rtd = substream->runtime; 19992dfa619SBo Shen struct atmel_runtime_data *prtd = rtd->private_data; 20092dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 20192dfa619SBo Shen int ret = 0; 20292dfa619SBo Shen 20392dfa619SBo Shen pr_debug("atmel-pcm:buffer_size = %ld," 204*153f5a18SJoachim Eastwood "dma_area = %p, dma_bytes = %zu\n", 20592dfa619SBo Shen rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); 20692dfa619SBo Shen 20792dfa619SBo Shen switch (cmd) { 20892dfa619SBo Shen case SNDRV_PCM_TRIGGER_START: 20992dfa619SBo Shen prtd->period_ptr = prtd->dma_buffer; 21092dfa619SBo Shen 21192dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xpr, 21292dfa619SBo Shen prtd->period_ptr); 21392dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xcr, 21492dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 21592dfa619SBo Shen 21692dfa619SBo Shen prtd->period_ptr += prtd->period_size; 21792dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xnpr, 21892dfa619SBo Shen prtd->period_ptr); 21992dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xncr, 22092dfa619SBo Shen prtd->period_size / params->pdc_xfer_size); 22192dfa619SBo Shen 22292dfa619SBo Shen pr_debug("atmel-pcm: trigger: " 22392dfa619SBo Shen "period_ptr=%lx, xpr=%u, " 22492dfa619SBo Shen "xcr=%u, xnpr=%u, xncr=%u\n", 22592dfa619SBo Shen (unsigned long)prtd->period_ptr, 22692dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xpr), 22792dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xcr), 22892dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xnpr), 22992dfa619SBo Shen ssc_readx(params->ssc->regs, params->pdc->xncr)); 23092dfa619SBo Shen 23192dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_IER, 23292dfa619SBo Shen params->mask->ssc_endx | params->mask->ssc_endbuf); 23392dfa619SBo Shen ssc_writex(params->ssc->regs, SSC_PDC_PTCR, 23492dfa619SBo Shen params->mask->pdc_enable); 23592dfa619SBo Shen 23692dfa619SBo Shen pr_debug("sr=%u imr=%u\n", 23792dfa619SBo Shen ssc_readx(params->ssc->regs, SSC_SR), 23892dfa619SBo Shen ssc_readx(params->ssc->regs, SSC_IER)); 23992dfa619SBo Shen break; /* SNDRV_PCM_TRIGGER_START */ 24092dfa619SBo Shen 24192dfa619SBo Shen case SNDRV_PCM_TRIGGER_STOP: 24292dfa619SBo Shen case SNDRV_PCM_TRIGGER_SUSPEND: 24392dfa619SBo Shen case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 24492dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 24592dfa619SBo Shen params->mask->pdc_disable); 24692dfa619SBo Shen break; 24792dfa619SBo Shen 24892dfa619SBo Shen case SNDRV_PCM_TRIGGER_RESUME: 24992dfa619SBo Shen case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 25092dfa619SBo Shen ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, 25192dfa619SBo Shen params->mask->pdc_enable); 25292dfa619SBo Shen break; 25392dfa619SBo Shen 25492dfa619SBo Shen default: 25592dfa619SBo Shen ret = -EINVAL; 25692dfa619SBo Shen } 25792dfa619SBo Shen 25892dfa619SBo Shen return ret; 25992dfa619SBo Shen } 26092dfa619SBo Shen 26192dfa619SBo Shen static snd_pcm_uframes_t atmel_pcm_pointer( 26292dfa619SBo Shen struct snd_pcm_substream *substream) 26392dfa619SBo Shen { 26492dfa619SBo Shen struct snd_pcm_runtime *runtime = substream->runtime; 26592dfa619SBo Shen struct atmel_runtime_data *prtd = runtime->private_data; 26692dfa619SBo Shen struct atmel_pcm_dma_params *params = prtd->params; 26792dfa619SBo Shen dma_addr_t ptr; 26892dfa619SBo Shen snd_pcm_uframes_t x; 26992dfa619SBo Shen 27092dfa619SBo Shen ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); 27192dfa619SBo Shen x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); 27292dfa619SBo Shen 27392dfa619SBo Shen if (x == runtime->buffer_size) 27492dfa619SBo Shen x = 0; 27592dfa619SBo Shen 27692dfa619SBo Shen return x; 27792dfa619SBo Shen } 27892dfa619SBo Shen 27992dfa619SBo Shen static int atmel_pcm_open(struct snd_pcm_substream *substream) 28092dfa619SBo Shen { 28192dfa619SBo Shen struct snd_pcm_runtime *runtime = substream->runtime; 28292dfa619SBo Shen struct atmel_runtime_data *prtd; 28392dfa619SBo Shen int ret = 0; 28492dfa619SBo Shen 28592dfa619SBo Shen snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); 28692dfa619SBo Shen 28792dfa619SBo Shen /* ensure that buffer size is a multiple of period size */ 28892dfa619SBo Shen ret = snd_pcm_hw_constraint_integer(runtime, 28992dfa619SBo Shen SNDRV_PCM_HW_PARAM_PERIODS); 29092dfa619SBo Shen if (ret < 0) 29192dfa619SBo Shen goto out; 29292dfa619SBo Shen 29392dfa619SBo Shen prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); 29492dfa619SBo Shen if (prtd == NULL) { 29592dfa619SBo Shen ret = -ENOMEM; 29692dfa619SBo Shen goto out; 29792dfa619SBo Shen } 29892dfa619SBo Shen runtime->private_data = prtd; 29992dfa619SBo Shen 30092dfa619SBo Shen out: 30192dfa619SBo Shen return ret; 30292dfa619SBo Shen } 30392dfa619SBo Shen 30492dfa619SBo Shen static int atmel_pcm_close(struct snd_pcm_substream *substream) 30592dfa619SBo Shen { 30692dfa619SBo Shen struct atmel_runtime_data *prtd = substream->runtime->private_data; 30792dfa619SBo Shen 30892dfa619SBo Shen kfree(prtd); 30992dfa619SBo Shen return 0; 31092dfa619SBo Shen } 31192dfa619SBo Shen 31292dfa619SBo Shen static struct snd_pcm_ops atmel_pcm_ops = { 31392dfa619SBo Shen .open = atmel_pcm_open, 31492dfa619SBo Shen .close = atmel_pcm_close, 31592dfa619SBo Shen .ioctl = snd_pcm_lib_ioctl, 31692dfa619SBo Shen .hw_params = atmel_pcm_hw_params, 31792dfa619SBo Shen .hw_free = atmel_pcm_hw_free, 31892dfa619SBo Shen .prepare = atmel_pcm_prepare, 31992dfa619SBo Shen .trigger = atmel_pcm_trigger, 32092dfa619SBo Shen .pointer = atmel_pcm_pointer, 32192dfa619SBo Shen .mmap = atmel_pcm_mmap, 32292dfa619SBo Shen }; 32392dfa619SBo Shen 32492dfa619SBo Shen 32592dfa619SBo Shen /*--------------------------------------------------------------------------*\ 32692dfa619SBo Shen * ASoC platform driver 32792dfa619SBo Shen \*--------------------------------------------------------------------------*/ 32892dfa619SBo Shen #ifdef CONFIG_PM 32992dfa619SBo Shen static int atmel_pcm_suspend(struct snd_soc_dai *dai) 33092dfa619SBo Shen { 33192dfa619SBo Shen struct snd_pcm_runtime *runtime = dai->runtime; 33292dfa619SBo Shen struct atmel_runtime_data *prtd; 33392dfa619SBo Shen struct atmel_pcm_dma_params *params; 33492dfa619SBo Shen 33592dfa619SBo Shen if (!runtime) 33692dfa619SBo Shen return 0; 33792dfa619SBo Shen 33892dfa619SBo Shen prtd = runtime->private_data; 33992dfa619SBo Shen params = prtd->params; 34092dfa619SBo Shen 34192dfa619SBo Shen /* disable the PDC and save the PDC registers */ 34292dfa619SBo Shen 34392dfa619SBo Shen ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); 34492dfa619SBo Shen 34592dfa619SBo Shen prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); 34692dfa619SBo Shen prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); 34792dfa619SBo Shen prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); 34892dfa619SBo Shen prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); 34992dfa619SBo Shen 35092dfa619SBo Shen return 0; 35192dfa619SBo Shen } 35292dfa619SBo Shen 35392dfa619SBo Shen static int atmel_pcm_resume(struct snd_soc_dai *dai) 35492dfa619SBo Shen { 35592dfa619SBo Shen struct snd_pcm_runtime *runtime = dai->runtime; 35692dfa619SBo Shen struct atmel_runtime_data *prtd; 35792dfa619SBo Shen struct atmel_pcm_dma_params *params; 35892dfa619SBo Shen 35992dfa619SBo Shen if (!runtime) 36092dfa619SBo Shen return 0; 36192dfa619SBo Shen 36292dfa619SBo Shen prtd = runtime->private_data; 36392dfa619SBo Shen params = prtd->params; 36492dfa619SBo Shen 36592dfa619SBo Shen /* restore the PDC registers and enable the PDC */ 36692dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); 36792dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); 36892dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); 36992dfa619SBo Shen ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); 37092dfa619SBo Shen 37192dfa619SBo Shen ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); 37292dfa619SBo Shen return 0; 37392dfa619SBo Shen } 37492dfa619SBo Shen #else 37592dfa619SBo Shen #define atmel_pcm_suspend NULL 37692dfa619SBo Shen #define atmel_pcm_resume NULL 37792dfa619SBo Shen #endif 37892dfa619SBo Shen 37992dfa619SBo Shen static struct snd_soc_platform_driver atmel_soc_platform = { 38092dfa619SBo Shen .ops = &atmel_pcm_ops, 38192dfa619SBo Shen .pcm_new = atmel_pcm_new, 38292dfa619SBo Shen .pcm_free = atmel_pcm_free, 38392dfa619SBo Shen .suspend = atmel_pcm_suspend, 38492dfa619SBo Shen .resume = atmel_pcm_resume, 38592dfa619SBo Shen }; 38692dfa619SBo Shen 38792dfa619SBo Shen int atmel_pcm_pdc_platform_register(struct device *dev) 38892dfa619SBo Shen { 38992dfa619SBo Shen return snd_soc_register_platform(dev, &atmel_soc_platform); 39092dfa619SBo Shen } 39192dfa619SBo Shen EXPORT_SYMBOL(atmel_pcm_pdc_platform_register); 39292dfa619SBo Shen 39392dfa619SBo Shen void atmel_pcm_pdc_platform_unregister(struct device *dev) 39492dfa619SBo Shen { 39592dfa619SBo Shen snd_soc_unregister_platform(dev); 39692dfa619SBo Shen } 39792dfa619SBo Shen EXPORT_SYMBOL(atmel_pcm_pdc_platform_unregister); 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