[alsa-devel] ASoC: DMA Platform driver for i.mx27

javier Martin javier.martin at vista-silicon.com
Wed Apr 15 13:19:58 CEST 2009


Patch submitted again.

Fixed a lot of coding style problems, debugging information now using
"pr_debug()"
and problem of freeing both dma's when closing pcm.

Signed-off-by: Javier Martin <javier.martin at vista-silicon.com>

diff --git a/sound/soc/imx/imx27-pcm.c b/sound/soc/imx/imx27-pcm.c
new file mode 100644
index 0000000..ea00983
--- /dev/null
+++ b/sound/soc/imx/imx27-pcm.c
@@ -0,0 +1,555 @@
+/*
+ * linux/sound/arm/mx27-pcm.c -- ALSA SoC interface for the Freescale
i.MX27 CPU
+ *
+ * Copyright 2009 Vista Silicon S.L.
+ * Author: Javier Martin
+ *         javier.martin at vista-silicon.com
+ *
+ * Based on mxc-pcm.c by    Liam Girdwood, (C) 2006 Wolfson
Microelectronics PLC.
+ * and on mxc-alsa-mc13783 (C) 2006 Freescale.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/dma.h>
+#include <asm/hardware.h>
+
+#include "imx27-pcm.h"
+
+/* Just for debugging */
+#include "imx27-ssi.h"
+
+/* Taken from drivers/mxc/ssi/registers.h just provisionally */
+#define    MXC_SSI1STX0        0x00
+#define    MXC_SSI1SRX0        0x08
+#define    MXC_SSI2STX0        0x00
+#define    MXC_SSI2SRX0        0x08
+
+static const struct snd_pcm_hardware mx27_pcm_hardware = {
+    .info            = (SNDRV_PCM_INFO_INTERLEAVED |
+                   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                   SNDRV_PCM_INFO_MMAP |
+                   SNDRV_PCM_INFO_MMAP_VALID),
+    .formats        = SNDRV_PCM_FMTBIT_S16_LE,
+    .buffer_bytes_max    = 32 * 1024,
+    .period_bytes_min    = 64,
+    .period_bytes_max    = 8 * 1024,
+    .periods_min        = 2,
+    .periods_max        = 255,
+    .fifo_size        = 0,
+};
+
+struct mx27_runtime_data {
+    int dma_ch_tx; //DMA channel number for tx
+    int dma_ch_rx; //DMA channel number for rx
+    int active; //Is the stream active?
+    unsigned int period; //Period number
+    unsigned int periods; //¿?
+    int tx_spin; //¿?
+    spinlock_t dma_lock; //DMA spinlock
+    struct mx27_pcm_dma_param *dma_params; //FIXME this is SDMA api
+};
+
+/**
+  * This function stops the current dma transfer for playback
+  * and clears the dma pointers.
+  *
+  * @param    substream    pointer to the structure of the current stream.
+  *
+  */
+static int audio_stop_dma(struct snd_pcm_substream *substream)
+{
+    struct snd_pcm_runtime *runtime = substream->runtime;
+    struct mx27_runtime_data *prtd = runtime->private_data;
+    unsigned int dma_size = frames_to_bytes(runtime, runtime->period_size);
+    unsigned int offset  = dma_size * prtd->periods;
+    unsigned long flags;
+
+    spin_lock_irqsave(&prtd->dma_lock, flags);
+
+    pr_debug("MX27 : audio_stop_dma active = 0\n");
+
+    prtd->active = 0;
+    prtd->period = 0;
+    prtd->periods = 0;
+
+    /* this stops the dma channel and clears the buffer ptrs */
+
+    if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+        if (mxc_dma_disable(prtd->dma_ch_tx) < 0)
+            printk(KERN_ERR "audio_stop_dma: error when stopping dma
transfer in channel %d \n",
+                prtd->dma_ch_tx);
+    } else {
+        if (mxc_dma_disable(prtd->dma_ch_rx) < 0)
+            printk(KERN_ERR "audio_stop_dma: error when stopping dma
transfer in channel %d \n",
+                prtd->dma_ch_rx);
+    }
+    spin_unlock_irqrestore(&prtd->dma_lock, flags);
+
+    return 0;
+}
+
+/**
+  * This function is called whenever a new audio block needs to be
+  * transferred to the codec. The function receives the address and the
size
+  * of the new block and start a new DMA transfer.
+  *
+  * @param    substream    pointer to the structure of the current stream.
+  *
+  */
+static int dma_new_period(struct snd_pcm_substream *substream)
+{
+    struct snd_pcm_runtime *runtime =  substream->runtime;
+    struct mx27_runtime_data *prtd = runtime->private_data;
+    unsigned int dma_size;
+    unsigned int offset;
+    int ret = 0;
+    mxc_dma_requestbuf_t dma_request;
+
+
+    if (prtd->active) {
+        memset(&dma_request, 0, sizeof(mxc_dma_requestbuf_t));;
+        dma_size = frames_to_bytes(runtime, runtime->period_size);
+
+        pr_debug("dma_new_period: prtd->period (%x) runtime->periods
(%d)\n",
+            prtd->period, runtime->periods);
+        pr_debug("dma_new_period: runtime->period_size (%d) dma_size
(%d)\n",
+            (unsigned int)runtime->period_size,
+            runtime->dma_bytes);
+
+        offset = dma_size * prtd->period;
+        snd_assert(dma_size <= mx27_pcm_hardware.period_bytes_max);
+
+        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+            pr_debug("\ndma_new_period (playback): runtime->dma_area =
%x\noffset = %x\ndma_size = %x\n",
+                runtime->dma_area, offset, dma_size);
+            pr_debug("\ndma_new_period : dma_addr is %x\n",
+                 (runtime->dma_addr + offset));
+
+            dma_request.src_addr = (dma_addr_t)(runtime->dma_addr +
offset);
+#ifdef CONFIG_SND_SOC_MX27_SSI1
+
+            dma_request.dst_addr = (dma_addr_t) (SSI1_BASE_ADDR +
MXC_SSI1STX0);
+
+            pr_debug("dst_addr is %x\n", dma_request.dst_addr);
+            pr_debug("src_addr is %x\n", dma_request.src_addr);
+#else
+            dma_request.dst_addr =
+                (dma_addr_t) (SSI2_BASE_ADDR + MXC_SSI2STX0);
+#endif
+        } else {
+            pr_debug("\ndma_new_period (capture): runtime->dma_area =
%x\noffset = %x\ndma_size = %x\n",
+                runtime->dma_area, offset, dma_size);
+            pr_debug("\ndma_new_period: dma_addr is %x\n",
+                (runtime->dma_addr + offset));
+
+            dma_request.dst_addr = (dma_addr_t) (runtime->dma_addr +
offset);
+#ifdef CONFIG_SND_SOC_MX27_SSI1
+            dma_request.src_addr =
+                (dma_addr_t) (SSI1_BASE_ADDR + MXC_SSI1SRX0);
+#else
+            dma_request.src_addr =
+                (dma_addr_t) (SSI2_BASE_ADDR + MXC_SSI2SRX0);
+#endif
+        }
+
+        dma_request.num_of_bytes = dma_size;
+        pr_debug("dma_new_period: Start DMA offset (%d) size (%d)\n",
+             offset, runtime->dma_bytes);
+        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+            pr_debug("dma_new_period: configuring tx dma\n");
+            ret = mxc_dma_config(prtd->dma_ch_tx, &dma_request, 1,
+                MXC_DMA_MODE_WRITE);
+            if (ret < 0) {
+                printk("dma_new_period: buffer could not be added for
playback transfer\n");
+                return ret;
+            }
+
+            pr_debug("dma_new_period: enable  tx dma transfer\n");
+            ret = mxc_dma_enable(prtd->dma_ch_tx);
+            if (ret < 0) {
+                printk("dma_new_period: cannot queue DMA buffer\
+                            (%i)\n", ret);
+                return ret;
+            }
+        } else {
+            ret = mxc_dma_config(prtd->dma_ch_rx, &dma_request, 1,
MXC_DMA_MODE_READ);
+            if (ret < 0) {
+                printk("dma_new_period: buffer could not be added for
capture transfer\n");
+                return ret;
+            }
+
+            pr_debug("dma_new_period: enable  dma transfer\n");
+            ret = mxc_dma_enable(prtd->dma_ch_rx);
+            if(ret<0) {
+                printk("dma_new_period: cannot queue DMA buffer\
+                            (%i)\n", ret);
+                return ret;
+            }
+        }
+
+        pr_debug("dma_new_period: transfer enabled\n src_addr = %x\n
dst_addr = %x\n num_of_byes = %d\n", (void *) dma_request.src_addr, (void *)
dma_request.dst_addr, dma_request.num_of_bytes);
+
+        prtd->tx_spin = 1; /* FGA little trick to retrieve DMA pos */
+        prtd->period++;
+        prtd->period %= runtime->periods;
+    }
+    return ret;
+}
+
+
+/**
+  * This is a callback which will be called
+  * when a TX transfer finishes. The call occurs
+  * in interrupt context.
+  *
+  * @param    dat    pointer to the structure of the current stream.
+  *
+  */
+static void audio_dma_irq(void *data, int error, unsigned int count)
+{
+    struct snd_pcm_substream *substream;
+    struct snd_pcm_runtime *runtime;
+    struct mx27_runtime_data *prtd;
+    unsigned int dma_size;
+    unsigned int previous_period;
+    unsigned int offset;
+
+    substream = data;
+    runtime = substream->runtime;
+    prtd = runtime->private_data;
+    previous_period  = prtd->periods;
+    dma_size = frames_to_bytes(runtime, runtime->period_size);
+    offset = dma_size * previous_period;
+
+    prtd->tx_spin = 0;
+    prtd->periods++;
+    prtd->periods %= runtime->periods;
+
+    pr_debug("audio_dma_irq: irq per %d offset %x\n", prtd->periods,
offset);
+
+    /*
+      * If we are getting a callback for an active stream then we inform
+      * the PCM middle layer we've finished a period
+      */
+     if (prtd->active)
+        snd_pcm_period_elapsed(substream);
+
+    /*
+      * Trig next DMA transfer
+      */
+    dma_new_period(substream);
+}
+
+/**
+  * This function configures the hardware to allow audio
+  * playback operations. It is called by ALSA framework.
+  *
+  * @param    substream    pointer to the structure of the current stream.
+  *
+  * @return              0 on success, -1 otherwise.
+  */
+static int
+snd_mxc_prepare(struct snd_pcm_substream *substream)
+{
+    struct snd_pcm_runtime *runtime =  substream->runtime;
+    struct mx27_runtime_data *prtd = runtime->private_data;
+
+    prtd->period = 0;
+    prtd->periods = 0;
+
+    return 0;
+}
+
+static int mxc_pcm_hw_params(struct snd_pcm_substream *substream,
+    struct snd_pcm_hw_params *hw_params)
+{
+    struct snd_pcm_runtime *runtime = substream->runtime;
+    struct mx27_runtime_data *prtd = runtime->private_data;
+    int ret;
+
+    if((ret=snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params))) < 0)
+    {
+        printk("imx27-pcm: failed to malloc pcm pages\n");
+        return ret;
+    }
+
+    pr_debug("mxc_pcm_hw_params: snd_pcm_lib_malloc pages has return
OK\n");
+    pr_debug("IMX27: snd_imx27_audio_hw_params runtime->dma_addr 0x(%x)\n",
+         (unsigned int)runtime->dma_addr);
+    pr_debug("IMX27: snd_imx27_audio_hw_params runtime->dma_area 0x(%x)\n",
+         (unsigned int)runtime->dma_area);
+    pr_debug("IMX27: snd_imx27_audio_hw_params runtime->dma_bytes
0x(%x)\n",
+         (unsigned int)runtime->dma_bytes);
+
+    return ret;
+}
+
+static int mxc_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+    struct snd_pcm_runtime *runtime = substream->runtime;
+    struct mx27_runtime_data *prtd = runtime->private_data;
+
+
+    if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+        mxc_dma_free(prtd->dma_ch_tx);
+    else
+        mxc_dma_free(prtd->dma_ch_rx);
+
+    snd_pcm_lib_free_pages(substream);
+
+    return 0;
+}
+
+static int mxc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+    struct mx27_runtime_data *prtd = substream->runtime->private_data;
+    int ret = 0;
+
+    switch (cmd) {
+    case SNDRV_PCM_TRIGGER_START:
+        prtd->tx_spin = 0;
+        /* requested stream startup */
+        prtd->active = 1;
+        pr_debug("mxc_pcm_trigger: starting dma_new_period\n");
+            ret = dma_new_period(substream);
+        break;
+    case SNDRV_PCM_TRIGGER_STOP:
+        /* requested stream shutdown */
+        pr_debug("mxc_pcm_trigger: stopping dma transfer\n");
+        ret = audio_stop_dma(substream);
+        break;
+    default:
+        ret = -EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+static snd_pcm_uframes_t mxc_pcm_pointer(struct snd_pcm_substream
*substream)
+{
+    struct snd_pcm_runtime *runtime = substream->runtime;
+    struct mx27_runtime_data *prtd = runtime->private_data;
+    unsigned int offset = 0;
+
+    pr_debug("mxc_pcm_pointer:\n runtime->period_size=%d\n
prtd->periods=%d\n runtime->buffer_size=%d\n prtd->tx_spin=%d\n",
+        runtime->period_size, prtd->periods, runtime->buffer_size,
prtd->tx_spin);
+    /* tx_spin value is used here to check if a transfer is active */
+    if (prtd->tx_spin){
+        offset = (runtime->period_size * (prtd->periods)) +
+                        (runtime->period_size >> 1);
+        if (offset >= runtime->buffer_size)
+            offset = runtime->period_size >> 1;
+    } else {
+        offset = (runtime->period_size * (prtd->periods));
+        if (offset >= runtime->buffer_size)
+            offset = 0;
+    }
+    pr_debug("mxc_pcm_pointer: pointer offset %x\n", offset);
+
+    return offset;
+}
+
+//Alocation of substream->runtime->private_data
+static int mxc_pcm_open(struct snd_pcm_substream *substream)
+{
+    struct snd_pcm_runtime *runtime = substream->runtime;
+    struct mx27_runtime_data *prtd;
+    int ret;
+
+    snd_soc_set_runtime_hwparams(substream, &mx27_pcm_hardware);
+
+    if ((ret = snd_pcm_hw_constraint_integer(runtime,
+                    SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+        return ret;
+
+    if ((prtd = kzalloc(sizeof(struct mx27_runtime_data), GFP_KERNEL)) ==
NULL) {
+        ret = -ENOMEM;
+        goto out;
+    }
+
+    runtime->private_data = prtd;
+
+    if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+    {
+
+#ifdef CONFIG_SND_SOC_MX27_SSI1
+        pr_debug("mxc_pcm_open: Requesting MXC_DMA_SSI1_16BIT_TX0 dma
channel\n");
+        prtd->dma_ch_tx  = mxc_dma_request(MXC_DMA_SSI1_16BIT_TX0, "ALSA TX
DMA");
+#else
+        prtd->dma_ch_tx = mxc_dma_request(MXC_DMA_SSI2_16BIT_TX0, "ALSA TX
DMA");
+#endif
+        if(prtd->dma_ch_tx < 0)
+        {
+            printk("error requesting a write(dma to device) dma
channel\n");
+            return ret;
+        }
+
+        /* Set dma callback */
+        pr_debug("mxc_pcm_open: Setting tx dma callback function\n");
+        ret = mxc_dma_callback_set(prtd->dma_ch_tx, (mxc_dma_callback_t)
audio_dma_irq, (void *)substream);
+        if(ret < 0) {
+            printk("error setting dma callback function\n");
+            return ret;
+        }
+
+        return 0;
+    } else {
+#ifdef CONFIG_SND_SOC_MX27_SSI1
+        pr_debug("mxc_pcm_open: Requesting MXC_DMA_SSI1_16BIT_RX0 dma
channel\n");
+        prtd->dma_ch_rx  = mxc_dma_request(MXC_DMA_SSI1_16BIT_RX0, "ALSA RX
DMA");
+#else
+        prtd->dma_ch_rx = mxc_dma_request(MXC_DMA_SSI2_16BIT_RX0, "ALSA RX
DMA");
+#endif
+        if (prtd->dma_ch_rx < 0) {
+            printk("error requesting a read(dma from device) dma
channel\n");
+            return ret;
+        }
+
+        //Set dma callback
+        pr_debug("mxc_pcm_open: Setting rx dma callback function\n");
+        if (mxc_dma_callback_set(prtd->dma_ch_rx, (mxc_dma_callback_t)
audio_dma_irq, (void *)substream)<0)
+            printk("error setting dma callback function\n");
+
+        return 0;
+    }
+
+
+
+ out:
+    return ret;
+}
+
+static int mxc_pcm_close(struct snd_pcm_substream *substream)
+{
+    struct snd_pcm_runtime *runtime = substream->runtime;
+    struct mxc_runtime_data *prtd = runtime->private_data;
+
+    kfree(prtd);
+
+    return 0;
+}
+
+static int
+mxc_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct
*vma)
+{
+    struct snd_pcm_runtime *runtime = substream->runtime;
+    return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+                     runtime->dma_area,
+                     runtime->dma_addr,
+                     runtime->dma_bytes);
+}
+
+struct snd_pcm_ops mxc_pcm_ops = {
+    .open        = mxc_pcm_open,
+    .close        = mxc_pcm_close,
+    .ioctl        = snd_pcm_lib_ioctl,
+    .hw_params    = mxc_pcm_hw_params,
+    .hw_free    = mxc_pcm_hw_free,
+    .prepare    = snd_mxc_prepare,
+    .trigger    = mxc_pcm_trigger,
+    .pointer    = mxc_pcm_pointer,
+    .mmap        = mxc_pcm_mmap,
+};
+
+static u64 mxc_pcm_dmamask = 0xffffffff;
+
+static int imx31_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int
stream)
+{
+    struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+    struct snd_dma_buffer *buf = &substream->dma_buffer;
+    size_t size = mx27_pcm_hardware.buffer_bytes_max;
+    buf->dev.type = SNDRV_DMA_TYPE_DEV;
+    buf->dev.dev = pcm->card->dev;
+    buf->private_data = NULL;
+
+    //Reserve uncached-buffered memory area for DMA
+    buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+                       &buf->addr, GFP_KERNEL);
+
+    pr_debug("imx27_pcm: preallocate_dma_buffer: area=%p, addr=%p,
size=%d\n", (void *) buf->area, (void *) buf->addr, size);
+
+    if (!buf->area)
+        return -ENOMEM;
+
+    buf->bytes = size;
+    return 0;
+}
+
+static void imx31_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+    struct snd_pcm_substream *substream;
+    struct snd_dma_buffer *buf;
+    int stream;
+
+    for (stream = 0; stream < 2; stream++) {
+        substream = pcm->streams[stream].substream;
+        if (!substream)
+            continue;
+
+        buf = &substream->dma_buffer;
+        if (!buf->area)
+            continue;
+
+        dma_free_writecombine(pcm->card->dev, buf->bytes,
+                      buf->area, buf->addr);
+        buf->area = NULL;
+    }
+}
+
+int mxc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+    struct snd_pcm *pcm)
+{
+    int ret = 0;
+
+    if (!card->dev->dma_mask)
+        card->dev->dma_mask = &mxc_pcm_dmamask;
+    if (!card->dev->coherent_dma_mask)
+        card->dev->coherent_dma_mask = 0xffffffff;
+
+    if (dai->playback.channels_min) {
+        ret = imx31_pcm_preallocate_dma_buffer(pcm,
+            SNDRV_PCM_STREAM_PLAYBACK);
+        printk("mxc_pcm_new: preallocate playback buffer\n");
+        if (ret)
+            goto out;
+    }
+
+    if (dai->capture.channels_min) {
+        ret = imx31_pcm_preallocate_dma_buffer(pcm,
+            SNDRV_PCM_STREAM_CAPTURE);
+        printk("mxc_pcm_new: preallocate capture buffer\n");
+        if (ret)
+            goto out;
+    }
+ out:
+    return ret;
+}
+
+struct snd_soc_platform imx27_soc_platform = {
+    .name        = "mxc-audio",
+    .pcm_ops     = &mxc_pcm_ops,
+    .pcm_new    = mxc_pcm_new,
+    .pcm_free    = imx31_pcm_free_dma_buffers,
+};
+
+EXPORT_SYMBOL_GPL(imx27_soc_platform);
+
+MODULE_AUTHOR("Javier Martin");
+MODULE_DESCRIPTION("Freescale i.MX27 PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/imx27-pcm.h b/sound/soc/imx/imx27-pcm.h
new file mode 100644
index 0000000..9852cff
--- /dev/null
+++ b/sound/soc/imx/imx27-pcm.h
@@ -0,0 +1,97 @@
+/*
+ * mxc-pcm.h :- ASoC platform header for Freescale i.MX
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MXC_PCM_H
+#define _MXC_PCM_H
+
+#include <asm/arch/dma.h>
+
+/* AUDMUX regs definition - MOVE to asm/arch when stable
+#define AUDMUX_IO_BASE_ADDR    IO_ADDRESS(AUDMUX_BASE_ADDR)
+
+#define DAM_PTCR1    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x00)))
+#define DAM_PDCR1    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x04)))
+#define DAM_PTCR2    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x08)))
+#define DAM_PDCR2    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x0C)))
+#define DAM_PTCR3    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x10)))
+#define DAM_PDCR3    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x14)))
+#define DAM_PTCR4    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x18)))
+#define DAM_PDCR4    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x1C)))
+#define DAM_PTCR5    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x20)))
+#define DAM_PDCR5    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x24)))
+#define DAM_PTCR6    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x28)))
+#define DAM_PDCR6    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x2C)))
+#define DAM_PTCR7    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x30)))
+#define DAM_PDCR7    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x34)))
+#define DAM_CNMCR    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x38)))
+#define DAM_PTCR(a)    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + a*8)))
+#define DAM_PDCR(a)    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 4 + a*8)))
+
+
+#define AUDMUX_PTCR_TFSDIR        (1 << 31)
+#define AUDMUX_PTCR_TFSSEL(x, y)        ((x << 30) | (((y - 1) & 0x7) <<
27))
+#define AUDMUX_PTCR_TCLKDIR        (1 << 26)
+#define AUDMUX_PTCR_TCSEL(x, y)        ((x << 25) | (((y - 1) & 0x7) <<
22))
+#define AUDMUX_PTCR_RFSDIR        (1 << 21)
+#define AUDMUX_PTCR_RFSSEL(x, y)        ((x << 20) | (((y - 1) & 0x7) <<
17))
+#define AUDMUX_PTCR_RCLKDIR        (1 << 16)
+#define AUDMUX_PTCR_RCSEL(x, y)        ((x << 15) | (((y - 1) & 0x7) <<
12))
+#define AUDMUX_PTCR_SYN        (1 << 11)
+
+#define AUDMUX_FROM_TXFS    0
+#define AUDMUX_FROM_RXFS    1
+
+#define AUDMUX_PDCR_RXDSEL(x)        (((x - 1) & 0x7) << 13)
+#define AUDMUX_PDCR_TXDXEN        (1 << 12)
+#define AUDMUX_PDCR_MODE(x)        (((x) & 0x3) << 8)
+#define AUDMUX_PDCR_INNMASK(x)        (((x) & 0xff) << 0)
+
+#define AUDMUX_CNMCR_CEN        (1 << 18)
+#define AUDMUX_CNMCR_FSPOL        (1 << 17)
+#define AUDMUX_CNMCR_CLKPOL        (1 << 16)
+#define AUDMUX_CNMCR_CNTHI(x)        (((x) & 0xff) << 8)
+#define AUDMUX_CNMCR_CNTLOW(x)        (((x) & 0xff) << 0)
+*/
+
+/* Previous defines are only valid for imx31 */
+#define AUDMUX_IO_BASE_ADDR    IO_ADDRESS(AUDMUX_BASE_ADDR)
+
+#define DAM_HPCR1    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x00)))
+#define DAM_HPCR2    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x04)))
+#define DAM_HPCR3    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x08)))
+#define DAM_PPCR1    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x10)))
+#define DAM_PPCR2    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x14)))
+#define DAM_PPCR3    (*((volatile u32 *)(AUDMUX_IO_BASE_ADDR + 0x1C)))
+
+#define AUDMUX_HPCR_TFSDIR    (1 << 31)
+#define AUDMUX_HPCR_TCLKDIR    (1 << 30)
+#define AUDMUX_HPCR_TFCSEL(x)    (((x) & 0xff) << 26)
+#define AUDMUX_HPCR_RXDSEL(x)    (((x) & 0x7) << 13)
+#define AUDMUX_HPCR_SYN        (1 << 12)
+
+#define AUDMUX_PPCR_TFSDIR    (1 << 31)
+#define AUDMUX_PPCR_TCLKDIR    (1 << 30)
+#define AUDMUX_PPCR_TFCSEL(x)    (((x) & 0xff) << 26)
+#define AUDMUX_PPCR_RXDSEL(x)    (((x) & 0x7) << 13)
+#define AUDMUX_PPCR_SYN        (1 << 12)
+
+
+
+struct mx27_pcm_dma_params {
+    char *name;            /* stream identifier */
+    mxc_dma_requestbuf_t buf_params; /*DMA buffer params */
+
+};
+
+extern struct snd_soc_dai mxc_ssi_dai[3];
+
+/* platform data */
+extern struct snd_soc_platform imx27_soc_platform;
+
+
+#endif
-------------- next part --------------
A non-text attachment was scrubbed...
Name: imx27-pcm.patch
Type: application/octet-stream
Size: 21352 bytes
Desc: not available
Url : http://mailman.alsa-project.org/pipermail/alsa-devel/attachments/20090415/774592ff/attachment-0001.dll 


More information about the Alsa-devel mailing list