linux/sound/soc/fsl/imx-pcm.c
<<
>>
Prefs
   1/*
   2 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
   3 *
   4 * This code is based on code copyrighted by Freescale,
   5 * Liam Girdwood, Javier Martin and probably others.
   6 *
   7 * This program is free software; you can redistribute  it and/or modify it
   8 * under  the terms of  the GNU General  Public License as published by the
   9 * Free Software Foundation;  either version 2 of the  License, or (at your
  10 * option) any later version.
  11 */
  12
  13#include <linux/dma-mapping.h>
  14#include <linux/module.h>
  15#include <sound/pcm.h>
  16#include <sound/soc.h>
  17#include "imx-pcm.h"
  18
  19int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
  20                struct vm_area_struct *vma)
  21{
  22        struct snd_pcm_runtime *runtime = substream->runtime;
  23        int ret;
  24
  25        ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
  26                runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
  27
  28        pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
  29                        runtime->dma_area,
  30                        runtime->dma_addr,
  31                        runtime->dma_bytes);
  32        return ret;
  33}
  34EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
  35
  36static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  37{
  38        struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  39        struct snd_dma_buffer *buf = &substream->dma_buffer;
  40        size_t size = IMX_SSI_DMABUF_SIZE;
  41
  42        buf->dev.type = SNDRV_DMA_TYPE_DEV;
  43        buf->dev.dev = pcm->card->dev;
  44        buf->private_data = NULL;
  45        buf->area = dma_alloc_writecombine(pcm->card->dev, size,
  46                                           &buf->addr, GFP_KERNEL);
  47        if (!buf->area)
  48                return -ENOMEM;
  49        buf->bytes = size;
  50
  51        return 0;
  52}
  53
  54static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
  55
  56int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
  57{
  58        struct snd_card *card = rtd->card->snd_card;
  59        struct snd_pcm *pcm = rtd->pcm;
  60        int ret = 0;
  61
  62        if (!card->dev->dma_mask)
  63                card->dev->dma_mask = &imx_pcm_dmamask;
  64        if (!card->dev->coherent_dma_mask)
  65                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
  66        if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
  67                ret = imx_pcm_preallocate_dma_buffer(pcm,
  68                        SNDRV_PCM_STREAM_PLAYBACK);
  69                if (ret)
  70                        goto out;
  71        }
  72
  73        if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
  74                ret = imx_pcm_preallocate_dma_buffer(pcm,
  75                        SNDRV_PCM_STREAM_CAPTURE);
  76                if (ret)
  77                        goto out;
  78        }
  79
  80out:
  81        return ret;
  82}
  83EXPORT_SYMBOL_GPL(imx_pcm_new);
  84
  85void imx_pcm_free(struct snd_pcm *pcm)
  86{
  87        struct snd_pcm_substream *substream;
  88        struct snd_dma_buffer *buf;
  89        int stream;
  90
  91        for (stream = 0; stream < 2; stream++) {
  92                substream = pcm->streams[stream].substream;
  93                if (!substream)
  94                        continue;
  95
  96                buf = &substream->dma_buffer;
  97                if (!buf->area)
  98                        continue;
  99
 100                dma_free_writecombine(pcm->card->dev, buf->bytes,
 101                                      buf->area, buf->addr);
 102                buf->area = NULL;
 103        }
 104}
 105EXPORT_SYMBOL_GPL(imx_pcm_free);
 106
 107static int imx_pcm_probe(struct platform_device *pdev)
 108{
 109        if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
 110                return imx_pcm_fiq_init(pdev);
 111
 112        return imx_pcm_dma_init(pdev);
 113}
 114
 115static int imx_pcm_remove(struct platform_device *pdev)
 116{
 117        snd_soc_unregister_platform(&pdev->dev);
 118        return 0;
 119}
 120
 121static struct platform_device_id imx_pcm_devtype[] = {
 122        { .name = "imx-pcm-audio", },
 123        { .name = "imx-fiq-pcm-audio", },
 124        { /* sentinel */ }
 125};
 126MODULE_DEVICE_TABLE(platform, imx_pcm_devtype);
 127
 128static struct platform_driver imx_pcm_driver = {
 129        .driver = {
 130                        .name = "imx-pcm",
 131                        .owner = THIS_MODULE,
 132        },
 133        .id_table = imx_pcm_devtype,
 134        .probe = imx_pcm_probe,
 135        .remove = imx_pcm_remove,
 136};
 137module_platform_driver(imx_pcm_driver);
 138
 139MODULE_DESCRIPTION("Freescale i.MX PCM driver");
 140MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 141MODULE_LICENSE("GPL");
 142