diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2013-04-15 13:19:52 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-04-17 09:25:09 -0400 |
commit | 11a8576a0a3f153784fc4fca28e6fcee83531135 (patch) | |
tree | 38cf55ee000aafff1cf3c0b9fc5cc48290af4fc2 | |
parent | 753e23ea588d353da9d0a2672828336453607265 (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/Kconfig | 2 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_pcm.c | 171 |
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 | ||
58 | static int tegra_pcm_open(struct snd_pcm_substream *substream) | 56 | static 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 | |||
76 | static 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 | |||
106 | static int tegra_pcm_hw_free(struct snd_pcm_substream *substream) | ||
107 | { | ||
108 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static 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 | |||
123 | static 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 | |||
134 | static 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 | |||
153 | static 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 | |||
171 | static u64 tegra_dma_mask = DMA_BIT_MASK(32); | ||
172 | |||
173 | static 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 | |||
200 | err_free_play: | ||
201 | tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); | ||
202 | err: | ||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | static 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 | |||
212 | static 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 | ||
218 | int tegra_pcm_platform_register(struct device *dev) | 63 | int 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 | } |
222 | EXPORT_SYMBOL_GPL(tegra_pcm_platform_register); | 69 | EXPORT_SYMBOL_GPL(tegra_pcm_platform_register); |
223 | 70 | ||
224 | void tegra_pcm_platform_unregister(struct device *dev) | 71 | void tegra_pcm_platform_unregister(struct device *dev) |
225 | { | 72 | { |
226 | snd_soc_unregister_platform(dev); | 73 | return snd_dmaengine_pcm_unregister(dev); |
227 | } | 74 | } |
228 | EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister); | 75 | EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister); |
229 | 76 | ||