diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2013-04-15 13:19:51 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-04-17 09:21:36 -0400 |
commit | c999836d37c6c1125e856f68877ae13952baa61a (patch) | |
tree | 77ca9109474b59a6a811e36784f3fed5b3458a2e | |
parent | 28c4468b00a1e55e08cc20117de968f7c6275441 (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.h | 29 | ||||
-rw-r--r-- | sound/soc/soc-dmaengine-pcm.c | 14 | ||||
-rw-r--r-- | sound/soc/soc-generic-dmaengine-pcm.c | 32 |
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); |
47 | int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream); | 48 | int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream); |
48 | 49 | ||
50 | struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn, | ||
51 | void *filter_data); | ||
49 | struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); | 52 | struct 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 | */ |
82 | struct snd_dmaengine_pcm_config { | 107 | struct 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 | } |
255 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); | 255 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); |
256 | 256 | ||
257 | static 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 | */ | ||
266 | struct 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 | } |
277 | EXPORT_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 | } |
325 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan); | 335 | EXPORT_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 | ||
34 | static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p) | 35 | static 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 | ||
125 | static 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 | |||
124 | static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) | 138 | static 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 | ||
176 | static const char * const dmaengine_pcm_dma_channel_names[] = { | 196 | static 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, |