linux/sound/soc/davinci/davinci-pcm.c
<<
>>
Prefs
   1/*
   2 * ALSA PCM interface for the TI DAVINCI processor
   3 *
   4 * Author:      Vladimir Barinov, <vbarinov@embeddedalley.com>
   5 * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/init.h>
  14#include <linux/platform_device.h>
  15#include <linux/slab.h>
  16#include <linux/dma-mapping.h>
  17#include <linux/kernel.h>
  18
  19#include <sound/core.h>
  20#include <sound/pcm.h>
  21#include <sound/pcm_params.h>
  22#include <sound/soc.h>
  23
  24#include <asm/dma.h>
  25#include <mach/edma.h>
  26
  27#include "davinci-pcm.h"
  28
  29static struct snd_pcm_hardware davinci_pcm_hardware = {
  30        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
  31                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
  32                 SNDRV_PCM_INFO_PAUSE),
  33        .formats = (SNDRV_PCM_FMTBIT_S16_LE),
  34        .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  35                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
  36                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
  37                  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
  38                  SNDRV_PCM_RATE_KNOT),
  39        .rate_min = 8000,
  40        .rate_max = 96000,
  41        .channels_min = 2,
  42        .channels_max = 2,
  43        .buffer_bytes_max = 128 * 1024,
  44        .period_bytes_min = 32,
  45        .period_bytes_max = 8 * 1024,
  46        .periods_min = 16,
  47        .periods_max = 255,
  48        .fifo_size = 0,
  49};
  50
  51struct davinci_runtime_data {
  52        spinlock_t lock;
  53        int period;             /* current DMA period */
  54        int master_lch;         /* Master DMA channel */
  55        int slave_lch;          /* linked parameter RAM reload slot */
  56        struct davinci_pcm_dma_params *params;  /* DMA params */
  57};
  58
  59static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
  60{
  61        struct davinci_runtime_data *prtd = substream->runtime->private_data;
  62        struct snd_pcm_runtime *runtime = substream->runtime;
  63        int lch = prtd->slave_lch;
  64        unsigned int period_size;
  65        unsigned int dma_offset;
  66        dma_addr_t dma_pos;
  67        dma_addr_t src, dst;
  68        unsigned short src_bidx, dst_bidx;
  69        unsigned int data_type;
  70        unsigned short acnt;
  71        unsigned int count;
  72
  73        period_size = snd_pcm_lib_period_bytes(substream);
  74        dma_offset = prtd->period * period_size;
  75        dma_pos = runtime->dma_addr + dma_offset;
  76
  77        pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d "
  78                "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size);
  79
  80        data_type = prtd->params->data_type;
  81        count = period_size / data_type;
  82
  83        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  84                src = dma_pos;
  85                dst = prtd->params->dma_addr;
  86                src_bidx = data_type;
  87                dst_bidx = 0;
  88        } else {
  89                src = prtd->params->dma_addr;
  90                dst = dma_pos;
  91                src_bidx = 0;
  92                dst_bidx = data_type;
  93        }
  94
  95        acnt = prtd->params->acnt;
  96        edma_set_src(lch, src, INCR, W8BIT);
  97        edma_set_dest(lch, dst, INCR, W8BIT);
  98        edma_set_src_index(lch, src_bidx, 0);
  99        edma_set_dest_index(lch, dst_bidx, 0);
 100        edma_set_transfer_params(lch, acnt, count, 1, 0, ASYNC);
 101
 102        prtd->period++;
 103        if (unlikely(prtd->period >= runtime->periods))
 104                prtd->period = 0;
 105}
 106
 107static void davinci_pcm_dma_irq(unsigned lch, u16 ch_status, void *data)
 108{
 109        struct snd_pcm_substream *substream = data;
 110        struct davinci_runtime_data *prtd = substream->runtime->private_data;
 111
 112        pr_debug("davinci_pcm: lch=%d, status=0x%x\n", lch, ch_status);
 113
 114        if (unlikely(ch_status != DMA_COMPLETE))
 115                return;
 116
 117        if (snd_pcm_running(substream)) {
 118                snd_pcm_period_elapsed(substream);
 119
 120                spin_lock(&prtd->lock);
 121                davinci_pcm_enqueue_dma(substream);
 122                spin_unlock(&prtd->lock);
 123        }
 124}
 125
 126static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
 127{
 128        struct davinci_runtime_data *prtd = substream->runtime->private_data;
 129        struct edmacc_param p_ram;
 130        int ret;
 131
 132        /* Request master DMA channel */
 133        ret = edma_alloc_channel(prtd->params->channel,
 134                                  davinci_pcm_dma_irq, substream,
 135                                  EVENTQ_0);
 136        if (ret < 0)
 137                return ret;
 138        prtd->master_lch = ret;
 139
 140        /* Request parameter RAM reload slot */
 141        ret = edma_alloc_slot(EDMA_CTLR(prtd->master_lch), EDMA_SLOT_ANY);
 142        if (ret < 0) {
 143                edma_free_channel(prtd->master_lch);
 144                return ret;
 145        }
 146        prtd->slave_lch = ret;
 147
 148        /* Issue transfer completion IRQ when the channel completes a
 149         * transfer, then always reload from the same slot (by a kind
 150         * of loopback link).  The completion IRQ handler will update
 151         * the reload slot with a new buffer.
 152         *
 153         * REVISIT save p_ram here after setting up everything except
 154         * the buffer and its length (ccnt) ... use it as a template
 155         * so davinci_pcm_enqueue_dma() takes less time in IRQ.
 156         */
 157        edma_read_slot(prtd->slave_lch, &p_ram);
 158        p_ram.opt |= TCINTEN | EDMA_TCC(EDMA_CHAN_SLOT(prtd->master_lch));
 159        p_ram.link_bcntrld = EDMA_CHAN_SLOT(prtd->slave_lch) << 5;
 160        edma_write_slot(prtd->slave_lch, &p_ram);
 161
 162        return 0;
 163}
 164
 165static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 166{
 167        struct davinci_runtime_data *prtd = substream->runtime->private_data;
 168        int ret = 0;
 169
 170        spin_lock(&prtd->lock);
 171
 172        switch (cmd) {
 173        case SNDRV_PCM_TRIGGER_START:
 174        case SNDRV_PCM_TRIGGER_RESUME:
 175        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 176                edma_start(prtd->master_lch);
 177                break;
 178        case SNDRV_PCM_TRIGGER_STOP:
 179        case SNDRV_PCM_TRIGGER_SUSPEND:
 180        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 181                edma_stop(prtd->master_lch);
 182                break;
 183        default:
 184                ret = -EINVAL;
 185                break;
 186        }
 187
 188        spin_unlock(&prtd->lock);
 189
 190        return ret;
 191}
 192
 193static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
 194{
 195        struct davinci_runtime_data *prtd = substream->runtime->private_data;
 196        struct edmacc_param temp;
 197
 198        prtd->period = 0;
 199        davinci_pcm_enqueue_dma(substream);
 200
 201        /* Copy self-linked parameter RAM entry into master channel */
 202        edma_read_slot(prtd->slave_lch, &temp);
 203        edma_write_slot(prtd->master_lch, &temp);
 204        davinci_pcm_enqueue_dma(substream);
 205
 206        return 0;
 207}
 208
 209static snd_pcm_uframes_t
 210davinci_pcm_pointer(struct snd_pcm_substream *substream)
 211{
 212        struct snd_pcm_runtime *runtime = substream->runtime;
 213        struct davinci_runtime_data *prtd = runtime->private_data;
 214        unsigned int offset;
 215        dma_addr_t count;
 216        dma_addr_t src, dst;
 217
 218        spin_lock(&prtd->lock);
 219
 220        edma_get_position(prtd->master_lch, &src, &dst);
 221        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 222                count = src - runtime->dma_addr;
 223        else
 224                count = dst - runtime->dma_addr;
 225
 226        spin_unlock(&prtd->lock);
 227
 228        offset = bytes_to_frames(runtime, count);
 229        if (offset >= runtime->buffer_size)
 230                offset = 0;
 231
 232        return offset;
 233}
 234
 235static int davinci_pcm_open(struct snd_pcm_substream *substream)
 236{
 237        struct snd_pcm_runtime *runtime = substream->runtime;
 238        struct davinci_runtime_data *prtd;
 239        int ret = 0;
 240        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 241        struct davinci_pcm_dma_params *pa = rtd->dai->cpu_dai->private_data;
 242        struct davinci_pcm_dma_params *params = &pa[substream->stream];
 243        if (!params)
 244                return -ENODEV;
 245
 246        snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware);
 247        /* ensure that buffer size is a multiple of period size */
 248        ret = snd_pcm_hw_constraint_integer(runtime,
 249                                                SNDRV_PCM_HW_PARAM_PERIODS);
 250        if (ret < 0)
 251                return ret;
 252
 253        prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL);
 254        if (prtd == NULL)
 255                return -ENOMEM;
 256
 257        spin_lock_init(&prtd->lock);
 258        prtd->params = params;
 259
 260        runtime->private_data = prtd;
 261
 262        ret = davinci_pcm_dma_request(substream);
 263        if (ret) {
 264                printk(KERN_ERR "davinci_pcm: Failed to get dma channels\n");
 265                kfree(prtd);
 266        }
 267
 268        return ret;
 269}
 270
 271static int davinci_pcm_close(struct snd_pcm_substream *substream)
 272{
 273        struct snd_pcm_runtime *runtime = substream->runtime;
 274        struct davinci_runtime_data *prtd = runtime->private_data;
 275
 276        edma_unlink(prtd->slave_lch);
 277
 278        edma_free_slot(prtd->slave_lch);
 279        edma_free_channel(prtd->master_lch);
 280
 281        kfree(prtd);
 282
 283        return 0;
 284}
 285
 286static int davinci_pcm_hw_params(struct snd_pcm_substream *substream,
 287                                 struct snd_pcm_hw_params *hw_params)
 288{
 289        return snd_pcm_lib_malloc_pages(substream,
 290                                        params_buffer_bytes(hw_params));
 291}
 292
 293static int davinci_pcm_hw_free(struct snd_pcm_substream *substream)
 294{
 295        return snd_pcm_lib_free_pages(substream);
 296}
 297
 298static int davinci_pcm_mmap(struct snd_pcm_substream *substream,
 299                            struct vm_area_struct *vma)
 300{
 301        struct snd_pcm_runtime *runtime = substream->runtime;
 302
 303        return dma_mmap_writecombine(substream->pcm->card->dev, vma,
 304                                     runtime->dma_area,
 305                                     runtime->dma_addr,
 306                                     runtime->dma_bytes);
 307}
 308
 309static struct snd_pcm_ops davinci_pcm_ops = {
 310        .open =         davinci_pcm_open,
 311        .close =        davinci_pcm_close,
 312        .ioctl =        snd_pcm_lib_ioctl,
 313        .hw_params =    davinci_pcm_hw_params,
 314        .hw_free =      davinci_pcm_hw_free,
 315        .prepare =      davinci_pcm_prepare,
 316        .trigger =      davinci_pcm_trigger,
 317        .pointer =      davinci_pcm_pointer,
 318        .mmap =         davinci_pcm_mmap,
 319};
 320
 321static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 322{
 323        struct snd_pcm_substream *substream = pcm->streams[stream].substream;
 324        struct snd_dma_buffer *buf = &substream->dma_buffer;
 325        size_t size = davinci_pcm_hardware.buffer_bytes_max;
 326
 327        buf->dev.type = SNDRV_DMA_TYPE_DEV;
 328        buf->dev.dev = pcm->card->dev;
 329        buf->private_data = NULL;
 330        buf->area = dma_alloc_writecombine(pcm->card->dev, size,
 331                                           &buf->addr, GFP_KERNEL);
 332
 333        pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, "
 334                "size=%d\n", (void *) buf->area, (void *) buf->addr, size);
 335
 336        if (!buf->area)
 337                return -ENOMEM;
 338
 339        buf->bytes = size;
 340        return 0;
 341}
 342
 343static void davinci_pcm_free(struct snd_pcm *pcm)
 344{
 345        struct snd_pcm_substream *substream;
 346        struct snd_dma_buffer *buf;
 347        int stream;
 348
 349        for (stream = 0; stream < 2; stream++) {
 350                substream = pcm->streams[stream].substream;
 351                if (!substream)
 352                        continue;
 353
 354                buf = &substream->dma_buffer;
 355                if (!buf->area)
 356                        continue;
 357
 358                dma_free_writecombine(pcm->card->dev, buf->bytes,
 359                                      buf->area, buf->addr);
 360                buf->area = NULL;
 361        }
 362}
 363
 364static u64 davinci_pcm_dmamask = 0xffffffff;
 365
 366static int davinci_pcm_new(struct snd_card *card,
 367                           struct snd_soc_dai *dai, struct snd_pcm *pcm)
 368{
 369        int ret;
 370
 371        if (!card->dev->dma_mask)
 372                card->dev->dma_mask = &davinci_pcm_dmamask;
 373        if (!card->dev->coherent_dma_mask)
 374                card->dev->coherent_dma_mask = 0xffffffff;
 375
 376        if (dai->playback.channels_min) {
 377                ret = davinci_pcm_preallocate_dma_buffer(pcm,
 378                        SNDRV_PCM_STREAM_PLAYBACK);
 379                if (ret)
 380                        return ret;
 381        }
 382
 383        if (dai->capture.channels_min) {
 384                ret = davinci_pcm_preallocate_dma_buffer(pcm,
 385                        SNDRV_PCM_STREAM_CAPTURE);
 386                if (ret)
 387                        return ret;
 388        }
 389
 390        return 0;
 391}
 392
 393struct snd_soc_platform davinci_soc_platform = {
 394        .name =         "davinci-audio",
 395        .pcm_ops =      &davinci_pcm_ops,
 396        .pcm_new =      davinci_pcm_new,
 397        .pcm_free =     davinci_pcm_free,
 398};
 399EXPORT_SYMBOL_GPL(davinci_soc_platform);
 400
 401static int __init davinci_soc_platform_init(void)
 402{
 403        return snd_soc_register_platform(&davinci_soc_platform);
 404}
 405module_init(davinci_soc_platform_init);
 406
 407static void __exit davinci_soc_platform_exit(void)
 408{
 409        snd_soc_unregister_platform(&davinci_soc_platform);
 410}
 411module_exit(davinci_soc_platform_exit);
 412
 413MODULE_AUTHOR("Vladimir Barinov");
 414MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
 415MODULE_LICENSE("GPL");
 416