1 /* 2 * Au1000/Au1500/Au1100 Audio DMA support. 3 * 4 * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com> 5 * 6 * copied almost verbatim from the old ALSA driver, written by 7 * Charles Eidsness <charles@cooper-street.com> 8 */ 9 10 #include <linux/module.h> 11 #include <linux/init.h> 12 #include <linux/platform_device.h> 13 #include <linux/slab.h> 14 #include <linux/dma-mapping.h> 15 #include <sound/core.h> 16 #include <sound/pcm.h> 17 #include <sound/pcm_params.h> 18 #include <sound/soc.h> 19 #include <asm/mach-au1x00/au1000.h> 20 #include <asm/mach-au1x00/au1000_dma.h> 21 22 #include "psc.h" 23 24 #define ALCHEMY_PCM_FMTS \ 25 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ 26 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ 27 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \ 28 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \ 29 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \ 30 0) 31 32 struct pcm_period { 33 u32 start; 34 u32 relative_end; /* relative to start of buffer */ 35 struct pcm_period *next; 36 }; 37 38 struct audio_stream { 39 struct snd_pcm_substream *substream; 40 int dma; 41 struct pcm_period *buffer; 42 unsigned int period_size; 43 unsigned int periods; 44 }; 45 46 struct alchemy_pcm_ctx { 47 struct audio_stream stream[2]; /* playback & capture */ 48 }; 49 50 static void au1000_release_dma_link(struct audio_stream *stream) 51 { 52 struct pcm_period *pointer; 53 struct pcm_period *pointer_next; 54 55 stream->period_size = 0; 56 stream->periods = 0; 57 pointer = stream->buffer; 58 if (!pointer) 59 return; 60 do { 61 pointer_next = pointer->next; 62 kfree(pointer); 63 pointer = pointer_next; 64 } while (pointer != stream->buffer); 65 stream->buffer = NULL; 66 } 67 68 static int au1000_setup_dma_link(struct audio_stream *stream, 69 unsigned int period_bytes, 70 unsigned int periods) 71 { 72 struct snd_pcm_substream *substream = stream->substream; 73 struct snd_pcm_runtime *runtime = substream->runtime; 74 struct pcm_period *pointer; 75 unsigned long dma_start; 76 int i; 77 78 dma_start = virt_to_phys(runtime->dma_area); 79 80 if (stream->period_size == period_bytes && 81 stream->periods == periods) 82 return 0; /* not changed */ 83 84 au1000_release_dma_link(stream); 85 86 stream->period_size = period_bytes; 87 stream->periods = periods; 88 89 stream->buffer = kmalloc(sizeof(struct pcm_period), GFP_KERNEL); 90 if (!stream->buffer) 91 return -ENOMEM; 92 pointer = stream->buffer; 93 for (i = 0; i < periods; i++) { 94 pointer->start = (u32)(dma_start + (i * period_bytes)); 95 pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1); 96 if (i < periods - 1) { 97 pointer->next = kmalloc(sizeof(struct pcm_period), 98 GFP_KERNEL); 99 if (!pointer->next) { 100 au1000_release_dma_link(stream); 101 return -ENOMEM; 102 } 103 pointer = pointer->next; 104 } 105 } 106 pointer->next = stream->buffer; 107 return 0; 108 } 109 110 static void au1000_dma_stop(struct audio_stream *stream) 111 { 112 if (stream->buffer) 113 disable_dma(stream->dma); 114 } 115 116 static void au1000_dma_start(struct audio_stream *stream) 117 { 118 if (!stream->buffer) 119 return; 120 121 init_dma(stream->dma); 122 if (get_dma_active_buffer(stream->dma) == 0) { 123 clear_dma_done0(stream->dma); 124 set_dma_addr0(stream->dma, stream->buffer->start); 125 set_dma_count0(stream->dma, stream->period_size >> 1); 126 set_dma_addr1(stream->dma, stream->buffer->next->start); 127 set_dma_count1(stream->dma, stream->period_size >> 1); 128 } else { 129 clear_dma_done1(stream->dma); 130 set_dma_addr1(stream->dma, stream->buffer->start); 131 set_dma_count1(stream->dma, stream->period_size >> 1); 132 set_dma_addr0(stream->dma, stream->buffer->next->start); 133 set_dma_count0(stream->dma, stream->period_size >> 1); 134 } 135 enable_dma_buffers(stream->dma); 136 start_dma(stream->dma); 137 } 138 139 static irqreturn_t au1000_dma_interrupt(int irq, void *ptr) 140 { 141 struct audio_stream *stream = (struct audio_stream *)ptr; 142 struct snd_pcm_substream *substream = stream->substream; 143 144 switch (get_dma_buffer_done(stream->dma)) { 145 case DMA_D0: 146 stream->buffer = stream->buffer->next; 147 clear_dma_done0(stream->dma); 148 set_dma_addr0(stream->dma, stream->buffer->next->start); 149 set_dma_count0(stream->dma, stream->period_size >> 1); 150 enable_dma_buffer0(stream->dma); 151 break; 152 case DMA_D1: 153 stream->buffer = stream->buffer->next; 154 clear_dma_done1(stream->dma); 155 set_dma_addr1(stream->dma, stream->buffer->next->start); 156 set_dma_count1(stream->dma, stream->period_size >> 1); 157 enable_dma_buffer1(stream->dma); 158 break; 159 case (DMA_D0 | DMA_D1): 160 pr_debug("DMA %d missed interrupt.\n", stream->dma); 161 au1000_dma_stop(stream); 162 au1000_dma_start(stream); 163 break; 164 case (~DMA_D0 & ~DMA_D1): 165 pr_debug("DMA %d empty irq.\n", stream->dma); 166 } 167 snd_pcm_period_elapsed(substream); 168 return IRQ_HANDLED; 169 } 170 171 static const struct snd_pcm_hardware alchemy_pcm_hardware = { 172 .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 173 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH, 174 .formats = ALCHEMY_PCM_FMTS, 175 .rates = SNDRV_PCM_RATE_8000_192000, 176 .rate_min = SNDRV_PCM_RATE_8000, 177 .rate_max = SNDRV_PCM_RATE_192000, 178 .channels_min = 2, 179 .channels_max = 2, 180 .period_bytes_min = 1024, 181 .period_bytes_max = 16 * 1024 - 1, 182 .periods_min = 4, 183 .periods_max = 255, 184 .buffer_bytes_max = 128 * 1024, 185 .fifo_size = 16, 186 }; 187 188 static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss) 189 { 190 struct snd_soc_pcm_runtime *rtd = ss->private_data; 191 return snd_soc_platform_get_drvdata(rtd->platform); 192 } 193 194 static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss) 195 { 196 struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss); 197 return &(ctx->stream[ss->stream]); 198 } 199 200 static int alchemy_pcm_open(struct snd_pcm_substream *substream) 201 { 202 struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream); 203 struct snd_soc_pcm_runtime *rtd = substream->private_data; 204 int *dmaids, s = substream->stream; 205 char *name; 206 207 dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); 208 if (!dmaids) 209 return -ENODEV; /* whoa, has ordering changed? */ 210 211 /* DMA setup */ 212 name = (s == SNDRV_PCM_STREAM_PLAYBACK) ? "audio-tx" : "audio-rx"; 213 ctx->stream[s].dma = request_au1000_dma(dmaids[s], name, 214 au1000_dma_interrupt, 0, 215 &ctx->stream[s]); 216 set_dma_mode(ctx->stream[s].dma, 217 get_dma_mode(ctx->stream[s].dma) & ~DMA_NC); 218 219 ctx->stream[s].substream = substream; 220 ctx->stream[s].buffer = NULL; 221 snd_soc_set_runtime_hwparams(substream, &alchemy_pcm_hardware); 222 223 return 0; 224 } 225 226 static int alchemy_pcm_close(struct snd_pcm_substream *substream) 227 { 228 struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream); 229 int stype = substream->stream; 230 231 ctx->stream[stype].substream = NULL; 232 free_au1000_dma(ctx->stream[stype].dma); 233 234 return 0; 235 } 236 237 static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream, 238 struct snd_pcm_hw_params *hw_params) 239 { 240 struct audio_stream *stream = ss_to_as(substream); 241 int err; 242 243 err = snd_pcm_lib_malloc_pages(substream, 244 params_buffer_bytes(hw_params)); 245 if (err < 0) 246 return err; 247 err = au1000_setup_dma_link(stream, 248 params_period_bytes(hw_params), 249 params_periods(hw_params)); 250 if (err) 251 snd_pcm_lib_free_pages(substream); 252 253 return err; 254 } 255 256 static int alchemy_pcm_hw_free(struct snd_pcm_substream *substream) 257 { 258 struct audio_stream *stream = ss_to_as(substream); 259 au1000_release_dma_link(stream); 260 return snd_pcm_lib_free_pages(substream); 261 } 262 263 static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 264 { 265 struct audio_stream *stream = ss_to_as(substream); 266 int err = 0; 267 268 switch (cmd) { 269 case SNDRV_PCM_TRIGGER_START: 270 au1000_dma_start(stream); 271 break; 272 case SNDRV_PCM_TRIGGER_STOP: 273 au1000_dma_stop(stream); 274 break; 275 default: 276 err = -EINVAL; 277 break; 278 } 279 return err; 280 } 281 282 static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss) 283 { 284 struct audio_stream *stream = ss_to_as(ss); 285 long location; 286 287 location = get_dma_residue(stream->dma); 288 location = stream->buffer->relative_end - location; 289 if (location == -1) 290 location = 0; 291 return bytes_to_frames(ss->runtime, location); 292 } 293 294 static struct snd_pcm_ops alchemy_pcm_ops = { 295 .open = alchemy_pcm_open, 296 .close = alchemy_pcm_close, 297 .ioctl = snd_pcm_lib_ioctl, 298 .hw_params = alchemy_pcm_hw_params, 299 .hw_free = alchemy_pcm_hw_free, 300 .trigger = alchemy_pcm_trigger, 301 .pointer = alchemy_pcm_pointer, 302 }; 303 304 static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm) 305 { 306 snd_pcm_lib_preallocate_free_for_all(pcm); 307 } 308 309 static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd) 310 { 311 struct snd_pcm *pcm = rtd->pcm; 312 313 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, 314 snd_dma_continuous_data(GFP_KERNEL), 65536, (4096 * 1024) - 1); 315 316 return 0; 317 } 318 319 static struct snd_soc_platform_driver alchemy_pcm_soc_platform = { 320 .ops = &alchemy_pcm_ops, 321 .pcm_new = alchemy_pcm_new, 322 .pcm_free = alchemy_pcm_free_dma_buffers, 323 }; 324 325 static int alchemy_pcm_drvprobe(struct platform_device *pdev) 326 { 327 struct alchemy_pcm_ctx *ctx; 328 329 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 330 if (!ctx) 331 return -ENOMEM; 332 333 platform_set_drvdata(pdev, ctx); 334 335 return snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform); 336 } 337 338 static int alchemy_pcm_drvremove(struct platform_device *pdev) 339 { 340 snd_soc_unregister_platform(&pdev->dev); 341 342 return 0; 343 } 344 345 static struct platform_driver alchemy_pcmdma_driver = { 346 .driver = { 347 .name = "alchemy-pcm-dma", 348 .owner = THIS_MODULE, 349 }, 350 .probe = alchemy_pcm_drvprobe, 351 .remove = alchemy_pcm_drvremove, 352 }; 353 354 module_platform_driver(alchemy_pcmdma_driver); 355 356 MODULE_LICENSE("GPL"); 357 MODULE_DESCRIPTION("Au1000/Au1500/Au1100 Audio DMA driver"); 358 MODULE_AUTHOR("Manuel Lauss"); 359