aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2013-04-15 13:19:52 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-04-17 09:25:09 -0400
commit11a8576a0a3f153784fc4fca28e6fcee83531135 (patch)
tree38cf55ee000aafff1cf3c0b9fc5cc48290af4fc2
parent753e23ea588d353da9d0a2672828336453607265 (diff)
ASoC: tegra: Use generic dmaengine PCM
Use the generic dmaengine PCM driver instead of a custom implementation. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Tested-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--sound/soc/tegra/Kconfig2
-rw-r--r--sound/soc/tegra/tegra_pcm.c171
2 files changed, 10 insertions, 163 deletions
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index dbc27ce1d4de..b1c9d573da05 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -2,7 +2,7 @@ config SND_SOC_TEGRA
2 tristate "SoC Audio for the Tegra System-on-Chip" 2 tristate "SoC Audio for the Tegra System-on-Chip"
3 depends on ARCH_TEGRA && TEGRA20_APB_DMA 3 depends on ARCH_TEGRA && TEGRA20_APB_DMA
4 select REGMAP_MMIO 4 select REGMAP_MMIO
5 select SND_SOC_DMAENGINE_PCM if TEGRA20_APB_DMA 5 select SND_SOC_GENERIC_DMAENGINE_PCM if TEGRA20_APB_DMA
6 help 6 help
7 Say Y or M here if you want support for SoC audio on Tegra. 7 Say Y or M here if you want support for SoC audio on Tegra.
8 8
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index f9f247c64c6d..f056f632557c 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -29,9 +29,7 @@
29 * 29 *
30 */ 30 */
31 31
32#include <linux/dma-mapping.h>
33#include <linux/module.h> 32#include <linux/module.h>
34#include <linux/slab.h>
35#include <sound/core.h> 33#include <sound/core.h>
36#include <sound/pcm.h> 34#include <sound/pcm.h>
37#include <sound/pcm_params.h> 35#include <sound/pcm_params.h>
@@ -55,175 +53,24 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
55 .fifo_size = 4, 53 .fifo_size = 4,
56}; 54};
57 55
58static int tegra_pcm_open(struct snd_pcm_substream *substream) 56static const struct snd_dmaengine_pcm_config tegra_dmaengine_pcm_config = {
59{ 57 .pcm_hardware = &tegra_pcm_hardware,
60 struct snd_soc_pcm_runtime *rtd = substream->private_data; 58 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
61 struct device *dev = rtd->platform->dev; 59 .compat_filter_fn = NULL,
62 int ret; 60 .prealloc_buffer_size = PAGE_SIZE * 8,
63
64 /* Set HW params now that initialization is complete */
65 snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
66
67 ret = snd_dmaengine_pcm_open_request_chan(substream, NULL, NULL);
68 if (ret) {
69 dev_err(dev, "dmaengine pcm open failed with err %d\n", ret);
70 return ret;
71 }
72
73 return 0;
74}
75
76static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
77 struct snd_pcm_hw_params *params)
78{
79 struct snd_soc_pcm_runtime *rtd = substream->private_data;
80 struct device *dev = rtd->platform->dev;
81 struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
82 struct dma_slave_config slave_config;
83 int ret;
84
85 ret = snd_hwparams_to_dma_slave_config(substream, params,
86 &slave_config);
87 if (ret) {
88 dev_err(dev, "hw params config failed with err %d\n", ret);
89 return ret;
90 }
91
92 snd_dmaengine_pcm_set_config_from_dai_data(substream,
93 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
94 &slave_config);
95
96 ret = dmaengine_slave_config(chan, &slave_config);
97 if (ret < 0) {
98 dev_err(dev, "dma slave config failed with err %d\n", ret);
99 return ret;
100 }
101
102 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
103 return 0;
104}
105
106static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
107{
108 snd_pcm_set_runtime_buffer(substream, NULL);
109 return 0;
110}
111
112static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
113 struct vm_area_struct *vma)
114{
115 struct snd_pcm_runtime *runtime = substream->runtime;
116
117 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
118 runtime->dma_area,
119 runtime->dma_addr,
120 runtime->dma_bytes);
121}
122
123static struct snd_pcm_ops tegra_pcm_ops = {
124 .open = tegra_pcm_open,
125 .close = snd_dmaengine_pcm_close_release_chan,
126 .ioctl = snd_pcm_lib_ioctl,
127 .hw_params = tegra_pcm_hw_params,
128 .hw_free = tegra_pcm_hw_free,
129 .trigger = snd_dmaengine_pcm_trigger,
130 .pointer = snd_dmaengine_pcm_pointer,
131 .mmap = tegra_pcm_mmap,
132};
133
134static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
135{
136 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
137 struct snd_dma_buffer *buf = &substream->dma_buffer;
138 size_t size = tegra_pcm_hardware.buffer_bytes_max;
139
140 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
141 &buf->addr, GFP_KERNEL);
142 if (!buf->area)
143 return -ENOMEM;
144
145 buf->dev.type = SNDRV_DMA_TYPE_DEV;
146 buf->dev.dev = pcm->card->dev;
147 buf->private_data = NULL;
148 buf->bytes = size;
149
150 return 0;
151}
152
153static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
154{
155 struct snd_pcm_substream *substream;
156 struct snd_dma_buffer *buf;
157
158 substream = pcm->streams[stream].substream;
159 if (!substream)
160 return;
161
162 buf = &substream->dma_buffer;
163 if (!buf->area)
164 return;
165
166 dma_free_writecombine(pcm->card->dev, buf->bytes,
167 buf->area, buf->addr);
168 buf->area = NULL;
169}
170
171static u64 tegra_dma_mask = DMA_BIT_MASK(32);
172
173static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
174{
175 struct snd_card *card = rtd->card->snd_card;
176 struct snd_pcm *pcm = rtd->pcm;
177 int ret = 0;
178
179 if (!card->dev->dma_mask)
180 card->dev->dma_mask = &tegra_dma_mask;
181 if (!card->dev->coherent_dma_mask)
182 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
183
184 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
185 ret = tegra_pcm_preallocate_dma_buffer(pcm,
186 SNDRV_PCM_STREAM_PLAYBACK);
187 if (ret)
188 goto err;
189 }
190
191 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
192 ret = tegra_pcm_preallocate_dma_buffer(pcm,
193 SNDRV_PCM_STREAM_CAPTURE);
194 if (ret)
195 goto err_free_play;
196 }
197
198 return 0;
199
200err_free_play:
201 tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
202err:
203 return ret;
204}
205
206static void tegra_pcm_free(struct snd_pcm *pcm)
207{
208 tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
209 tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
210}
211
212static struct snd_soc_platform_driver tegra_pcm_platform = {
213 .ops = &tegra_pcm_ops,
214 .pcm_new = tegra_pcm_new,
215 .pcm_free = tegra_pcm_free,
216}; 61};
217 62
218int tegra_pcm_platform_register(struct device *dev) 63int tegra_pcm_platform_register(struct device *dev)
219{ 64{
220 return snd_soc_register_platform(dev, &tegra_pcm_platform); 65 return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config,
66 SND_DMAENGINE_PCM_FLAG_NO_DT |
67 SND_DMAENGINE_PCM_FLAG_COMPAT);
221} 68}
222EXPORT_SYMBOL_GPL(tegra_pcm_platform_register); 69EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
223 70
224void tegra_pcm_platform_unregister(struct device *dev) 71void tegra_pcm_platform_unregister(struct device *dev)
225{ 72{
226 snd_soc_unregister_platform(dev); 73 return snd_dmaengine_pcm_unregister(dev);
227} 74}
228EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister); 75EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
229 76