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 <linux/platform_data/dma-ep93xx.h> 29 #include <mach/hardware.h> 30 #include <mach/ep93xx-regs.h> 31 32 static const struct snd_pcm_hardware ep93xx_pcm_hardware = { 33 .info = (SNDRV_PCM_INFO_MMAP | 34 SNDRV_PCM_INFO_MMAP_VALID | 35 SNDRV_PCM_INFO_INTERLEAVED | 36 SNDRV_PCM_INFO_BLOCK_TRANSFER), 37 38 .rates = SNDRV_PCM_RATE_8000_192000, 39 .rate_min = SNDRV_PCM_RATE_8000, 40 .rate_max = SNDRV_PCM_RATE_192000, 41 42 .formats = (SNDRV_PCM_FMTBIT_S16_LE | 43 SNDRV_PCM_FMTBIT_S24_LE | 44 SNDRV_PCM_FMTBIT_S32_LE), 45 46 .buffer_bytes_max = 131072, 47 .period_bytes_min = 32, 48 .period_bytes_max = 32768, 49 .periods_min = 1, 50 .periods_max = 32, 51 .fifo_size = 32, 52 }; 53 54 static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param) 55 { 56 struct ep93xx_dma_data *data = filter_param; 57 58 if (data->direction == ep93xx_dma_chan_direction(chan)) { 59 chan->private = data; 60 return true; 61 } 62 63 return false; 64 } 65 66 static int ep93xx_pcm_open(struct snd_pcm_substream *substream) 67 { 68 struct snd_soc_pcm_runtime *rtd = substream->private_data; 69 70 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); 71 72 return snd_dmaengine_pcm_open_request_chan(substream, 73 ep93xx_pcm_dma_filter, 74 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); 75 } 76 77 static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream, 78 struct snd_pcm_hw_params *params) 79 { 80 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 81 82 return 0; 83 } 84 85 static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream) 86 { 87 snd_pcm_set_runtime_buffer(substream, NULL); 88 return 0; 89 } 90 91 static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream, 92 struct vm_area_struct *vma) 93 { 94 struct snd_pcm_runtime *runtime = substream->runtime; 95 96 return dma_mmap_writecombine(substream->pcm->card->dev, vma, 97 runtime->dma_area, 98 runtime->dma_addr, 99 runtime->dma_bytes); 100 } 101 102 static struct snd_pcm_ops ep93xx_pcm_ops = { 103 .open = ep93xx_pcm_open, 104 .close = snd_dmaengine_pcm_close_release_chan, 105 .ioctl = snd_pcm_lib_ioctl, 106 .hw_params = ep93xx_pcm_hw_params, 107 .hw_free = ep93xx_pcm_hw_free, 108 .trigger = snd_dmaengine_pcm_trigger, 109 .pointer = snd_dmaengine_pcm_pointer_no_residue, 110 .mmap = ep93xx_pcm_mmap, 111 }; 112 113 static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) 114 { 115 struct snd_pcm_substream *substream = pcm->streams[stream].substream; 116 struct snd_dma_buffer *buf = &substream->dma_buffer; 117 size_t size = ep93xx_pcm_hardware.buffer_bytes_max; 118 119 buf->dev.type = SNDRV_DMA_TYPE_DEV; 120 buf->dev.dev = pcm->card->dev; 121 buf->private_data = NULL; 122 buf->area = dma_alloc_writecombine(pcm->card->dev, size, 123 &buf->addr, GFP_KERNEL); 124 buf->bytes = size; 125 126 return (buf->area == NULL) ? -ENOMEM : 0; 127 } 128 129 static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm) 130 { 131 struct snd_pcm_substream *substream; 132 struct snd_dma_buffer *buf; 133 int stream; 134 135 for (stream = 0; stream < 2; stream++) { 136 substream = pcm->streams[stream].substream; 137 if (!substream) 138 continue; 139 140 buf = &substream->dma_buffer; 141 if (!buf->area) 142 continue; 143 144 dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area, 145 buf->addr); 146 buf->area = NULL; 147 } 148 } 149 150 static u64 ep93xx_pcm_dmamask = DMA_BIT_MASK(32); 151 152 static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd) 153 { 154 struct snd_card *card = rtd->card->snd_card; 155 struct snd_pcm *pcm = rtd->pcm; 156 int ret = 0; 157 158 if (!card->dev->dma_mask) 159 card->dev->dma_mask = &ep93xx_pcm_dmamask; 160 if (!card->dev->coherent_dma_mask) 161 card->dev->coherent_dma_mask = DMA_BIT_MASK(32); 162 163 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 164 ret = ep93xx_pcm_preallocate_dma_buffer(pcm, 165 SNDRV_PCM_STREAM_PLAYBACK); 166 if (ret) 167 return ret; 168 } 169 170 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 171 ret = ep93xx_pcm_preallocate_dma_buffer(pcm, 172 SNDRV_PCM_STREAM_CAPTURE); 173 if (ret) 174 return ret; 175 } 176 177 return 0; 178 } 179 180 static struct snd_soc_platform_driver ep93xx_soc_platform = { 181 .ops = &ep93xx_pcm_ops, 182 .pcm_new = &ep93xx_pcm_new, 183 .pcm_free = &ep93xx_pcm_free_dma_buffers, 184 }; 185 186 static int ep93xx_soc_platform_probe(struct platform_device *pdev) 187 { 188 return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform); 189 } 190 191 static int ep93xx_soc_platform_remove(struct platform_device *pdev) 192 { 193 snd_soc_unregister_platform(&pdev->dev); 194 return 0; 195 } 196 197 static struct platform_driver ep93xx_pcm_driver = { 198 .driver = { 199 .name = "ep93xx-pcm-audio", 200 .owner = THIS_MODULE, 201 }, 202 203 .probe = ep93xx_soc_platform_probe, 204 .remove = ep93xx_soc_platform_remove, 205 }; 206 207 module_platform_driver(ep93xx_pcm_driver); 208 209 MODULE_AUTHOR("Ryan Mallon"); 210 MODULE_DESCRIPTION("EP93xx ALSA PCM interface"); 211 MODULE_LICENSE("GPL"); 212 MODULE_ALIAS("platform:ep93xx-pcm-audio"); 213