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