1 /* 2 * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. 3 * 4 * Based on sound/soc/imx/imx-pcm-dma-mx2.c 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #include <linux/clk.h> 22 #include <linux/delay.h> 23 #include <linux/device.h> 24 #include <linux/dma-mapping.h> 25 #include <linux/init.h> 26 #include <linux/interrupt.h> 27 #include <linux/module.h> 28 #include <linux/platform_device.h> 29 #include <linux/slab.h> 30 #include <linux/dmaengine.h> 31 32 #include <sound/core.h> 33 #include <sound/initval.h> 34 #include <sound/pcm.h> 35 #include <sound/pcm_params.h> 36 #include <sound/soc.h> 37 38 #include <mach/dma.h> 39 #include "mxs-pcm.h" 40 41 static struct snd_pcm_hardware snd_mxs_hardware = { 42 .info = SNDRV_PCM_INFO_MMAP | 43 SNDRV_PCM_INFO_MMAP_VALID | 44 SNDRV_PCM_INFO_PAUSE | 45 SNDRV_PCM_INFO_RESUME | 46 SNDRV_PCM_INFO_INTERLEAVED, 47 .formats = SNDRV_PCM_FMTBIT_S16_LE | 48 SNDRV_PCM_FMTBIT_S20_3LE | 49 SNDRV_PCM_FMTBIT_S24_LE, 50 .channels_min = 2, 51 .channels_max = 2, 52 .period_bytes_min = 32, 53 .period_bytes_max = 8192, 54 .periods_min = 1, 55 .periods_max = 52, 56 .buffer_bytes_max = 64 * 1024, 57 .fifo_size = 32, 58 59 }; 60 61 static void audio_dma_irq(void *data) 62 { 63 struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; 64 struct snd_pcm_runtime *runtime = substream->runtime; 65 struct mxs_pcm_runtime_data *iprtd = runtime->private_data; 66 67 iprtd->offset += iprtd->period_bytes; 68 iprtd->offset %= iprtd->period_bytes * iprtd->periods; 69 snd_pcm_period_elapsed(substream); 70 } 71 72 static bool filter(struct dma_chan *chan, void *param) 73 { 74 struct mxs_pcm_runtime_data *iprtd = param; 75 struct mxs_pcm_dma_params *dma_params = iprtd->dma_params; 76 77 if (!mxs_dma_is_apbx(chan)) 78 return false; 79 80 if (chan->chan_id != dma_params->chan_num) 81 return false; 82 83 chan->private = &iprtd->dma_data; 84 85 return true; 86 } 87 88 static int mxs_dma_alloc(struct snd_pcm_substream *substream, 89 struct snd_pcm_hw_params *params) 90 { 91 struct snd_soc_pcm_runtime *rtd = substream->private_data; 92 struct snd_pcm_runtime *runtime = substream->runtime; 93 struct mxs_pcm_runtime_data *iprtd = runtime->private_data; 94 dma_cap_mask_t mask; 95 96 iprtd->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); 97 98 dma_cap_zero(mask); 99 dma_cap_set(DMA_SLAVE, mask); 100 iprtd->dma_data.chan_irq = iprtd->dma_params->chan_irq; 101 iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); 102 if (!iprtd->dma_chan) 103 return -EINVAL; 104 105 return 0; 106 } 107 108 static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream, 109 struct snd_pcm_hw_params *params) 110 { 111 struct snd_pcm_runtime *runtime = substream->runtime; 112 struct mxs_pcm_runtime_data *iprtd = runtime->private_data; 113 unsigned long dma_addr; 114 struct dma_chan *chan; 115 int ret; 116 117 ret = mxs_dma_alloc(substream, params); 118 if (ret) 119 return ret; 120 chan = iprtd->dma_chan; 121 122 iprtd->size = params_buffer_bytes(params); 123 iprtd->periods = params_periods(params); 124 iprtd->period_bytes = params_period_bytes(params); 125 iprtd->offset = 0; 126 iprtd->period_time = HZ / (params_rate(params) / 127 params_period_size(params)); 128 129 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 130 131 dma_addr = runtime->dma_addr; 132 133 iprtd->buf = substream->dma_buffer.area; 134 135 iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr, 136 iprtd->period_bytes * iprtd->periods, 137 iprtd->period_bytes, 138 substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 139 DMA_TO_DEVICE : DMA_FROM_DEVICE); 140 if (!iprtd->desc) { 141 dev_err(&chan->dev->device, "cannot prepare slave dma\n"); 142 return -EINVAL; 143 } 144 145 iprtd->desc->callback = audio_dma_irq; 146 iprtd->desc->callback_param = substream; 147 148 return 0; 149 } 150 151 static int snd_mxs_pcm_hw_free(struct snd_pcm_substream *substream) 152 { 153 struct snd_pcm_runtime *runtime = substream->runtime; 154 struct mxs_pcm_runtime_data *iprtd = runtime->private_data; 155 156 if (iprtd->dma_chan) { 157 dma_release_channel(iprtd->dma_chan); 158 iprtd->dma_chan = NULL; 159 } 160 161 return 0; 162 } 163 164 static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 165 { 166 struct snd_pcm_runtime *runtime = substream->runtime; 167 struct mxs_pcm_runtime_data *iprtd = runtime->private_data; 168 169 switch (cmd) { 170 case SNDRV_PCM_TRIGGER_START: 171 case SNDRV_PCM_TRIGGER_RESUME: 172 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 173 dmaengine_submit(iprtd->desc); 174 175 break; 176 case SNDRV_PCM_TRIGGER_STOP: 177 case SNDRV_PCM_TRIGGER_SUSPEND: 178 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 179 dmaengine_terminate_all(iprtd->dma_chan); 180 181 break; 182 default: 183 return -EINVAL; 184 } 185 186 return 0; 187 } 188 189 static snd_pcm_uframes_t snd_mxs_pcm_pointer( 190 struct snd_pcm_substream *substream) 191 { 192 struct snd_pcm_runtime *runtime = substream->runtime; 193 struct mxs_pcm_runtime_data *iprtd = runtime->private_data; 194 195 return bytes_to_frames(substream->runtime, iprtd->offset); 196 } 197 198 static int snd_mxs_open(struct snd_pcm_substream *substream) 199 { 200 struct snd_pcm_runtime *runtime = substream->runtime; 201 struct mxs_pcm_runtime_data *iprtd; 202 int ret; 203 204 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); 205 if (iprtd == NULL) 206 return -ENOMEM; 207 runtime->private_data = iprtd; 208 209 ret = snd_pcm_hw_constraint_integer(substream->runtime, 210 SNDRV_PCM_HW_PARAM_PERIODS); 211 if (ret < 0) { 212 kfree(iprtd); 213 return ret; 214 } 215 216 snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); 217 218 return 0; 219 } 220 221 static int snd_mxs_close(struct snd_pcm_substream *substream) 222 { 223 struct snd_pcm_runtime *runtime = substream->runtime; 224 struct mxs_pcm_runtime_data *iprtd = runtime->private_data; 225 226 kfree(iprtd); 227 228 return 0; 229 } 230 231 static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream, 232 struct vm_area_struct *vma) 233 { 234 struct snd_pcm_runtime *runtime = substream->runtime; 235 236 return dma_mmap_writecombine(substream->pcm->card->dev, vma, 237 runtime->dma_area, 238 runtime->dma_addr, 239 runtime->dma_bytes); 240 } 241 242 static struct snd_pcm_ops mxs_pcm_ops = { 243 .open = snd_mxs_open, 244 .close = snd_mxs_close, 245 .ioctl = snd_pcm_lib_ioctl, 246 .hw_params = snd_mxs_pcm_hw_params, 247 .hw_free = snd_mxs_pcm_hw_free, 248 .trigger = snd_mxs_pcm_trigger, 249 .pointer = snd_mxs_pcm_pointer, 250 .mmap = snd_mxs_pcm_mmap, 251 }; 252 253 static int mxs_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) 254 { 255 struct snd_pcm_substream *substream = pcm->streams[stream].substream; 256 struct snd_dma_buffer *buf = &substream->dma_buffer; 257 size_t size = snd_mxs_hardware.buffer_bytes_max; 258 259 buf->dev.type = SNDRV_DMA_TYPE_DEV; 260 buf->dev.dev = pcm->card->dev; 261 buf->private_data = NULL; 262 buf->area = dma_alloc_writecombine(pcm->card->dev, size, 263 &buf->addr, GFP_KERNEL); 264 if (!buf->area) 265 return -ENOMEM; 266 buf->bytes = size; 267 268 return 0; 269 } 270 271 static u64 mxs_pcm_dmamask = DMA_BIT_MASK(32); 272 static int mxs_pcm_new(struct snd_soc_pcm_runtime *rtd) 273 { 274 struct snd_card *card = rtd->card->snd_card; 275 struct snd_pcm *pcm = rtd->pcm; 276 int ret = 0; 277 278 if (!card->dev->dma_mask) 279 card->dev->dma_mask = &mxs_pcm_dmamask; 280 if (!card->dev->coherent_dma_mask) 281 card->dev->coherent_dma_mask = DMA_BIT_MASK(32); 282 283 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 284 ret = mxs_pcm_preallocate_dma_buffer(pcm, 285 SNDRV_PCM_STREAM_PLAYBACK); 286 if (ret) 287 goto out; 288 } 289 290 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 291 ret = mxs_pcm_preallocate_dma_buffer(pcm, 292 SNDRV_PCM_STREAM_CAPTURE); 293 if (ret) 294 goto out; 295 } 296 297 out: 298 return ret; 299 } 300 301 static void mxs_pcm_free(struct snd_pcm *pcm) 302 { 303 struct snd_pcm_substream *substream; 304 struct snd_dma_buffer *buf; 305 int stream; 306 307 for (stream = 0; stream < 2; stream++) { 308 substream = pcm->streams[stream].substream; 309 if (!substream) 310 continue; 311 312 buf = &substream->dma_buffer; 313 if (!buf->area) 314 continue; 315 316 dma_free_writecombine(pcm->card->dev, buf->bytes, 317 buf->area, buf->addr); 318 buf->area = NULL; 319 } 320 } 321 322 static struct snd_soc_platform_driver mxs_soc_platform = { 323 .ops = &mxs_pcm_ops, 324 .pcm_new = mxs_pcm_new, 325 .pcm_free = mxs_pcm_free, 326 }; 327 328 static int __devinit mxs_soc_platform_probe(struct platform_device *pdev) 329 { 330 return snd_soc_register_platform(&pdev->dev, &mxs_soc_platform); 331 } 332 333 static int __devexit mxs_soc_platform_remove(struct platform_device *pdev) 334 { 335 snd_soc_unregister_platform(&pdev->dev); 336 337 return 0; 338 } 339 340 static struct platform_driver mxs_pcm_driver = { 341 .driver = { 342 .name = "mxs-pcm-audio", 343 .owner = THIS_MODULE, 344 }, 345 .probe = mxs_soc_platform_probe, 346 .remove = __devexit_p(mxs_soc_platform_remove), 347 }; 348 349 static int __init snd_mxs_pcm_init(void) 350 { 351 return platform_driver_register(&mxs_pcm_driver); 352 } 353 module_init(snd_mxs_pcm_init); 354 355 static void __exit snd_mxs_pcm_exit(void) 356 { 357 platform_driver_unregister(&mxs_pcm_driver); 358 } 359 module_exit(snd_mxs_pcm_exit); 360