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