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