Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
jz4740-pcm.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010, Lars-Peter Clausen <[email protected]>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * You should have received a copy of the GNU General Public License along
10  * with this program; if not, write to the Free Software Foundation, Inc.,
11  * 675 Mass Ave, Cambridge, MA 02139, USA.
12  *
13  */
14 
15 #include <linux/init.h>
16 #include <linux/interrupt.h>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/platform_device.h>
20 #include <linux/slab.h>
21 
22 #include <linux/dma-mapping.h>
23 
24 #include <sound/core.h>
25 #include <sound/pcm.h>
26 #include <sound/pcm_params.h>
27 #include <sound/soc.h>
28 
29 #include <asm/mach-jz4740/dma.h>
30 #include "jz4740-pcm.h"
31 
33  unsigned long dma_period;
37 
39 
41 };
42 
43 /* identify hardware playback capabilities */
44 static const struct snd_pcm_hardware jz4740_pcm_hardware = {
45  .info = SNDRV_PCM_INFO_MMAP |
50 
52  .channels_min = 1,
53  .channels_max = 2,
54  .period_bytes_min = 16,
55  .period_bytes_max = 2 * PAGE_SIZE,
56  .periods_min = 2,
57  .periods_max = 128,
58  .buffer_bytes_max = 128 * 2 * PAGE_SIZE,
59  .fifo_size = 32,
60 };
61 
62 static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd,
63  struct snd_pcm_substream *substream)
64 {
65  unsigned long count;
66 
67  if (prtd->dma_pos == prtd->dma_end)
68  prtd->dma_pos = prtd->dma_start;
69 
70  if (prtd->dma_pos + prtd->dma_period > prtd->dma_end)
71  count = prtd->dma_end - prtd->dma_pos;
72  else
73  count = prtd->dma_period;
74 
75  jz4740_dma_disable(prtd->dma);
76 
77  if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
78  jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos);
80  } else {
82  jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos);
83  }
84 
85  jz4740_dma_set_transfer_count(prtd->dma, count);
86 
87  prtd->dma_pos += count;
88 
89  jz4740_dma_enable(prtd->dma);
90 }
91 
92 static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err,
93  void *dev_id)
94 {
95  struct snd_pcm_substream *substream = dev_id;
96  struct snd_pcm_runtime *runtime = substream->runtime;
97  struct jz4740_runtime_data *prtd = runtime->private_data;
98 
99  snd_pcm_period_elapsed(substream);
100 
101  jz4740_pcm_start_transfer(prtd, substream);
102 }
103 
104 static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
105  struct snd_pcm_hw_params *params)
106 {
107  struct snd_pcm_runtime *runtime = substream->runtime;
108  struct jz4740_runtime_data *prtd = runtime->private_data;
109  struct snd_soc_pcm_runtime *rtd = substream->private_data;
110  struct jz4740_pcm_config *config;
111 
112  config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
113 
114  if (!config)
115  return 0;
116 
117  if (!prtd->dma) {
118  if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
119  prtd->dma = jz4740_dma_request(substream, "PCM Capture");
120  else
121  prtd->dma = jz4740_dma_request(substream, "PCM Playback");
122  }
123 
124  if (!prtd->dma)
125  return -EBUSY;
126 
127  jz4740_dma_configure(prtd->dma, &config->dma_config);
128  prtd->fifo_addr = config->fifo_addr;
129 
130  jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done);
131 
132  snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
133  runtime->dma_bytes = params_buffer_bytes(params);
134 
135  prtd->dma_period = params_period_bytes(params);
136  prtd->dma_start = runtime->dma_addr;
137  prtd->dma_pos = prtd->dma_start;
138  prtd->dma_end = prtd->dma_start + runtime->dma_bytes;
139 
140  return 0;
141 }
142 
143 static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
144 {
145  struct jz4740_runtime_data *prtd = substream->runtime->private_data;
146 
147  snd_pcm_set_runtime_buffer(substream, NULL);
148  if (prtd->dma) {
149  jz4740_dma_free(prtd->dma);
150  prtd->dma = NULL;
151  }
152 
153  return 0;
154 }
155 
156 static int jz4740_pcm_prepare(struct snd_pcm_substream *substream)
157 {
158  struct jz4740_runtime_data *prtd = substream->runtime->private_data;
159 
160  if (!prtd->dma)
161  return -EBUSY;
162 
163  prtd->dma_pos = prtd->dma_start;
164 
165  return 0;
166 }
167 
168 static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
169 {
170  struct snd_pcm_runtime *runtime = substream->runtime;
171  struct jz4740_runtime_data *prtd = runtime->private_data;
172 
173  switch (cmd) {
177  jz4740_pcm_start_transfer(prtd, substream);
178  break;
182  jz4740_dma_disable(prtd->dma);
183  break;
184  default:
185  break;
186  }
187 
188  return 0;
189 }
190 
191 static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream)
192 {
193  struct snd_pcm_runtime *runtime = substream->runtime;
194  struct jz4740_runtime_data *prtd = runtime->private_data;
195  unsigned long byte_offset;
197  struct jz4740_dma_chan *dma = prtd->dma;
198 
199  /* prtd->dma_pos points to the end of the current transfer. So by
200  * subtracting prdt->dma_start we get the offset to the end of the
201  * current period in bytes. By subtracting the residue of the transfer
202  * we get the current offset in bytes. */
203  byte_offset = prtd->dma_pos - prtd->dma_start;
204  byte_offset -= jz4740_dma_get_residue(dma);
205 
206  offset = bytes_to_frames(runtime, byte_offset);
207  if (offset >= runtime->buffer_size)
208  offset = 0;
209 
210  return offset;
211 }
212 
213 static int jz4740_pcm_open(struct snd_pcm_substream *substream)
214 {
215  struct snd_pcm_runtime *runtime = substream->runtime;
216  struct jz4740_runtime_data *prtd;
217 
218  prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
219  if (prtd == NULL)
220  return -ENOMEM;
221 
222  snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
223 
224  runtime->private_data = prtd;
225 
226  return 0;
227 }
228 
229 static int jz4740_pcm_close(struct snd_pcm_substream *substream)
230 {
231  struct snd_pcm_runtime *runtime = substream->runtime;
232  struct jz4740_runtime_data *prtd = runtime->private_data;
233 
234  kfree(prtd);
235 
236  return 0;
237 }
238 
239 static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
240  struct vm_area_struct *vma)
241 {
242  return remap_pfn_range(vma, vma->vm_start,
243  substream->dma_buffer.addr >> PAGE_SHIFT,
244  vma->vm_end - vma->vm_start, vma->vm_page_prot);
245 }
246 
247 static struct snd_pcm_ops jz4740_pcm_ops = {
248  .open = jz4740_pcm_open,
249  .close = jz4740_pcm_close,
250  .ioctl = snd_pcm_lib_ioctl,
251  .hw_params = jz4740_pcm_hw_params,
252  .hw_free = jz4740_pcm_hw_free,
253  .prepare = jz4740_pcm_prepare,
254  .trigger = jz4740_pcm_trigger,
255  .pointer = jz4740_pcm_pointer,
256  .mmap = jz4740_pcm_mmap,
257 };
258 
259 static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
260 {
261  struct snd_pcm_substream *substream = pcm->streams[stream].substream;
262  struct snd_dma_buffer *buf = &substream->dma_buffer;
263  size_t size = jz4740_pcm_hardware.buffer_bytes_max;
264 
265  buf->dev.type = SNDRV_DMA_TYPE_DEV;
266  buf->dev.dev = pcm->card->dev;
267  buf->private_data = NULL;
268 
269  buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
270  &buf->addr, GFP_KERNEL);
271  if (!buf->area)
272  return -ENOMEM;
273 
274  buf->bytes = size;
275 
276  return 0;
277 }
278 
279 static void jz4740_pcm_free(struct snd_pcm *pcm)
280 {
281  struct snd_pcm_substream *substream;
282  struct snd_dma_buffer *buf;
283  int stream;
284 
285  for (stream = 0; stream < SNDRV_PCM_STREAM_LAST; ++stream) {
286  substream = pcm->streams[stream].substream;
287  if (!substream)
288  continue;
289 
290  buf = &substream->dma_buffer;
291  if (!buf->area)
292  continue;
293 
294  dma_free_noncoherent(pcm->card->dev, buf->bytes, buf->area,
295  buf->addr);
296  buf->area = NULL;
297  }
298 }
299 
300 static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
301 
302 static int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
303 {
304  struct snd_card *card = rtd->card->snd_card;
305  struct snd_pcm *pcm = rtd->pcm;
306  int ret = 0;
307 
308  if (!card->dev->dma_mask)
309  card->dev->dma_mask = &jz4740_pcm_dmamask;
310 
311  if (!card->dev->coherent_dma_mask)
312  card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
313 
314  if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
315  ret = jz4740_pcm_preallocate_dma_buffer(pcm,
317  if (ret)
318  goto err;
319  }
320 
321  if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
322  ret = jz4740_pcm_preallocate_dma_buffer(pcm,
324  if (ret)
325  goto err;
326  }
327 
328 err:
329  return ret;
330 }
331 
332 static struct snd_soc_platform_driver jz4740_soc_platform = {
333  .ops = &jz4740_pcm_ops,
334  .pcm_new = jz4740_pcm_new,
335  .pcm_free = jz4740_pcm_free,
336 };
337 
338 static int __devinit jz4740_pcm_probe(struct platform_device *pdev)
339 {
340  return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform);
341 }
342 
343 static int __devexit jz4740_pcm_remove(struct platform_device *pdev)
344 {
346  return 0;
347 }
348 
349 static struct platform_driver jz4740_pcm_driver = {
350  .probe = jz4740_pcm_probe,
351  .remove = __devexit_p(jz4740_pcm_remove),
352  .driver = {
353  .name = "jz4740-pcm-audio",
354  .owner = THIS_MODULE,
355  },
356 };
357 
358 module_platform_driver(jz4740_pcm_driver);
359 
360 MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
361 MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver");
362 MODULE_LICENSE("GPL");