davinci-pcm.c

来源:互联网 发布:机器视觉偏重算法吗 编辑:程序博客网 时间:2024/06/15 21:21

davinci-pcm.c

001     /**
002       * ALSA PCM interface for the TI DAVINCI processor
003       *
004       * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
005       * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
006       * added SRAM ping/pong (C) 2008 Troy Kisky <troy.kisky@boundarydevices.com>
007       *
008       * This program is free software; you can redistribute it and/or modify
009       * it under the terms of the GNU General Public License version 2 as
010       * published by the Free Software Foundation.
011       */
012     
013     #include <linux/module.h>
014     #include <linux/init.h>
015     #include <linux/platform_device.h>
016     #include <linux/slab.h>
017     #include <linux/dma-mapping.h>
018     #include <linux/kernel.h>
019     
020     #include <sound/core.h>
021     #include <sound/pcm.h>
022     #include <sound/pcm_params.h>
023     #include <sound/soc.h>
024     
025     #include <asm/dma.h>
026     #include <mach/edma.h>
027     #include <mach/sram.h>
028     
029     #include "davinci-pcm.h"
030     
031     #ifdef DEBUG
032     static void print_buf_info( int slot, char *name)
033     {
034          struct edmacc_param p;
035          if (slot < 0)
036              return ;
037          edma_read_slot(slot, &p);
038          printk(KERN_DEBUG "%s: 0x%x, opt=%x, src=%x, a_b_cnt=%x dst=%x/n" ,
039                  name, slot, p.opt, p.src, p.a_b_cnt, p.dst);
040          printk(KERN_DEBUG "    src_dst_bidx=%x link_bcntrld=%x src_dst_cidx=%x ccnt=%x/n" ,
041                  p.src_dst_bidx, p.link_bcntrld, p.src_dst_cidx, p.ccnt);
042     }
043     #else
044     static void print_buf_info( int slot, char *name)
045     {
046     }
047     #endif
048     
049     static struct snd_pcm_hardware pcm_hardware_playback = {
050          .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
051               SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
052               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
053          .formats = (SNDRV_PCM_FMTBIT_S16_LE),
054          .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
055                SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
056                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
057                SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
058                SNDRV_PCM_RATE_KNOT),
059          .rate_min = 8000,
060          .rate_max = 96000,
061          .channels_min = 2,
062          .channels_max = 2,
063          .buffer_bytes_max = 128 * 1024,
064          .period_bytes_min = 32,
065          .period_bytes_max = 8 * 1024,
066          .periods_min = 16,
067          .periods_max = 255,
068          .fifo_size = 0,
069     };
070     
071     static struct snd_pcm_hardware pcm_hardware_capture = {
072          .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
073               SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
074               SNDRV_PCM_INFO_PAUSE),
075          .formats = (SNDRV_PCM_FMTBIT_S16_LE),
076          .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
077                SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
078                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
079                SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
080                SNDRV_PCM_RATE_KNOT),
081          .rate_min = 8000,
082          .rate_max = 96000,
083          .channels_min = 2,
084          .channels_max = 2,
085          .buffer_bytes_max = 128 * 1024,
086          .period_bytes_min = 32,
087          .period_bytes_max = 8 * 1024,
088          .periods_min = 16,
089          .periods_max = 255,
090          .fifo_size = 0,
091     };
092     
093     /**
094       * How ping/pong works....
095       *
096       * Playback:
097       * ram_params - copys 2*ping_size from start of SDRAM to iram,
098       *  links to ram_link2
099       * ram_link2 - copys rest of SDRAM to iram in ping_size units,
100       *  links to ram_link
101       * ram_link - copys entire SDRAM to iram in ping_size uints,
102       *  links to self
103       *
104       * asp_params - same as asp_link[0]
105       * asp_link[0] - copys from lower half of iram to asp port
106       *  links to asp_link[1], triggers iram copy event on completion
107       * asp_link[1] - copys from upper half of iram to asp port
108       *  links to asp_link[0], triggers iram copy event on completion
109       *  triggers interrupt only needed to let upper SOC levels update position
110       *  in stream on completion
111       *
112       * When playback is started:
113       *  ram_params started
114       *  asp_params started
115       *
116       * Capture:
117       * ram_params - same as ram_link,
118       *  links to ram_link
119       * ram_link - same as playback
120       *  links to self
121       *
122       * asp_params - same as playback
123       * asp_link[0] - same as playback
124       * asp_link[1] - same as playback
125       *
126       * When capture is started:
127       *  asp_params started
128       */
129     struct davinci_runtime_data {
130          spinlock_t lock;
131          int period;     /** current DMA period */
132          int asp_channel;    /** Master DMA channel */
133          int asp_link[2];    /** asp parameter link channel, ping/pong */
134          struct davinci_pcm_dma_params *params;  /** DMA params */
135          int ram_channel;
136          int ram_link;
137          int ram_link2;
138          struct edmacc_param asp_params;
139          struct edmacc_param ram_params;
140     };
141     
142     /**
143       * Not used with ping/pong
144       */
145     static void davinci_pcm_enqueue_dma( struct snd_pcm_substream *substream)
146     {
147          struct davinci_runtime_data *prtd = substream->runtime->private_data;
148          struct snd_pcm_runtime *runtime = substream->runtime;
149          int link = prtd->asp_link[0];
150          unsigned int period_size;
151          unsigned int dma_offset;
152          dma_addr_t dma_pos;
153          dma_addr_t src, dst;
154          unsigned short src_bidx, dst_bidx;
155          unsigned short src_cidx, dst_cidx;
156          unsigned int data_type;
157          unsigned short acnt;
158          unsigned int count;
159          unsigned int fifo_level;
160     
161          period_size = snd_pcm_lib_period_bytes(substream);
162          dma_offset = prtd->period * period_size;
163          dma_pos = runtime->dma_addr + dma_offset;
164          fifo_level = prtd->params->fifo_level;
165     
166          pr_debug( "davinci_pcm: audio_set_dma_params_play channel = %d "
167              "dma_ptr = %x period_size=%x/n" , link, dma_pos, period_size);
168     
169          data_type = prtd->params->data_type;
170          count = period_size / data_type;
171          if (fifo_level)
172              count /= fifo_level;
173     
174          if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
175              src = dma_pos;
176              dst = prtd->params->dma_addr;
177              src_bidx = data_type;
178              dst_bidx = 0;
179              src_cidx = data_type * fifo_level;
180              dst_cidx = 0;
181          } else {
182              src = prtd->params->dma_addr;
183              dst = dma_pos;
184              src_bidx = 0;
185              dst_bidx = data_type;
186              src_cidx = 0;
187              dst_cidx = data_type * fifo_level;
188          }
189     
190          acnt = prtd->params->acnt;
191          edma_set_src(link, src, INCR, W8BIT);
192          edma_set_dest(link, dst, INCR, W8BIT);
193     
194          edma_set_src_index(link, src_bidx, src_cidx);
195          edma_set_dest_index(link, dst_bidx, dst_cidx);
196     
197          if (!fifo_level)
198              edma_set_transfer_params(link, acnt, count, 1, 0, ASYNC);
199          else
200              edma_set_transfer_params(link, acnt, fifo_level, count,
201                                  fifo_level, ABSYNC);
202     
203          prtd->period++;
204          if (unlikely(prtd->period >= runtime->periods))
205              prtd->period = 0;
206     }
207     
208     static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
209     {
210          struct snd_pcm_substream *substream = data;
211          struct davinci_runtime_data *prtd = substream->runtime->private_data;
212     
213          print_buf_info(prtd->ram_channel, "i ram_channel" );
214          pr_debug( "davinci_pcm: link=%d, status=0x%x/n" , link, ch_status);
215     
216          if (unlikely(ch_status != DMA_COMPLETE))
217              return ;
218     
219          if (snd_pcm_running(substream)) {
220              if (prtd->ram_channel < 0) {
221                  /** No ping/pong must fix up link dma data*/
222                  spin_lock(&prtd->lock);
223                  davinci_pcm_enqueue_dma(substream);
224                  spin_unlock(&prtd->lock);
225              }
226              snd_pcm_period_elapsed(substream);
227          }
228     }
229     
230     static int allocate_sram( struct snd_pcm_substream *substream, unsigned size,
231              struct snd_pcm_hardware *ppcm)
232     {
233          struct snd_dma_buffer *buf = &substream->dma_buffer;
234          struct snd_dma_buffer *iram_dma = NULL;
235          dma_addr_t iram_phys = 0;
236          void *iram_virt = NULL;
237     
238          if (buf->private_data || !size)
239              return 0;
240     
241          ppcm->period_bytes_max = size;
242          iram_virt = sram_alloc(size, &iram_phys);
243          if (!iram_virt)
244              goto exit1;
245          iram_dma = kzalloc( sizeof (*iram_dma), GFP_KERNEL);
246          if (!iram_dma)
247              goto exit2;
248          iram_dma->area = iram_virt;
249          iram_dma->addr = iram_phys;
250          memset (iram_dma->area, 0, size);
251          iram_dma->bytes = size;
252          buf->private_data = iram_dma;
253          return 0;
254     exit2:
255          if (iram_virt)
256              sram_free(iram_virt, size);
257     exit1:
258          return -ENOMEM;
259     }
260     
261     /**
262       * Only used with ping/pong.
263       * This is called after runtime->dma_addr, period_bytes and data_type are valid
264       */
265     static int ping_pong_dma_setup( struct snd_pcm_substream *substream)
266     {
267          unsigned short ram_src_cidx, ram_dst_cidx;
268          struct snd_pcm_runtime *runtime = substream->runtime;
269          struct davinci_runtime_data *prtd = runtime->private_data;
270          struct snd_dma_buffer *iram_dma =
271              ( struct snd_dma_buffer *)substream->dma_buffer.private_data;
272          struct davinci_pcm_dma_params *params = prtd->params;
273          unsigned int data_type = params->data_type;
274          unsigned int acnt = params->acnt;
275          /** divide by 2 for ping/pong */
276          unsigned int ping_size = snd_pcm_lib_period_bytes(substream) >> 1;
277          int link = prtd->asp_link[1];
278          unsigned int fifo_level = prtd->params->fifo_level;
279          unsigned int count;
280          if ((data_type == 0) || (data_type > 4)) {
281              printk(KERN_ERR "%s: data_type=%i/n" , __func__, data_type);
282              return -EINVAL;
283          }
284          if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
285              dma_addr_t asp_src_pong = iram_dma->addr + ping_size;
286              ram_src_cidx = ping_size;
287              ram_dst_cidx = -ping_size;
288              edma_set_src(link, asp_src_pong, INCR, W8BIT);
289     
290              link = prtd->asp_link[0];
291              edma_set_src_index(link, data_type, data_type * fifo_level);
292              link = prtd->asp_link[1];
293              edma_set_src_index(link, data_type, data_type * fifo_level);
294     
295              link = prtd->ram_link;
296              edma_set_src(link, runtime->dma_addr, INCR, W32BIT);
297          } else {
298              dma_addr_t asp_dst_pong = iram_dma->addr + ping_size;
299              ram_src_cidx = -ping_size;
300              ram_dst_cidx = ping_size;
301              edma_set_dest(link, asp_dst_pong, INCR, W8BIT);
302     
303              link = prtd->asp_link[0];
304              edma_set_dest_index(link, data_type, data_type * fifo_level);
305              link = prtd->asp_link[1];
306              edma_set_dest_index(link, data_type, data_type * fifo_level);
307     
308              link = prtd->ram_link;
309              edma_set_dest(link, runtime->dma_addr, INCR, W32BIT);
310          }
311     
312          if (!fifo_level) {
313              count = ping_size / data_type;
314              edma_set_transfer_params(prtd->asp_link[0], acnt, count,
315                      1, 0, ASYNC);
316              edma_set_transfer_params(prtd->asp_link[1], acnt, count,
317                      1, 0, ASYNC);
318          } else {
319              count = ping_size / (data_type * fifo_level);
320              edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
321                      count, fifo_level, ABSYNC);
322              edma_set_transfer_params(prtd->asp_link[1], acnt, fifo_level,
323                      count, fifo_level, ABSYNC);
324          }
325     
326          link = prtd->ram_link;
327          edma_set_src_index(link, ping_size, ram_src_cidx);
328          edma_set_dest_index(link, ping_size, ram_dst_cidx);
329          edma_set_transfer_params(link, ping_size, 2,
330                  runtime->periods, 2, ASYNC);
331     
332          /** init master params */
333          edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
334          edma_read_slot(prtd->ram_link, &prtd->ram_params);
335          if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
336              struct edmacc_param p_ram;
337              /** Copy entire iram buffer before playback started */
338              prtd->ram_params.a_b_cnt = (1 << 16) | (ping_size << 1);
339              /** 0 dst_bidx */
340              prtd->ram_params.src_dst_bidx = (ping_size << 1);
341              /** 0 dst_cidx */
342              prtd->ram_params.src_dst_cidx = (ping_size << 1);
343              prtd->ram_params.ccnt = 1;
344     
345              /** Skip 1st period */
346              edma_read_slot(prtd->ram_link, &p_ram);
347              p_ram.src += (ping_size << 1);
348              p_ram.ccnt -= 1;
349              edma_write_slot(prtd->ram_link2, &p_ram);
350              /**
351               * When 1st started, ram -> iram dma channel will fill the
352               * entire iram.  Then, whenever a ping/pong asp buffer finishes,
353               * 1/2 iram will be filled.
354               */
355              prtd->ram_params.link_bcntrld =
356                  EDMA_CHAN_SLOT(prtd->ram_link2) << 5;
357          }
358          return 0;
359     }
360     
361     /** 1 asp tx or rx channel using 2 parameter channels
362       * 1 ram to/from iram channel using 1 parameter channel
363       *
364       * Playback
365       * ram copy channel kicks off first,
366       * 1st ram copy of entire iram buffer completion kicks off asp channel
367       * asp tcc always kicks off ram copy of 1/2 iram buffer
368       *
369       * Record
370       * asp channel starts, tcc kicks off ram copy
371       */
372     static int request_ping_pong( struct snd_pcm_substream *substream,
373              struct davinci_runtime_data *prtd,
374              struct snd_dma_buffer *iram_dma)
375     {
376          dma_addr_t asp_src_ping;
377          dma_addr_t asp_dst_ping;
378          int link;
379          struct davinci_pcm_dma_params *params = prtd->params;
380     
381          /** Request ram master channel */
382          link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
383                        davinci_pcm_dma_irq, substream,
384                        prtd->params->ram_chan_q);
385          if (link < 0)
386              goto exit1;
387     
388          /** Request ram link channel */
389          link = prtd->ram_link = edma_alloc_slot(
390                  EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
391          if (link < 0)
392              goto exit2;
393     
394          link = prtd->asp_link[1] = edma_alloc_slot(
395                  EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
396          if (link < 0)
397              goto exit3;
398     
399          prtd->ram_link2 = -1;
400          if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
401              link = prtd->ram_link2 = edma_alloc_slot(
402                  EDMA_CTLR(prtd->ram_channel), EDMA_SLOT_ANY);
403              if (link < 0)
404                  goto exit4;
405          }
406          /** circle ping-pong buffers */
407          edma_link(prtd->asp_link[0], prtd->asp_link[1]);
408          edma_link(prtd->asp_link[1], prtd->asp_link[0]);
409          /** circle ram buffers */
410          edma_link(prtd->ram_link, prtd->ram_link);
411     
412          if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
413              asp_src_ping = iram_dma->addr;
414              asp_dst_ping = params->dma_addr; /** fifo */
415          } else {
416              asp_src_ping = params->dma_addr; /** fifo */
417              asp_dst_ping = iram_dma->addr;
418          }
419          /** ping */
420          link = prtd->asp_link[0];
421          edma_set_src(link, asp_src_ping, INCR, W16BIT);
422          edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
423          edma_set_src_index(link, 0, 0);
424          edma_set_dest_index(link, 0, 0);
425     
426          edma_read_slot(link, &prtd->asp_params);
427          prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
428          prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f);
429          edma_write_slot(link, &prtd->asp_params);
430     
431          /** pong */
432          link = prtd->asp_link[1];
433          edma_set_src(link, asp_src_ping, INCR, W16BIT);
434          edma_set_dest(link, asp_dst_ping, INCR, W16BIT);
435          edma_set_src_index(link, 0, 0);
436          edma_set_dest_index(link, 0, 0);
437     
438          edma_read_slot(link, &prtd->asp_params);
439          prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
440          /** interrupt after every pong completion */
441          prtd->asp_params.opt |= TCINTEN | TCCHEN |
442              EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel));
443          edma_write_slot(link, &prtd->asp_params);
444     
445          /** ram */
446          link = prtd->ram_link;
447          edma_set_src(link, iram_dma->addr, INCR, W32BIT);
448          edma_set_dest(link, iram_dma->addr, INCR, W32BIT);
449          pr_debug( "%s: audio dma channels/slots in use for ram:%u %u %u,"
450              "for asp:%u %u %u/n" , __func__,
451              prtd->ram_channel, prtd->ram_link, prtd->ram_link2,
452              prtd->asp_channel, prtd->asp_link[0],
453              prtd->asp_link[1]);
454          return 0;
455     exit4:
456          edma_free_channel(prtd->asp_link[1]);
457          prtd->asp_link[1] = -1;
458     exit3:
459          edma_free_channel(prtd->ram_link);
460          prtd->ram_link = -1;
461     exit2:
462          edma_free_channel(prtd->ram_channel);
463          prtd->ram_channel = -1;
464     exit1:
465          return link;
466     }
467     
468     static int davinci_pcm_dma_request( struct snd_pcm_substream *substream)
469     {
470          struct snd_dma_buffer *iram_dma;
471          struct davinci_runtime_data *prtd = substream->runtime->private_data;
472          struct davinci_pcm_dma_params *params = prtd->params;
473          int link;
474     
475          if (!params)
476              return -ENODEV;
477     
478          /** Request asp master DMA channel */
479          link = prtd->asp_channel = edma_alloc_channel(params->channel,
480                  davinci_pcm_dma_irq, substream,
481                  prtd->params->asp_chan_q);
482          if (link < 0)
483              goto exit1;
484     
485          /** Request asp link channels */
486          link = prtd->asp_link[0] = edma_alloc_slot(
487                  EDMA_CTLR(prtd->asp_channel), EDMA_SLOT_ANY);
488          if (link < 0)
489              goto exit2;
490     
491          iram_dma = ( struct snd_dma_buffer *)substream->dma_buffer.private_data;
492          if (iram_dma) {
493              if (request_ping_pong(substream, prtd, iram_dma) == 0)
494                  return 0;
495              printk(KERN_WARNING "%s: dma channel allocation failed,"
496                      "not using sram/n" , __func__);
497          }
498     
499          /** Issue transfer completion IRQ when the channel completes a
500           * transfer, then always reload from the same slot (by a kind
501           * of loopback link).  The completion IRQ handler will update
502           * the reload slot with a new buffer.
503           *
504           * REVISIT save p_ram here after setting up everything except
505           * the buffer and its length (ccnt) ... use it as a template
506           * so davinci_pcm_enqueue_dma() takes less time in IRQ.
507           */
508          edma_read_slot(link, &prtd->asp_params);
509          prtd->asp_params.opt |= TCINTEN |
510              EDMA_TCC(EDMA_CHAN_SLOT(prtd->asp_channel));
511          prtd->asp_params.link_bcntrld = EDMA_CHAN_SLOT(link) << 5;
512          edma_write_slot(link, &prtd->asp_params);
513          return 0;
514     exit2:
515          edma_free_channel(prtd->asp_channel);
516          prtd->asp_channel = -1;
517     exit1:
518          return link;
519     }
520     
521     static int davinci_pcm_trigger( struct snd_pcm_substream *substream, int cmd)
522     {
523          struct davinci_runtime_data *prtd = substream->runtime->private_data;
524          int ret = 0;
525     
526          spin_lock(&prtd->lock);
527     
528          switch (cmd) {
529          case SNDRV_PCM_TRIGGER_START:
530          case SNDRV_PCM_TRIGGER_RESUME:
531          case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
532              edma_resume(prtd->asp_channel);
533              break ;
534          case SNDRV_PCM_TRIGGER_STOP:
535          case SNDRV_PCM_TRIGGER_SUSPEND:
536          case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
537              edma_pause(prtd->asp_channel);
538              break ;
539          default :
540              ret = -EINVAL;
541              break ;
542          }
543     
544          spin_unlock(&prtd->lock);
545     
546          return ret;
547     }
548     
549     static int davinci_pcm_prepare( struct snd_pcm_substream *substream)
550     {
551          struct davinci_runtime_data *prtd = substream->runtime->private_data;
552     
553          if (prtd->ram_channel >= 0) {
554              int ret = ping_pong_dma_setup(substream);
555              if (ret < 0)
556                  return ret;
557     
558              edma_write_slot(prtd->ram_channel, &prtd->ram_params);
559              edma_write_slot(prtd->asp_channel, &prtd->asp_params);
560     
561              print_buf_info(prtd->ram_channel, "ram_channel" );
562              print_buf_info(prtd->ram_link, "ram_link" );
563              print_buf_info(prtd->ram_link2, "ram_link2" );
564              print_buf_info(prtd->asp_channel, "asp_channel" );
565              print_buf_info(prtd->asp_link[0], "asp_link[0]" );
566              print_buf_info(prtd->asp_link[1], "asp_link[1]" );
567     
568              if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
569                  /** copy 1st iram buffer */
570                  edma_start(prtd->ram_channel);
571              }
572              edma_start(prtd->asp_channel);
573              return 0;
574          }
575          prtd->period = 0;
576          davinci_pcm_enqueue_dma(substream);
577     
578          /** Copy self-linked parameter RAM entry into master channel */
579          edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
580          edma_write_slot(prtd->asp_channel, &prtd->asp_params);
581          davinci_pcm_enqueue_dma(substream);
582          edma_start(prtd->asp_channel);
583     
584          return 0;
585     }
586     
587     static snd_pcm_uframes_t
588     davinci_pcm_pointer( struct snd_pcm_substream *substream)
589     {
590          struct snd_pcm_runtime *runtime = substream->runtime;
591          struct davinci_runtime_data *prtd = runtime->private_data;
592          unsigned int offset;
593          int asp_count;
594          dma_addr_t asp_src, asp_dst;
595     
596          spin_lock(&prtd->lock);
597          if (prtd->ram_channel >= 0) {
598              int ram_count;
599              int mod_ram;
600              dma_addr_t ram_src, ram_dst;
601              unsigned int period_size = snd_pcm_lib_period_bytes(substream);
602              if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
603                  /** reading ram before asp should be safe
604                   * as long as the asp transfers less than a ping size
605                   * of bytes between the 2 reads
606                   */
607                  edma_get_position(prtd->ram_channel,
608                          &ram_src, &ram_dst);
609                  edma_get_position(prtd->asp_channel,
610                          &asp_src, &asp_dst);
611                  asp_count = asp_src - prtd->asp_params.src;
612                  ram_count = ram_src - prtd->ram_params.src;
613                  mod_ram = ram_count % period_size;
614                  mod_ram -= asp_count;
615                  if (mod_ram < 0)
616                      mod_ram += period_size;
617                  else if (mod_ram == 0) {
618                      if (snd_pcm_running(substream))
619                          mod_ram += period_size;
620                  }
621                  ram_count -= mod_ram;
622                  if (ram_count < 0)
623                      ram_count += period_size * runtime->periods;
624              } else {
625                  edma_get_position(prtd->ram_channel,
626                          &ram_src, &ram_dst);
627                  ram_count = ram_dst - prtd->ram_params.dst;
628              }
629              asp_count = ram_count;
630          } else {
631              edma_get_position(prtd->asp_channel, &asp_src, &asp_dst);
632              if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
633                  asp_count = asp_src - runtime->dma_addr;
634              else
635                  asp_count = asp_dst - runtime->dma_addr;
636          }
637          spin_unlock(&prtd->lock);
638     
639          offset = bytes_to_frames(runtime, asp_count);
640          if (offset >= runtime->buffer_size)
641              offset = 0;
642     
643          return offset;
644     }
645     
646     static int davinci_pcm_open( struct snd_pcm_substream *substream)
647     {
648          struct snd_pcm_runtime *runtime = substream->runtime;
649          struct davinci_runtime_data *prtd;
650          struct snd_pcm_hardware *ppcm;
651          int ret = 0;
652          struct snd_soc_pcm_runtime *rtd = substream->private_data;
653          struct davinci_pcm_dma_params *pa;
654          struct davinci_pcm_dma_params *params;
655     
656          pa = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
657          if (!pa)
658              return -ENODEV;
659          params = &pa[substream->stream];
660     
661          ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
662                  &pcm_hardware_playback : &pcm_hardware_capture;
663          allocate_sram(substream, params->sram_size, ppcm);
664          snd_soc_set_runtime_hwparams(substream, ppcm);
665          /** ensure that buffer size is a multiple of period size */
666          ret = snd_pcm_hw_constraint_integer(runtime,
667                              SNDRV_PCM_HW_PARAM_PERIODS);
668          if (ret < 0)
669              return ret;
670     
671          prtd = kzalloc( sizeof ( struct davinci_runtime_data), GFP_KERNEL);
672          if (prtd == NULL)
673              return -ENOMEM;
674     
675          spin_lock_init(&prtd->lock);
676          prtd->params = params;
677          prtd->asp_channel = -1;
678          prtd->asp_link[0] = prtd->asp_link[1] = -1;
679          prtd->ram_channel = -1;
680          prtd->ram_link = -1;
681          prtd->ram_link2 = -1;
682     
683          runtime->private_data = prtd;
684     
685          ret = davinci_pcm_dma_request(substream);
686          if (ret) {
687              printk(KERN_ERR "davinci_pcm: Failed to get dma channels/n" );
688              kfree(prtd);
689          }
690     
691          return ret;
692     }
693     
694     static int davinci_pcm_close( struct snd_pcm_substream *substream)
695     {
696          struct snd_pcm_runtime *runtime = substream->runtime;
697          struct davinci_runtime_data *prtd = runtime->private_data;
698     
699          if (prtd->ram_channel >= 0)
700              edma_stop(prtd->ram_channel);
701          if (prtd->asp_channel >= 0)
702              edma_stop(prtd->asp_channel);
703          if (prtd->asp_link[0] >= 0)
704              edma_unlink(prtd->asp_link[0]);
705          if (prtd->asp_link[1] >= 0)
706              edma_unlink(prtd->asp_link[1]);
707          if (prtd->ram_link >= 0)
708              edma_unlink(prtd->ram_link);
709     
710          if (prtd->asp_link[0] >= 0)
711              edma_free_slot(prtd->asp_link[0]);
712          if (prtd->asp_link[1] >= 0)
713              edma_free_slot(prtd->asp_link[1]);
714          if (prtd->asp_channel >= 0)
715              edma_free_channel(prtd->asp_channel);
716          if (prtd->ram_link >= 0)
717              edma_free_slot(prtd->ram_link);
718          if (prtd->ram_link2 >= 0)
719              edma_free_slot(prtd->ram_link2);
720          if (prtd->ram_channel >= 0)
721              edma_free_channel(prtd->ram_channel);
722     
723          kfree(prtd);
724     
725          return 0;
726     }
727     
728     static int davinci_pcm_hw_params( struct snd_pcm_substream *substream,
729                       struct snd_pcm_hw_params *hw_params)
730     {
731          return snd_pcm_lib_malloc_pages(substream,
732                          params_buffer_bytes(hw_params));
733     }
734     
735     static int davinci_pcm_hw_free( struct snd_pcm_substream *substream)
736     {
737          return snd_pcm_lib_free_pages(substream);
738     }
739     
740     static int davinci_pcm_mmap( struct snd_pcm_substream *substream,
741                      struct vm_area_struct *vma)
742     {
743          struct snd_pcm_runtime *runtime = substream->runtime;
744     
745          return dma_mmap_writecombine(substream->pcm->card->dev, vma,
746                           runtime->dma_area,
747                           runtime->dma_addr,
748                           runtime->dma_bytes);
749     }
750     
751     static struct snd_pcm_ops davinci_pcm_ops = {
752          .open =     davinci_pcm_open,
753          .close =    davinci_pcm_close,
754          .ioctl =    snd_pcm_lib_ioctl,
755          .hw_params =    davinci_pcm_hw_params,
756          .hw_free =  davinci_pcm_hw_free,
757          .prepare =  davinci_pcm_prepare,
758          .trigger =  davinci_pcm_trigger,
759          .pointer =  davinci_pcm_pointer,
760          .mmap =     davinci_pcm_mmap,
761     };
762     
763     static int davinci_pcm_preallocate_dma_buffer( struct snd_pcm *pcm, int stream,
764              size_t size)
765     {
766          struct snd_pcm_substream *substream = pcm->streams[stream].substream;
767          struct snd_dma_buffer *buf = &substream->dma_buffer;
768     
769          buf->dev.type = SNDRV_DMA_TYPE_DEV;
770          buf->dev.dev = pcm->card->dev;
771          buf->private_data = NULL;
772          buf->area = dma_alloc_writecombine(pcm->card->dev, size,
773                             &buf->addr, GFP_KERNEL);
774     
775          pr_debug( "davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, "
776              "size=%d/n" , ( void *) buf->area, ( void *) buf->addr, size);
777     
778          if (!buf->area)
779              return -ENOMEM;
780     
781          buf->bytes = size;
782          return 0;
783     }
784     
785     static void davinci_pcm_free( struct snd_pcm *pcm)
786     {
787          struct snd_pcm_substream *substream;
788          struct snd_dma_buffer *buf;
789          int stream;
790     
791          for (stream = 0; stream < 2; stream++) {
792              struct snd_dma_buffer *iram_dma;
793              substream = pcm->streams[stream].substream;
794              if (!substream)
795                  continue ;
796     
797              buf = &substream->dma_buffer;
798              if (!buf->area)
799                  continue ;
800     
801              dma_free_writecombine(pcm->card->dev, buf->bytes,
802                            buf->area, buf->addr);
803              buf->area = NULL;
804              iram_dma = buf->private_data;
805              if (iram_dma) {
806                  sram_free(iram_dma->area, iram_dma->bytes);
807                  kfree(iram_dma);
808              }
809          }
810     }
811     
812     static u64 davinci_pcm_dmamask = 0xffffffff;
813     
814     static int davinci_pcm_new( struct snd_card *card,
815                     struct snd_soc_dai *dai, struct snd_pcm *pcm)
816     {
817          int ret;
818     
819          if (!card->dev->dma_mask)
820              card->dev->dma_mask = &davinci_pcm_dmamask;
821          if (!card->dev->coherent_dma_mask)
822              card->dev->coherent_dma_mask = 0xffffffff;
823     
824          if (dai->playback.channels_min) {
825              ret = davinci_pcm_preallocate_dma_buffer(pcm,
826                  SNDRV_PCM_STREAM_PLAYBACK,
827                  pcm_hardware_playback.buffer_bytes_max);
828              if (ret)
829                  return ret;
830          }
831     
832          if (dai->capture.channels_min) {
833              ret = davinci_pcm_preallocate_dma_buffer(pcm,
834                  SNDRV_PCM_STREAM_CAPTURE,
835                  pcm_hardware_capture.buffer_bytes_max);
836              if (ret)
837                  return ret;
838          }
839     
840          return 0;
841     }
842     
843     struct snd_soc_platform davinci_soc_platform = {
844          .name =     "davinci-audio" ,
845          .pcm_ops =  &davinci_pcm_ops,
846          .pcm_new =  davinci_pcm_new,
847          .pcm_free =     davinci_pcm_free,
848     };
849     EXPORT_SYMBOL_GPL(davinci_soc_platform);
850     
851     static int __init davinci_soc_platform_init( void )
852     {
853          return snd_soc_register_platform(&davinci_soc_platform);
854     }
855     module_init(davinci_soc_platform_init);
856     
857     static void __exit davinci_soc_platform_exit( void )
858     {
859          snd_soc_unregister_platform(&davinci_soc_platform);
860     }
861     module_exit(davinci_soc_platform_exit);
862     
863     MODULE_AUTHOR( "Vladimir Barinov" );
864     MODULE_DESCRIPTION( "TI DAVINCI PCM DMA module" );
865     MODULE_LICENSE( "GPL" );