aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2013-04-15 13:19:51 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-04-17 09:21:36 -0400
commitc999836d37c6c1125e856f68877ae13952baa61a (patch)
tree77ca9109474b59a6a811e36784f3fed5b3458a2e
parent28c4468b00a1e55e08cc20117de968f7c6275441 (diff)
ASoC: dmaengine_pcm: Add support for compat platforms
Add support for platforms which don't use devicetree yet or have to optionally support a non-devicetree way to request the DMA channel. The patch adds the compat_request_channel and compat_filter_fn callbacks to the snd_dmaengine_pcm_config struct. If the compat_request_channel is implemented it will be used to request the DMA channel. If not dma_request_channel with compat_filter_fn as the filter function will be used to request the channel. The patch also exports the snd_dmaengine_pcm_request_chan() function, since compat platforms will want to use it to request their DMA channel. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Tested-by: Stephen Warren <swarren@nvidia.com> Tested-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--include/sound/dmaengine_pcm.h29
-rw-r--r--sound/soc/soc-dmaengine-pcm.c14
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c32
3 files changed, 68 insertions, 7 deletions
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index e0bf24e90669..1a7897ab3572 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -16,6 +16,7 @@
16#define __SOUND_DMAENGINE_PCM_H__ 16#define __SOUND_DMAENGINE_PCM_H__
17 17
18#include <sound/pcm.h> 18#include <sound/pcm.h>
19#include <sound/soc.h>
19#include <linux/dmaengine.h> 20#include <linux/dmaengine.h>
20 21
21/** 22/**
@@ -46,6 +47,8 @@ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
46 dma_filter_fn filter_fn, void *filter_data); 47 dma_filter_fn filter_fn, void *filter_data);
47int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream); 48int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream);
48 49
50struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
51 void *filter_data);
49struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); 52struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream);
50 53
51/** 54/**
@@ -72,17 +75,43 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
72 const struct snd_dmaengine_dai_dma_data *dma_data, 75 const struct snd_dmaengine_dai_dma_data *dma_data,
73 struct dma_slave_config *config); 76 struct dma_slave_config *config);
74 77
78
79/*
80 * Try to request the DMA channel using compat_request_channel or
81 * compat_filter_fn if it couldn't be requested through devicetree.
82 */
83#define SND_DMAENGINE_PCM_FLAG_COMPAT BIT(0)
84/*
85 * Don't try to request the DMA channels through devicetree. This flag only
86 * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well.
87 */
88#define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1)
89
75/** 90/**
76 * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM 91 * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM
77 * @prepare_slave_config: Callback used to fill in the DMA slave_config for a 92 * @prepare_slave_config: Callback used to fill in the DMA slave_config for a
78 * PCM substream. Will be called from the PCM drivers hwparams callback. 93 * PCM substream. Will be called from the PCM drivers hwparams callback.
94 * @compat_request_channel: Callback to request a DMA channel for platforms
95 * which do not use devicetree.
96 * @compat_filter_fn: Will be used as the filter function when requesting a
97 * channel for platforms which do not use devicetree. The filter parameter
98 * will be the DAI's DMA data.
79 * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM. 99 * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM.
80 * @prealloc_buffer_size: Size of the preallocated audio buffer. 100 * @prealloc_buffer_size: Size of the preallocated audio buffer.
101 *
102 * Note: If both compat_request_channel and compat_filter_fn are set
103 * compat_request_channel will be used to request the channel and
104 * compat_filter_fn will be ignored. Otherwise the channel will be requested
105 * using dma_request_channel with compat_filter_fn as the filter function.
81 */ 106 */
82struct snd_dmaengine_pcm_config { 107struct snd_dmaengine_pcm_config {
83 int (*prepare_slave_config)(struct snd_pcm_substream *substream, 108 int (*prepare_slave_config)(struct snd_pcm_substream *substream,
84 struct snd_pcm_hw_params *params, 109 struct snd_pcm_hw_params *params,
85 struct dma_slave_config *slave_config); 110 struct dma_slave_config *slave_config);
111 struct dma_chan *(*compat_request_channel)(
112 struct snd_soc_pcm_runtime *rtd,
113 struct snd_pcm_substream *substream);
114 dma_filter_fn compat_filter_fn;
86 115
87 const struct snd_pcm_hardware *pcm_hardware; 116 const struct snd_pcm_hardware *pcm_hardware;
88 unsigned int prealloc_buffer_size; 117 unsigned int prealloc_buffer_size;
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
index b0420a75f412..aa924d9b7986 100644
--- a/sound/soc/soc-dmaengine-pcm.c
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -254,7 +254,16 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
254} 254}
255EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); 255EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
256 256
257static struct dma_chan *dmaengine_pcm_request_channel(dma_filter_fn filter_fn, 257/**
258 * snd_dmaengine_pcm_request_channel - Request channel for the dmaengine PCM
259 * @filter_fn: Filter function used to request the DMA channel
260 * @filter_data: Data passed to the DMA filter function
261 *
262 * Returns NULL or the requested DMA channel.
263 *
264 * This function request a DMA channel for usage with dmaengine PCM.
265 */
266struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
258 void *filter_data) 267 void *filter_data)
259{ 268{
260 dma_cap_mask_t mask; 269 dma_cap_mask_t mask;
@@ -265,6 +274,7 @@ static struct dma_chan *dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
265 274
266 return dma_request_channel(mask, filter_fn, filter_data); 275 return dma_request_channel(mask, filter_fn, filter_data);
267} 276}
277EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
268 278
269/** 279/**
270 * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream 280 * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
@@ -320,7 +330,7 @@ int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
320 dma_filter_fn filter_fn, void *filter_data) 330 dma_filter_fn filter_fn, void *filter_data)
321{ 331{
322 return snd_dmaengine_pcm_open(substream, 332 return snd_dmaengine_pcm_open(substream,
323 dmaengine_pcm_request_channel(filter_fn, filter_data)); 333 snd_dmaengine_pcm_request_channel(filter_fn, filter_data));
324} 334}
325EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); 335EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
326 336
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index acfc92698995..d6e638056389 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -29,6 +29,7 @@ struct dmaengine_pcm {
29 struct dma_chan *chan[SNDRV_PCM_STREAM_CAPTURE + 1]; 29 struct dma_chan *chan[SNDRV_PCM_STREAM_CAPTURE + 1];
30 const struct snd_dmaengine_pcm_config *config; 30 const struct snd_dmaengine_pcm_config *config;
31 struct snd_soc_platform platform; 31 struct snd_soc_platform platform;
32 bool compat;
32}; 33};
33 34
34static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p) 35static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p)
@@ -121,6 +122,19 @@ static void dmaengine_pcm_free(struct snd_pcm *pcm)
121 snd_pcm_lib_preallocate_free_for_all(pcm); 122 snd_pcm_lib_preallocate_free_for_all(pcm);
122} 123}
123 124
125static struct dma_chan *dmaengine_pcm_compat_request_channel(
126 struct snd_soc_pcm_runtime *rtd,
127 struct snd_pcm_substream *substream)
128{
129 struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
130
131 if (pcm->config->compat_request_channel)
132 return pcm->config->compat_request_channel(rtd, substream);
133
134 return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn,
135 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
136}
137
124static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) 138static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
125{ 139{
126 struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); 140 struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
@@ -134,6 +148,11 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
134 if (!substream) 148 if (!substream)
135 continue; 149 continue;
136 150
151 if (!pcm->chan[i] && pcm->compat) {
152 pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd,
153 substream);
154 }
155
137 if (!pcm->chan[i]) { 156 if (!pcm->chan[i]) {
138 dev_err(rtd->platform->dev, 157 dev_err(rtd->platform->dev,
139 "Missing dma channel for stream: %d\n", i); 158 "Missing dma channel for stream: %d\n", i);
@@ -171,6 +190,7 @@ static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
171 .ops = &dmaengine_pcm_ops, 190 .ops = &dmaengine_pcm_ops,
172 .pcm_new = dmaengine_pcm_new, 191 .pcm_new = dmaengine_pcm_new,
173 .pcm_free = dmaengine_pcm_free, 192 .pcm_free = dmaengine_pcm_free,
193 .probe_order = SND_SOC_COMP_ORDER_LATE,
174}; 194};
175 195
176static const char * const dmaengine_pcm_dma_channel_names[] = { 196static const char * const dmaengine_pcm_dma_channel_names[] = {
@@ -190,18 +210,20 @@ int snd_dmaengine_pcm_register(struct device *dev,
190 struct dmaengine_pcm *pcm; 210 struct dmaengine_pcm *pcm;
191 unsigned int i; 211 unsigned int i;
192 212
193 if (!dev->of_node)
194 return -EINVAL;
195
196 pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); 213 pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
197 if (!pcm) 214 if (!pcm)
198 return -ENOMEM; 215 return -ENOMEM;
199 216
200 pcm->config = config; 217 pcm->config = config;
201 218
202 for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { 219 if (flags & SND_DMAENGINE_PCM_FLAG_COMPAT)
203 pcm->chan[i] = of_dma_request_slave_channel(dev->of_node, 220 pcm->compat = true;
221
222 if (!(flags & SND_DMAENGINE_PCM_FLAG_NO_DT) && dev->of_node) {
223 for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
224 pcm->chan[i] = of_dma_request_slave_channel(dev->of_node,
204 dmaengine_pcm_dma_channel_names[i]); 225 dmaengine_pcm_dma_channel_names[i]);
226 }
205 } 227 }
206 228
207 return snd_soc_add_platform(dev, &pcm->platform, 229 return snd_soc_add_platform(dev, &pcm->platform,