1/* 2 * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip 3 * 4 * Author: Nicolas Pitre 5 * Created: Nov 30, 2004 6 * Copyright: (C) 2004 MontaVista Software, Inc. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13#include <linux/module.h> 14#include <linux/dma-mapping.h> 15#include <linux/dmaengine.h> 16 17#include <mach/dma.h> 18 19#include <sound/core.h> 20#include <sound/pxa2xx-lib.h> 21#include <sound/dmaengine_pcm.h> 22 23#include "pxa2xx-pcm.h" 24 25static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) 26{ 27 struct pxa2xx_pcm_client *client = substream->private_data; 28 29 __pxa2xx_pcm_prepare(substream); 30 31 return client->prepare(substream); 32} 33 34static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) 35{ 36 struct pxa2xx_pcm_client *client = substream->private_data; 37 struct snd_pcm_runtime *runtime = substream->runtime; 38 struct pxa2xx_runtime_data *rtd; 39 int ret; 40 41 ret = __pxa2xx_pcm_open(substream); 42 if (ret) 43 goto out; 44 45 rtd = runtime->private_data; 46 47 rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 48 client->playback_params : client->capture_params; 49 ret = pxa_request_dma("dma", DMA_PRIO_LOW, 50 pxa2xx_pcm_dma_irq, substream); 51 if (ret < 0) 52 goto err2; 53 rtd->dma_ch = ret; 54 55 ret = client->startup(substream); 56 if (!ret) 57 goto out; 58 59 pxa_free_dma(rtd->dma_ch); 60 err2: 61 __pxa2xx_pcm_close(substream); 62 out: 63 return ret; 64} 65 66static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) 67{ 68 struct pxa2xx_pcm_client *client = substream->private_data; 69 struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; 70 71 pxa_free_dma(rtd->dma_ch); 72 client->shutdown(substream); 73 74 return __pxa2xx_pcm_close(substream); 75} 76 77static struct snd_pcm_ops pxa2xx_pcm_ops = { 78 .open = pxa2xx_pcm_open, 79 .close = pxa2xx_pcm_close, 80 .ioctl = snd_pcm_lib_ioctl, 81 .hw_params = __pxa2xx_pcm_hw_params, 82 .hw_free = __pxa2xx_pcm_hw_free, 83 .prepare = pxa2xx_pcm_prepare, 84 .trigger = pxa2xx_pcm_trigger, 85 .pointer = pxa2xx_pcm_pointer, 86 .mmap = pxa2xx_pcm_mmap, 87}; 88 89int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client, 90 struct snd_pcm **rpcm) 91{ 92 struct snd_pcm *pcm; 93 int play = client->playback_params ? 1 : 0; 94 int capt = client->capture_params ? 1 : 0; 95 int ret; 96 97 ret = snd_pcm_new(card, "PXA2xx-PCM", 0, play, capt, &pcm); 98 if (ret) 99 goto out; 100 101 pcm->private_data = client; 102 pcm->private_free = pxa2xx_pcm_free_dma_buffers; 103 104 ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); 105 if (ret) 106 goto out; 107 108 if (play) { 109 int stream = SNDRV_PCM_STREAM_PLAYBACK; 110 snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops); 111 ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream); 112 if (ret) 113 goto out; 114 } 115 if (capt) { 116 int stream = SNDRV_PCM_STREAM_CAPTURE; 117 snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops); 118 ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream); 119 if (ret) 120 goto out; 121 } 122 123 if (rpcm) 124 *rpcm = pcm; 125 ret = 0; 126 127 out: 128 return ret; 129} 130 131EXPORT_SYMBOL(pxa2xx_pcm_new); 132 133MODULE_AUTHOR("Nicolas Pitre"); 134MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); 135MODULE_LICENSE("GPL"); 136