1 /* 2 * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip 3 * 4 * Author: Nicolas Pitre 5 * Created: Nov 30, 2004 6 * Copyright: (C) 2004 MontaVista Software, Inc. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/init.h> 15 #include <linux/platform_device.h> 16 #include <linux/slab.h> 17 #include <linux/dma-mapping.h> 18 19 #include <sound/driver.h> 20 #include <sound/core.h> 21 #include <sound/pcm.h> 22 #include <sound/pcm_params.h> 23 #include <sound/soc.h> 24 25 #include <asm/dma.h> 26 #include <asm/hardware.h> 27 #include <asm/arch/pxa-regs.h> 28 #include <asm/arch/audio.h> 29 30 #include "pxa2xx-pcm.h" 31 32 static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { 33 .info = SNDRV_PCM_INFO_MMAP | 34 SNDRV_PCM_INFO_MMAP_VALID | 35 SNDRV_PCM_INFO_INTERLEAVED | 36 SNDRV_PCM_INFO_PAUSE | 37 SNDRV_PCM_INFO_RESUME, 38 .formats = SNDRV_PCM_FMTBIT_S16_LE | 39 SNDRV_PCM_FMTBIT_S24_LE | 40 SNDRV_PCM_FMTBIT_S32_LE, 41 .period_bytes_min = 32, 42 .period_bytes_max = 8192 - 32, 43 .periods_min = 1, 44 .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc), 45 .buffer_bytes_max = 128 * 1024, 46 .fifo_size = 32, 47 }; 48 49 struct pxa2xx_runtime_data { 50 int dma_ch; 51 struct pxa2xx_pcm_dma_params *params; 52 pxa_dma_desc *dma_desc_array; 53 dma_addr_t dma_desc_array_phys; 54 }; 55 56 static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) 57 { 58 struct snd_pcm_substream *substream = dev_id; 59 struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; 60 int dcsr; 61 62 dcsr = DCSR(dma_ch); 63 DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; 64 65 if (dcsr & DCSR_ENDINTR) { 66 snd_pcm_period_elapsed(substream); 67 } else { 68 printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", 69 prtd->params->name, dma_ch, dcsr ); 70 } 71 } 72 73 static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, 74 struct snd_pcm_hw_params *params) 75 { 76 struct snd_pcm_runtime *runtime = substream->runtime; 77 struct pxa2xx_runtime_data *prtd = runtime->private_data; 78 struct snd_soc_pcm_runtime *rtd = substream->private_data; 79 struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; 80 size_t totsize = params_buffer_bytes(params); 81 size_t period = params_period_bytes(params); 82 pxa_dma_desc *dma_desc; 83 dma_addr_t dma_buff_phys, next_desc_phys; 84 int ret; 85 86 /* return if this is a bufferless transfer e.g. 87 * codec <--> BT codec or GSM modem -- lg FIXME */ 88 if (!dma) 89 return 0; 90 91 /* this may get called several times by oss emulation 92 * with different params */ 93 if (prtd->params == NULL) { 94 prtd->params = dma; 95 ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, 96 pxa2xx_pcm_dma_irq, substream); 97 if (ret < 0) 98 return ret; 99 prtd->dma_ch = ret; 100 } else if (prtd->params != dma) { 101 pxa_free_dma(prtd->dma_ch); 102 prtd->params = dma; 103 ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, 104 pxa2xx_pcm_dma_irq, substream); 105 if (ret < 0) 106 return ret; 107 prtd->dma_ch = ret; 108 } 109 110 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 111 runtime->dma_bytes = totsize; 112 113 dma_desc = prtd->dma_desc_array; 114 next_desc_phys = prtd->dma_desc_array_phys; 115 dma_buff_phys = runtime->dma_addr; 116 do { 117 next_desc_phys += sizeof(pxa_dma_desc); 118 dma_desc->ddadr = next_desc_phys; 119 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 120 dma_desc->dsadr = dma_buff_phys; 121 dma_desc->dtadr = prtd->params->dev_addr; 122 } else { 123 dma_desc->dsadr = prtd->params->dev_addr; 124 dma_desc->dtadr = dma_buff_phys; 125 } 126 if (period > totsize) 127 period = totsize; 128 dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN; 129 dma_desc++; 130 dma_buff_phys += period; 131 } while (totsize -= period); 132 dma_desc[-1].ddadr = prtd->dma_desc_array_phys; 133 134 return 0; 135 } 136 137 static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) 138 { 139 struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; 140 141 if (prtd && prtd->params) 142 *prtd->params->drcmr = 0; 143 144 if (prtd->dma_ch) { 145 snd_pcm_set_runtime_buffer(substream, NULL); 146 pxa_free_dma(prtd->dma_ch); 147 prtd->dma_ch = 0; 148 } 149 150 return 0; 151 } 152 153 static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) 154 { 155 struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; 156 157 DCSR(prtd->dma_ch) &= ~DCSR_RUN; 158 DCSR(prtd->dma_ch) = 0; 159 DCMD(prtd->dma_ch) = 0; 160 *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; 161 162 return 0; 163 } 164 165 static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 166 { 167 struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; 168 int ret = 0; 169 170 switch (cmd) { 171 case SNDRV_PCM_TRIGGER_START: 172 DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; 173 DCSR(prtd->dma_ch) = DCSR_RUN; 174 break; 175 176 case SNDRV_PCM_TRIGGER_STOP: 177 case SNDRV_PCM_TRIGGER_SUSPEND: 178 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 179 DCSR(prtd->dma_ch) &= ~DCSR_RUN; 180 break; 181 182 case SNDRV_PCM_TRIGGER_RESUME: 183 DCSR(prtd->dma_ch) |= DCSR_RUN; 184 break; 185 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 186 DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; 187 DCSR(prtd->dma_ch) |= DCSR_RUN; 188 break; 189 190 default: 191 ret = -EINVAL; 192 } 193 194 return ret; 195 } 196 197 static snd_pcm_uframes_t 198 pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) 199 { 200 struct snd_pcm_runtime *runtime = substream->runtime; 201 struct pxa2xx_runtime_data *prtd = runtime->private_data; 202 203 dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 204 DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch); 205 snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr); 206 207 if (x == runtime->buffer_size) 208 x = 0; 209 return x; 210 } 211 212 static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) 213 { 214 struct snd_pcm_runtime *runtime = substream->runtime; 215 struct pxa2xx_runtime_data *prtd; 216 int ret; 217 218 snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware); 219 220 /* 221 * For mysterious reasons (and despite what the manual says) 222 * playback samples are lost if the DMA count is not a multiple 223 * of the DMA burst size. Let's add a rule to enforce that. 224 */ 225 ret = snd_pcm_hw_constraint_step(runtime, 0, 226 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); 227 if (ret) 228 goto out; 229 230 ret = snd_pcm_hw_constraint_step(runtime, 0, 231 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); 232 if (ret) 233 goto out; 234 235 ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 236 if (ret < 0) 237 goto out; 238 239 prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL); 240 if (prtd == NULL) { 241 ret = -ENOMEM; 242 goto out; 243 } 244 245 prtd->dma_desc_array = 246 dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, 247 &prtd->dma_desc_array_phys, GFP_KERNEL); 248 if (!prtd->dma_desc_array) { 249 ret = -ENOMEM; 250 goto err1; 251 } 252 253 runtime->private_data = prtd; 254 return 0; 255 256 err1: 257 kfree(prtd); 258 out: 259 return ret; 260 } 261 262 static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) 263 { 264 struct snd_pcm_runtime *runtime = substream->runtime; 265 struct pxa2xx_runtime_data *prtd = runtime->private_data; 266 267 dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, 268 prtd->dma_desc_array, prtd->dma_desc_array_phys); 269 kfree(prtd); 270 return 0; 271 } 272 273 static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, 274 struct vm_area_struct *vma) 275 { 276 struct snd_pcm_runtime *runtime = substream->runtime; 277 return dma_mmap_writecombine(substream->pcm->card->dev, vma, 278 runtime->dma_area, 279 runtime->dma_addr, 280 runtime->dma_bytes); 281 } 282 283 struct snd_pcm_ops pxa2xx_pcm_ops = { 284 .open = pxa2xx_pcm_open, 285 .close = pxa2xx_pcm_close, 286 .ioctl = snd_pcm_lib_ioctl, 287 .hw_params = pxa2xx_pcm_hw_params, 288 .hw_free = pxa2xx_pcm_hw_free, 289 .prepare = pxa2xx_pcm_prepare, 290 .trigger = pxa2xx_pcm_trigger, 291 .pointer = pxa2xx_pcm_pointer, 292 .mmap = pxa2xx_pcm_mmap, 293 }; 294 295 static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) 296 { 297 struct snd_pcm_substream *substream = pcm->streams[stream].substream; 298 struct snd_dma_buffer *buf = &substream->dma_buffer; 299 size_t size = pxa2xx_pcm_hardware.buffer_bytes_max; 300 buf->dev.type = SNDRV_DMA_TYPE_DEV; 301 buf->dev.dev = pcm->card->dev; 302 buf->private_data = NULL; 303 buf->area = dma_alloc_writecombine(pcm->card->dev, size, 304 &buf->addr, GFP_KERNEL); 305 if (!buf->area) 306 return -ENOMEM; 307 buf->bytes = size; 308 return 0; 309 } 310 311 static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) 312 { 313 struct snd_pcm_substream *substream; 314 struct snd_dma_buffer *buf; 315 int stream; 316 317 for (stream = 0; stream < 2; stream++) { 318 substream = pcm->streams[stream].substream; 319 if (!substream) 320 continue; 321 322 buf = &substream->dma_buffer; 323 if (!buf->area) 324 continue; 325 326 dma_free_writecombine(pcm->card->dev, buf->bytes, 327 buf->area, buf->addr); 328 buf->area = NULL; 329 } 330 } 331 332 static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; 333 334 int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, 335 struct snd_pcm *pcm) 336 { 337 int ret = 0; 338 339 if (!card->dev->dma_mask) 340 card->dev->dma_mask = &pxa2xx_pcm_dmamask; 341 if (!card->dev->coherent_dma_mask) 342 card->dev->coherent_dma_mask = DMA_32BIT_MASK; 343 344 if (dai->playback.channels_min) { 345 ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, 346 SNDRV_PCM_STREAM_PLAYBACK); 347 if (ret) 348 goto out; 349 } 350 351 if (dai->capture.channels_min) { 352 ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, 353 SNDRV_PCM_STREAM_CAPTURE); 354 if (ret) 355 goto out; 356 } 357 out: 358 return ret; 359 } 360 361 struct snd_soc_platform pxa2xx_soc_platform = { 362 .name = "pxa2xx-audio", 363 .pcm_ops = &pxa2xx_pcm_ops, 364 .pcm_new = pxa2xx_pcm_new, 365 .pcm_free = pxa2xx_pcm_free_dma_buffers, 366 }; 367 368 EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); 369 370 MODULE_AUTHOR("Nicolas Pitre"); 371 MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); 372 MODULE_LICENSE("GPL"); 373