xref: /linux/sound/soc/tegra/tegra_pcm.c (revision 26b0d14106954ae46d2f4f7eec3481828a210f7d)
1 /*
2  * tegra_pcm.c - Tegra PCM driver
3  *
4  * Author: Stephen Warren <swarren@nvidia.com>
5  * Copyright (C) 2010,2012 - NVIDIA, Inc.
6  *
7  * Based on code copyright/by:
8  *
9  * Copyright (c) 2009-2010, NVIDIA Corporation.
10  * Scott Peterson <speterson@nvidia.com>
11  * Vijay Mali <vmali@nvidia.com>
12  *
13  * Copyright (C) 2010 Google, Inc.
14  * Iliyan Malchev <malchev@google.com>
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * version 2 as published by the Free Software Foundation.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28  * 02110-1301 USA
29  *
30  */
31 
32 #include <linux/dma-mapping.h>
33 #include <linux/module.h>
34 #include <linux/slab.h>
35 #include <sound/core.h>
36 #include <sound/pcm.h>
37 #include <sound/pcm_params.h>
38 #include <sound/soc.h>
39 
40 #include "tegra_pcm.h"
41 
42 static const struct snd_pcm_hardware tegra_pcm_hardware = {
43 	.info			= SNDRV_PCM_INFO_MMAP |
44 				  SNDRV_PCM_INFO_MMAP_VALID |
45 				  SNDRV_PCM_INFO_PAUSE |
46 				  SNDRV_PCM_INFO_RESUME |
47 				  SNDRV_PCM_INFO_INTERLEAVED,
48 	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
49 	.channels_min		= 2,
50 	.channels_max		= 2,
51 	.period_bytes_min	= 1024,
52 	.period_bytes_max	= PAGE_SIZE,
53 	.periods_min		= 2,
54 	.periods_max		= 8,
55 	.buffer_bytes_max	= PAGE_SIZE * 8,
56 	.fifo_size		= 4,
57 };
58 
59 static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd)
60 {
61 	struct snd_pcm_substream *substream = prtd->substream;
62 	struct snd_dma_buffer *buf = &substream->dma_buffer;
63 	struct tegra_dma_req *dma_req;
64 	unsigned long addr;
65 
66 	dma_req = &prtd->dma_req[prtd->dma_req_idx];
67 	prtd->dma_req_idx = 1 - prtd->dma_req_idx;
68 
69 	addr = buf->addr + prtd->dma_pos;
70 	prtd->dma_pos += dma_req->size;
71 	if (prtd->dma_pos >= prtd->dma_pos_end)
72 		prtd->dma_pos = 0;
73 
74 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
75 		dma_req->source_addr = addr;
76 	else
77 		dma_req->dest_addr = addr;
78 
79 	tegra_dma_enqueue_req(prtd->dma_chan, dma_req);
80 }
81 
82 static void dma_complete_callback(struct tegra_dma_req *req)
83 {
84 	struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev;
85 	struct snd_pcm_substream *substream = prtd->substream;
86 	struct snd_pcm_runtime *runtime = substream->runtime;
87 
88 	spin_lock(&prtd->lock);
89 
90 	if (!prtd->running) {
91 		spin_unlock(&prtd->lock);
92 		return;
93 	}
94 
95 	if (++prtd->period_index >= runtime->periods)
96 		prtd->period_index = 0;
97 
98 	tegra_pcm_queue_dma(prtd);
99 
100 	spin_unlock(&prtd->lock);
101 
102 	snd_pcm_period_elapsed(substream);
103 }
104 
105 static void setup_dma_tx_request(struct tegra_dma_req *req,
106 					struct tegra_pcm_dma_params * dmap)
107 {
108 	req->complete = dma_complete_callback;
109 	req->to_memory = false;
110 	req->dest_addr = dmap->addr;
111 	req->dest_wrap = dmap->wrap;
112 	req->source_bus_width = 32;
113 	req->source_wrap = 0;
114 	req->dest_bus_width = dmap->width;
115 	req->req_sel = dmap->req_sel;
116 }
117 
118 static void setup_dma_rx_request(struct tegra_dma_req *req,
119 					struct tegra_pcm_dma_params * dmap)
120 {
121 	req->complete = dma_complete_callback;
122 	req->to_memory = true;
123 	req->source_addr = dmap->addr;
124 	req->dest_wrap = 0;
125 	req->source_bus_width = dmap->width;
126 	req->source_wrap = dmap->wrap;
127 	req->dest_bus_width = 32;
128 	req->req_sel = dmap->req_sel;
129 }
130 
131 static int tegra_pcm_open(struct snd_pcm_substream *substream)
132 {
133 	struct snd_pcm_runtime *runtime = substream->runtime;
134 	struct tegra_runtime_data *prtd;
135 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
136 	struct tegra_pcm_dma_params * dmap;
137 	int ret = 0;
138 
139 	prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL);
140 	if (prtd == NULL)
141 		return -ENOMEM;
142 
143 	runtime->private_data = prtd;
144 	prtd->substream = substream;
145 
146 	spin_lock_init(&prtd->lock);
147 
148 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
149 		dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
150 		setup_dma_tx_request(&prtd->dma_req[0], dmap);
151 		setup_dma_tx_request(&prtd->dma_req[1], dmap);
152 	} else {
153 		dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
154 		setup_dma_rx_request(&prtd->dma_req[0], dmap);
155 		setup_dma_rx_request(&prtd->dma_req[1], dmap);
156 	}
157 
158 	prtd->dma_req[0].dev = prtd;
159 	prtd->dma_req[1].dev = prtd;
160 
161 	prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
162 	if (prtd->dma_chan == NULL) {
163 		ret = -ENOMEM;
164 		goto err;
165 	}
166 
167 	/* Set HW params now that initialization is complete */
168 	snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
169 
170 	/* Ensure that buffer size is a multiple of period size */
171 	ret = snd_pcm_hw_constraint_integer(runtime,
172 						SNDRV_PCM_HW_PARAM_PERIODS);
173 	if (ret < 0)
174 		goto err;
175 
176 	return 0;
177 
178 err:
179 	if (prtd->dma_chan) {
180 		tegra_dma_free_channel(prtd->dma_chan);
181 	}
182 
183 	kfree(prtd);
184 
185 	return ret;
186 }
187 
188 static int tegra_pcm_close(struct snd_pcm_substream *substream)
189 {
190 	struct snd_pcm_runtime *runtime = substream->runtime;
191 	struct tegra_runtime_data *prtd = runtime->private_data;
192 
193 	tegra_dma_free_channel(prtd->dma_chan);
194 
195 	kfree(prtd);
196 
197 	return 0;
198 }
199 
200 static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
201 				struct snd_pcm_hw_params *params)
202 {
203 	struct snd_pcm_runtime *runtime = substream->runtime;
204 	struct tegra_runtime_data *prtd = runtime->private_data;
205 
206 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
207 
208 	prtd->dma_req[0].size = params_period_bytes(params);
209 	prtd->dma_req[1].size = prtd->dma_req[0].size;
210 
211 	return 0;
212 }
213 
214 static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
215 {
216 	snd_pcm_set_runtime_buffer(substream, NULL);
217 
218 	return 0;
219 }
220 
221 static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
222 {
223 	struct snd_pcm_runtime *runtime = substream->runtime;
224 	struct tegra_runtime_data *prtd = runtime->private_data;
225 	unsigned long flags;
226 
227 	switch (cmd) {
228 	case SNDRV_PCM_TRIGGER_START:
229 		prtd->dma_pos = 0;
230 		prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size);
231 		prtd->period_index = 0;
232 		prtd->dma_req_idx = 0;
233 		/* Fall-through */
234 	case SNDRV_PCM_TRIGGER_RESUME:
235 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
236 		spin_lock_irqsave(&prtd->lock, flags);
237 		prtd->running = 1;
238 		spin_unlock_irqrestore(&prtd->lock, flags);
239 		tegra_pcm_queue_dma(prtd);
240 		tegra_pcm_queue_dma(prtd);
241 		break;
242 	case SNDRV_PCM_TRIGGER_STOP:
243 	case SNDRV_PCM_TRIGGER_SUSPEND:
244 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
245 		spin_lock_irqsave(&prtd->lock, flags);
246 		prtd->running = 0;
247 		spin_unlock_irqrestore(&prtd->lock, flags);
248 		tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[0]);
249 		tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[1]);
250 		break;
251 	default:
252 		return -EINVAL;
253 	}
254 
255 	return 0;
256 }
257 
258 static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
259 {
260 	struct snd_pcm_runtime *runtime = substream->runtime;
261 	struct tegra_runtime_data *prtd = runtime->private_data;
262 
263 	return prtd->period_index * runtime->period_size;
264 }
265 
266 
267 static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
268 				struct vm_area_struct *vma)
269 {
270 	struct snd_pcm_runtime *runtime = substream->runtime;
271 
272 	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
273 					runtime->dma_area,
274 					runtime->dma_addr,
275 					runtime->dma_bytes);
276 }
277 
278 static struct snd_pcm_ops tegra_pcm_ops = {
279 	.open		= tegra_pcm_open,
280 	.close		= tegra_pcm_close,
281 	.ioctl		= snd_pcm_lib_ioctl,
282 	.hw_params	= tegra_pcm_hw_params,
283 	.hw_free	= tegra_pcm_hw_free,
284 	.trigger	= tegra_pcm_trigger,
285 	.pointer	= tegra_pcm_pointer,
286 	.mmap		= tegra_pcm_mmap,
287 };
288 
289 static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
290 {
291 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
292 	struct snd_dma_buffer *buf = &substream->dma_buffer;
293 	size_t size = tegra_pcm_hardware.buffer_bytes_max;
294 
295 	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
296 						&buf->addr, GFP_KERNEL);
297 	if (!buf->area)
298 		return -ENOMEM;
299 
300 	buf->dev.type = SNDRV_DMA_TYPE_DEV;
301 	buf->dev.dev = pcm->card->dev;
302 	buf->private_data = NULL;
303 	buf->bytes = size;
304 
305 	return 0;
306 }
307 
308 static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
309 {
310 	struct snd_pcm_substream *substream;
311 	struct snd_dma_buffer *buf;
312 
313 	substream = pcm->streams[stream].substream;
314 	if (!substream)
315 		return;
316 
317 	buf = &substream->dma_buffer;
318 	if (!buf->area)
319 		return;
320 
321 	dma_free_writecombine(pcm->card->dev, buf->bytes,
322 				buf->area, buf->addr);
323 	buf->area = NULL;
324 }
325 
326 static u64 tegra_dma_mask = DMA_BIT_MASK(32);
327 
328 static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
329 {
330 	struct snd_card *card = rtd->card->snd_card;
331 	struct snd_pcm *pcm = rtd->pcm;
332 	int ret = 0;
333 
334 	if (!card->dev->dma_mask)
335 		card->dev->dma_mask = &tegra_dma_mask;
336 	if (!card->dev->coherent_dma_mask)
337 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
338 
339 	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
340 		ret = tegra_pcm_preallocate_dma_buffer(pcm,
341 						SNDRV_PCM_STREAM_PLAYBACK);
342 		if (ret)
343 			goto err;
344 	}
345 
346 	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
347 		ret = tegra_pcm_preallocate_dma_buffer(pcm,
348 						SNDRV_PCM_STREAM_CAPTURE);
349 		if (ret)
350 			goto err_free_play;
351 	}
352 
353 	return 0;
354 
355 err_free_play:
356 	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
357 err:
358 	return ret;
359 }
360 
361 static void tegra_pcm_free(struct snd_pcm *pcm)
362 {
363 	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
364 	tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
365 }
366 
367 static struct snd_soc_platform_driver tegra_pcm_platform = {
368 	.ops		= &tegra_pcm_ops,
369 	.pcm_new	= tegra_pcm_new,
370 	.pcm_free	= tegra_pcm_free,
371 };
372 
373 int __devinit tegra_pcm_platform_register(struct device *dev)
374 {
375 	return snd_soc_register_platform(dev, &tegra_pcm_platform);
376 }
377 EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
378 
379 void __devexit tegra_pcm_platform_unregister(struct device *dev)
380 {
381 	snd_soc_unregister_platform(dev);
382 }
383 EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
384 
385 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
386 MODULE_DESCRIPTION("Tegra PCM ASoC driver");
387 MODULE_LICENSE("GPL");
388