diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2013-04-15 13:20:04 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-04-18 10:04:44 -0400 |
commit | 22f38f792ec53e2a93be13ecb609bbe911ed8ff9 (patch) | |
tree | cbbd8ee051127923651133bdf505b5b0e520e2f5 /sound/soc | |
parent | adaa3229fbb88532e0d460afad779efbfb92ffeb (diff) |
ASoC: ux500: Use generic dmaengine PCM
Use the generic dmaengine PCM driver instead of a custom implemention. There is
a minor functional change, the ux500 PCM driver did not preallocate the audio
buffer, while the generic dmaengine PCM driver will do this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/ux500/Kconfig | 2 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_pcm.c | 159 |
2 files changed, 18 insertions, 143 deletions
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig index 069330d82be5..c73c5907eb11 100644 --- a/sound/soc/ux500/Kconfig +++ b/sound/soc/ux500/Kconfig | |||
@@ -16,7 +16,7 @@ config SND_SOC_UX500_PLAT_MSP_I2S | |||
16 | config SND_SOC_UX500_PLAT_DMA | 16 | config SND_SOC_UX500_PLAT_DMA |
17 | tristate "Platform - DB8500 (DMA)" | 17 | tristate "Platform - DB8500 (DMA)" |
18 | depends on SND_SOC_UX500 | 18 | depends on SND_SOC_UX500 |
19 | select SND_SOC_DMAENGINE_PCM | 19 | select SND_SOC_GENERIC_DMAENGINE_PCM |
20 | help | 20 | help |
21 | Say Y if you want to enable the Ux500 platform-driver. | 21 | Say Y if you want to enable the Ux500 platform-driver. |
22 | 22 | ||
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c index a7d4f04e5964..b6e5ae277299 100644 --- a/sound/soc/ux500/ux500_pcm.c +++ b/sound/soc/ux500/ux500_pcm.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #define UX500_PLATFORM_PERIODS_MAX 48 | 40 | #define UX500_PLATFORM_PERIODS_MAX 48 |
41 | #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) | 41 | #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) |
42 | 42 | ||
43 | static struct snd_pcm_hardware ux500_pcm_hw = { | 43 | static const struct snd_pcm_hardware ux500_pcm_hw = { |
44 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 44 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
45 | SNDRV_PCM_INFO_MMAP | | 45 | SNDRV_PCM_INFO_MMAP | |
46 | SNDRV_PCM_INFO_RESUME | | 46 | SNDRV_PCM_INFO_RESUME | |
@@ -61,43 +61,23 @@ static struct snd_pcm_hardware ux500_pcm_hw = { | |||
61 | .periods_max = UX500_PLATFORM_PERIODS_MAX, | 61 | .periods_max = UX500_PLATFORM_PERIODS_MAX, |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static void ux500_pcm_dma_hw_free(struct device *dev, | 64 | static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd, |
65 | struct snd_pcm_substream *substream) | 65 | struct snd_pcm_substream *substream) |
66 | { | 66 | { |
67 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
68 | struct snd_dma_buffer *buf = runtime->dma_buffer_p; | ||
69 | |||
70 | if (runtime->dma_area == NULL) | ||
71 | return; | ||
72 | |||
73 | if (buf != &substream->dma_buffer) { | ||
74 | dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, | ||
75 | buf->addr); | ||
76 | kfree(runtime->dma_buffer_p); | ||
77 | } | ||
78 | |||
79 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
80 | } | ||
81 | |||
82 | static int ux500_pcm_open(struct snd_pcm_substream *substream) | ||
83 | { | ||
84 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
85 | struct snd_soc_dai *dai = rtd->cpu_dai; | 67 | struct snd_soc_dai *dai = rtd->cpu_dai; |
86 | struct device *dev = dai->dev; | 68 | struct device *dev = dai->dev; |
87 | int ret; | ||
88 | struct ux500_msp_dma_params *dma_params; | ||
89 | u16 per_data_width, mem_data_width; | 69 | u16 per_data_width, mem_data_width; |
90 | struct stedma40_chan_cfg *dma_cfg; | 70 | struct stedma40_chan_cfg *dma_cfg; |
71 | struct ux500_msp_dma_params *dma_params; | ||
91 | 72 | ||
92 | dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, | 73 | dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, |
93 | snd_pcm_stream_str(substream)); | 74 | snd_pcm_stream_str(substream)); |
94 | 75 | ||
95 | dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__); | 76 | dma_params = snd_soc_dai_get_dma_data(dai, substream); |
96 | snd_soc_set_runtime_hwparams(substream, &ux500_pcm_hw); | 77 | dma_cfg = dma_params->dma_cfg; |
97 | 78 | ||
98 | mem_data_width = STEDMA40_HALFWORD_WIDTH; | 79 | mem_data_width = STEDMA40_HALFWORD_WIDTH; |
99 | 80 | ||
100 | dma_params = snd_soc_dai_get_dma_data(dai, substream); | ||
101 | switch (dma_params->data_size) { | 81 | switch (dma_params->data_size) { |
102 | case 32: | 82 | case 32: |
103 | per_data_width = STEDMA40_WORD_WIDTH; | 83 | per_data_width = STEDMA40_WORD_WIDTH; |
@@ -110,13 +90,8 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) | |||
110 | break; | 90 | break; |
111 | default: | 91 | default: |
112 | per_data_width = STEDMA40_WORD_WIDTH; | 92 | per_data_width = STEDMA40_WORD_WIDTH; |
113 | dev_warn(rtd->platform->dev, | ||
114 | "%s: Unknown data-size (%d)! Assuming 32 bits.\n", | ||
115 | __func__, dma_params->data_size); | ||
116 | } | 93 | } |
117 | 94 | ||
118 | dma_cfg = dma_params->dma_cfg; | ||
119 | |||
120 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 95 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
121 | dma_cfg->src_info.data_width = mem_data_width; | 96 | dma_cfg->src_info.data_width = mem_data_width; |
122 | dma_cfg->dst_info.data_width = per_data_width; | 97 | dma_cfg->dst_info.data_width = per_data_width; |
@@ -125,123 +100,24 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream) | |||
125 | dma_cfg->dst_info.data_width = mem_data_width; | 100 | dma_cfg->dst_info.data_width = mem_data_width; |
126 | } | 101 | } |
127 | 102 | ||
128 | ret = snd_dmaengine_pcm_open_request_chan(substream, stedma40_filter, | 103 | return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg); |
129 | dma_cfg); | ||
130 | if (ret) { | ||
131 | dev_dbg(dai->dev, | ||
132 | "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n", | ||
133 | __func__, ret); | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int ux500_pcm_hw_params(struct snd_pcm_substream *substream, | ||
141 | struct snd_pcm_hw_params *hw_params) | ||
142 | { | ||
143 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
144 | struct snd_dma_buffer *buf = runtime->dma_buffer_p; | ||
145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
146 | int ret = 0; | ||
147 | int size; | ||
148 | |||
149 | dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__); | ||
150 | |||
151 | size = params_buffer_bytes(hw_params); | ||
152 | |||
153 | if (buf) { | ||
154 | if (buf->bytes >= size) | ||
155 | goto out; | ||
156 | ux500_pcm_dma_hw_free(NULL, substream); | ||
157 | } | ||
158 | |||
159 | if (substream->dma_buffer.area != NULL && | ||
160 | substream->dma_buffer.bytes >= size) { | ||
161 | buf = &substream->dma_buffer; | ||
162 | } else { | ||
163 | buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); | ||
164 | if (!buf) | ||
165 | goto nomem; | ||
166 | |||
167 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
168 | buf->dev.dev = NULL; | ||
169 | buf->area = dma_alloc_coherent(NULL, size, &buf->addr, | ||
170 | GFP_KERNEL); | ||
171 | buf->bytes = size; | ||
172 | buf->private_data = NULL; | ||
173 | |||
174 | if (!buf->area) | ||
175 | goto free; | ||
176 | } | ||
177 | snd_pcm_set_runtime_buffer(substream, buf); | ||
178 | ret = 1; | ||
179 | out: | ||
180 | runtime->dma_bytes = size; | ||
181 | return ret; | ||
182 | |||
183 | free: | ||
184 | kfree(buf); | ||
185 | nomem: | ||
186 | return -ENOMEM; | ||
187 | } | ||
188 | |||
189 | static int ux500_pcm_hw_free(struct snd_pcm_substream *substream) | ||
190 | { | ||
191 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
192 | |||
193 | dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__); | ||
194 | |||
195 | ux500_pcm_dma_hw_free(NULL, substream); | ||
196 | |||
197 | return 0; | ||
198 | } | 104 | } |
199 | 105 | ||
200 | static int ux500_pcm_mmap(struct snd_pcm_substream *substream, | 106 | static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = { |
201 | struct vm_area_struct *vma) | 107 | .pcm_hardware = &ux500_pcm_hw, |
202 | { | 108 | .compat_request_channel = ux500_pcm_request_chan, |
203 | struct snd_pcm_runtime *runtime = substream->runtime; | 109 | .prealloc_buffer_size = 128 * 1024, |
204 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
205 | |||
206 | dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__); | ||
207 | |||
208 | return dma_mmap_coherent(NULL, vma, runtime->dma_area, | ||
209 | runtime->dma_addr, runtime->dma_bytes); | ||
210 | } | ||
211 | |||
212 | static struct snd_pcm_ops ux500_pcm_ops = { | ||
213 | .open = ux500_pcm_open, | ||
214 | .close = snd_dmaengine_pcm_close_release_chan, | ||
215 | .ioctl = snd_pcm_lib_ioctl, | ||
216 | .hw_params = ux500_pcm_hw_params, | ||
217 | .hw_free = ux500_pcm_hw_free, | ||
218 | .trigger = snd_dmaengine_pcm_trigger, | ||
219 | .pointer = snd_dmaengine_pcm_pointer_no_residue, | ||
220 | .mmap = ux500_pcm_mmap | ||
221 | }; | ||
222 | |||
223 | int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
224 | { | ||
225 | struct snd_pcm *pcm = rtd->pcm; | ||
226 | |||
227 | dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__, | ||
228 | pcm->id); | ||
229 | |||
230 | pcm->info_flags = 0; | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static struct snd_soc_platform_driver ux500_pcm_soc_drv = { | ||
236 | .ops = &ux500_pcm_ops, | ||
237 | .pcm_new = ux500_pcm_new, | ||
238 | }; | 110 | }; |
239 | 111 | ||
240 | int ux500_pcm_register_platform(struct platform_device *pdev) | 112 | int ux500_pcm_register_platform(struct platform_device *pdev) |
241 | { | 113 | { |
242 | int ret; | 114 | int ret; |
243 | 115 | ||
244 | ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv); | 116 | ret = snd_dmaengine_pcm_register(&pdev->dev, |
117 | &ux500_dmaengine_pcm_config, | ||
118 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | | ||
119 | SND_DMAENGINE_PCM_FLAG_COMPAT | | ||
120 | SND_DMAENGINE_PCM_FLAG_NO_DT); | ||
245 | if (ret < 0) { | 121 | if (ret < 0) { |
246 | dev_err(&pdev->dev, | 122 | dev_err(&pdev->dev, |
247 | "%s: ERROR: Failed to register platform '%s' (%d)!\n", | 123 | "%s: ERROR: Failed to register platform '%s' (%d)!\n", |
@@ -255,8 +131,7 @@ EXPORT_SYMBOL_GPL(ux500_pcm_register_platform); | |||
255 | 131 | ||
256 | int ux500_pcm_unregister_platform(struct platform_device *pdev) | 132 | int ux500_pcm_unregister_platform(struct platform_device *pdev) |
257 | { | 133 | { |
258 | snd_soc_unregister_platform(&pdev->dev); | 134 | snd_dmaengine_pcm_unregister(&pdev->dev); |
259 | |||
260 | return 0; | 135 | return 0; |
261 | } | 136 | } |
262 | EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); | 137 | EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); |