aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2013-04-15 13:20:04 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-04-18 10:04:44 -0400
commit22f38f792ec53e2a93be13ecb609bbe911ed8ff9 (patch)
treecbbd8ee051127923651133bdf505b5b0e520e2f5 /sound/soc
parentadaa3229fbb88532e0d460afad779efbfb92ffeb (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/Kconfig2
-rw-r--r--sound/soc/ux500/ux500_pcm.c159
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
16config SND_SOC_UX500_PLAT_DMA 16config 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
43static struct snd_pcm_hardware ux500_pcm_hw = { 43static 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
64static void ux500_pcm_dma_hw_free(struct device *dev, 64static 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
82static 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
140static 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
189static 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
200static int ux500_pcm_mmap(struct snd_pcm_substream *substream, 106static 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
212static 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
223int 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
235static struct snd_soc_platform_driver ux500_pcm_soc_drv = {
236 .ops = &ux500_pcm_ops,
237 .pcm_new = ux500_pcm_new,
238}; 110};
239 111
240int ux500_pcm_register_platform(struct platform_device *pdev) 112int 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
256int ux500_pcm_unregister_platform(struct platform_device *pdev) 132int 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}
262EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); 137EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);