~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/ep93xx/ep93xx-pcm.c

Version: ~ [ linux-5.5-rc7 ] ~ [ linux-5.4.13 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.97 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.166 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.210 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.210 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface
  3  *
  4  * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
  5  * Copyright (C) 2006 Applied Data Systems
  6  *
  7  * Rewritten for the SoC audio subsystem (Based on PXA2xx code):
  8  *   Copyright (c) 2008 Ryan Mallon
  9  *
 10  * This program is free software; you can redistribute it and/or modify
 11  * it under the terms of the GNU General Public License version 2 as
 12  * published by the Free Software Foundation.
 13  */
 14 
 15 #include <linux/module.h>
 16 #include <linux/init.h>
 17 #include <linux/device.h>
 18 #include <linux/slab.h>
 19 #include <linux/dmaengine.h>
 20 #include <linux/dma-mapping.h>
 21 
 22 #include <sound/core.h>
 23 #include <sound/pcm.h>
 24 #include <sound/pcm_params.h>
 25 #include <sound/soc.h>
 26 #include <sound/dmaengine_pcm.h>
 27 
 28 #include <mach/dma.h>
 29 #include <mach/hardware.h>
 30 #include <mach/ep93xx-regs.h>
 31 
 32 #include "ep93xx-pcm.h"
 33 
 34 static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
 35         .info                   = (SNDRV_PCM_INFO_MMAP          |
 36                                    SNDRV_PCM_INFO_MMAP_VALID    |
 37                                    SNDRV_PCM_INFO_INTERLEAVED   |
 38                                    SNDRV_PCM_INFO_BLOCK_TRANSFER),
 39                                    
 40         .rates                  = SNDRV_PCM_RATE_8000_192000,
 41         .rate_min               = SNDRV_PCM_RATE_8000,
 42         .rate_max               = SNDRV_PCM_RATE_192000,
 43         
 44         .formats                = (SNDRV_PCM_FMTBIT_S16_LE |
 45                                    SNDRV_PCM_FMTBIT_S24_LE |
 46                                    SNDRV_PCM_FMTBIT_S32_LE),
 47         
 48         .buffer_bytes_max       = 131072,
 49         .period_bytes_min       = 32,
 50         .period_bytes_max       = 32768,
 51         .periods_min            = 1,
 52         .periods_max            = 32,
 53         .fifo_size              = 32,
 54 };
 55 
 56 static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
 57 {
 58         struct ep93xx_dma_data *data = filter_param;
 59 
 60         if (data->direction == ep93xx_dma_chan_direction(chan)) {
 61                 chan->private = data;
 62                 return true;
 63         }
 64 
 65         return false;
 66 }
 67 
 68 static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
 69 {
 70         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 71         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 72         struct ep93xx_pcm_dma_params *dma_params;
 73         struct ep93xx_dma_data *dma_data;
 74         int ret;
 75 
 76         snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
 77 
 78         dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL);
 79         if (!dma_data)
 80                 return -ENOMEM;
 81 
 82         dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
 83         dma_data->port = dma_params->dma_port;
 84         dma_data->name = dma_params->name;
 85         dma_data->direction = snd_pcm_substream_to_dma_direction(substream);
 86 
 87         ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data);
 88         if (ret) {
 89                 kfree(dma_data);
 90                 return ret;
 91         }
 92 
 93         snd_dmaengine_pcm_set_data(substream, dma_data);
 94 
 95         return 0;
 96 }
 97 
 98 static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
 99 {
100         struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
101 
102         snd_dmaengine_pcm_close(substream);
103         kfree(dma_data);
104         return 0;
105 }
106 
107 static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
108                                 struct snd_pcm_hw_params *params)
109 {
110         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
111 
112         return 0;
113 }
114 
115 static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
116 {
117         snd_pcm_set_runtime_buffer(substream, NULL);
118         return 0;
119 }
120 
121 static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
122                            struct vm_area_struct *vma)
123 {
124         struct snd_pcm_runtime *runtime = substream->runtime;
125 
126         return dma_mmap_writecombine(substream->pcm->card->dev, vma,
127                                      runtime->dma_area,
128                                      runtime->dma_addr,
129                                      runtime->dma_bytes);
130 }
131 
132 static struct snd_pcm_ops ep93xx_pcm_ops = {
133         .open           = ep93xx_pcm_open,
134         .close          = ep93xx_pcm_close,
135         .ioctl          = snd_pcm_lib_ioctl,
136         .hw_params      = ep93xx_pcm_hw_params,
137         .hw_free        = ep93xx_pcm_hw_free,
138         .trigger        = snd_dmaengine_pcm_trigger,
139         .pointer        = snd_dmaengine_pcm_pointer,
140         .mmap           = ep93xx_pcm_mmap,
141 };
142 
143 static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
144 {
145         struct snd_pcm_substream *substream = pcm->streams[stream].substream;
146         struct snd_dma_buffer *buf = &substream->dma_buffer;
147         size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
148 
149         buf->dev.type = SNDRV_DMA_TYPE_DEV;
150         buf->dev.dev = pcm->card->dev;
151         buf->private_data = NULL;
152         buf->area = dma_alloc_writecombine(pcm->card->dev, size,
153                                            &buf->addr, GFP_KERNEL);
154         buf->bytes = size;
155 
156         return (buf->area == NULL) ? -ENOMEM : 0;
157 }
158 
159 static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
160 {
161         struct snd_pcm_substream *substream;
162         struct snd_dma_buffer *buf;
163         int stream;
164 
165         for (stream = 0; stream < 2; stream++) {                
166                 substream = pcm->streams[stream].substream;
167                 if (!substream)
168                         continue;
169                 
170                 buf = &substream->dma_buffer;
171                 if (!buf->area)
172                         continue;
173 
174                 dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
175                                       buf->addr);
176                 buf->area = NULL;
177         }
178 }
179 
180 static u64 ep93xx_pcm_dmamask = DMA_BIT_MASK(32);
181 
182 static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
183 {
184         struct snd_card *card = rtd->card->snd_card;
185         struct snd_pcm *pcm = rtd->pcm;
186         int ret = 0;
187 
188         if (!card->dev->dma_mask)
189                 card->dev->dma_mask = &ep93xx_pcm_dmamask;
190         if (!card->dev->coherent_dma_mask)
191                 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
192 
193         if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
194                 ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
195                                         SNDRV_PCM_STREAM_PLAYBACK);
196                 if (ret)
197                         return ret;
198         }
199 
200         if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
201                 ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
202                                         SNDRV_PCM_STREAM_CAPTURE);
203                 if (ret)
204                         return ret;
205         }
206 
207         return 0;
208 }
209 
210 static struct snd_soc_platform_driver ep93xx_soc_platform = {
211         .ops            = &ep93xx_pcm_ops,
212         .pcm_new        = &ep93xx_pcm_new,
213         .pcm_free       = &ep93xx_pcm_free_dma_buffers,
214 };
215 
216 static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev)
217 {
218         return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
219 }
220 
221 static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev)
222 {
223         snd_soc_unregister_platform(&pdev->dev);
224         return 0;
225 }
226 
227 static struct platform_driver ep93xx_pcm_driver = {
228         .driver = {
229                         .name = "ep93xx-pcm-audio",
230                         .owner = THIS_MODULE,
231         },
232 
233         .probe = ep93xx_soc_platform_probe,
234         .remove = __devexit_p(ep93xx_soc_platform_remove),
235 };
236 
237 module_platform_driver(ep93xx_pcm_driver);
238 
239 MODULE_AUTHOR("Ryan Mallon");
240 MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
241 MODULE_LICENSE("GPL");
242 MODULE_ALIAS("platform:ep93xx-pcm-audio");
243 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp