aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2014-01-02 08:01:52 -0500
committerMark Brown <broonie@linaro.org>2014-01-02 08:01:52 -0500
commit75aac8206006e70859930d356ccfe02543530c27 (patch)
tree3d7581b0dd992da0661a1eea81737d427ac81eb4
parent01ad154ea505aeda249a4db4140a276f3eae509b (diff)
parent2b67f8ba41ac7acf01c8d5c742c713ead8b589cd (diff)
Merge remote-tracking branch 'asoc/topic/dma' into asoc-next
-rw-r--r--drivers/dma/dmaengine.c35
-rw-r--r--drivers/dma/of-dma.c15
-rw-r--r--include/linux/dmaengine.h8
-rw-r--r--include/sound/dmaengine_pcm.h10
-rw-r--r--sound/soc/soc-devres.c41
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c56
6 files changed, 144 insertions, 21 deletions
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index ef63b9058f3c..92caad629d99 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -540,6 +540,8 @@ EXPORT_SYMBOL_GPL(dma_get_slave_channel);
540 * @mask: capabilities that the channel must satisfy 540 * @mask: capabilities that the channel must satisfy
541 * @fn: optional callback to disposition available channels 541 * @fn: optional callback to disposition available channels
542 * @fn_param: opaque parameter to pass to dma_filter_fn 542 * @fn_param: opaque parameter to pass to dma_filter_fn
543 *
544 * Returns pointer to appropriate DMA channel on success or NULL.
543 */ 545 */
544struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, 546struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
545 dma_filter_fn fn, void *fn_param) 547 dma_filter_fn fn, void *fn_param)
@@ -591,18 +593,43 @@ EXPORT_SYMBOL_GPL(__dma_request_channel);
591 * dma_request_slave_channel - try to allocate an exclusive slave channel 593 * dma_request_slave_channel - try to allocate an exclusive slave channel
592 * @dev: pointer to client device structure 594 * @dev: pointer to client device structure
593 * @name: slave channel name 595 * @name: slave channel name
596 *
597 * Returns pointer to appropriate DMA channel on success or an error pointer.
594 */ 598 */
595struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) 599struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
600 const char *name)
596{ 601{
602 struct dma_chan *chan;
603
597 /* If device-tree is present get slave info from here */ 604 /* If device-tree is present get slave info from here */
598 if (dev->of_node) 605 if (dev->of_node)
599 return of_dma_request_slave_channel(dev->of_node, name); 606 return of_dma_request_slave_channel(dev->of_node, name);
600 607
601 /* If device was enumerated by ACPI get slave info from here */ 608 /* If device was enumerated by ACPI get slave info from here */
602 if (ACPI_HANDLE(dev)) 609 if (ACPI_HANDLE(dev)) {
603 return acpi_dma_request_slave_chan_by_name(dev, name); 610 chan = acpi_dma_request_slave_chan_by_name(dev, name);
611 if (chan)
612 return chan;
613 }
604 614
605 return NULL; 615 return ERR_PTR(-ENODEV);
616}
617EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason);
618
619/**
620 * dma_request_slave_channel - try to allocate an exclusive slave channel
621 * @dev: pointer to client device structure
622 * @name: slave channel name
623 *
624 * Returns pointer to appropriate DMA channel on success or NULL.
625 */
626struct dma_chan *dma_request_slave_channel(struct device *dev,
627 const char *name)
628{
629 struct dma_chan *ch = dma_request_slave_channel_reason(dev, name);
630 if (IS_ERR(ch))
631 return NULL;
632 return ch;
606} 633}
607EXPORT_SYMBOL_GPL(dma_request_slave_channel); 634EXPORT_SYMBOL_GPL(dma_request_slave_channel);
608 635
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index 0b88dd3d05f4..e8fe9dc455f4 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -143,7 +143,7 @@ static int of_dma_match_channel(struct device_node *np, const char *name,
143 * @np: device node to get DMA request from 143 * @np: device node to get DMA request from
144 * @name: name of desired channel 144 * @name: name of desired channel
145 * 145 *
146 * Returns pointer to appropriate dma channel on success or NULL on error. 146 * Returns pointer to appropriate DMA channel on success or an error pointer.
147 */ 147 */
148struct dma_chan *of_dma_request_slave_channel(struct device_node *np, 148struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
149 const char *name) 149 const char *name)
@@ -152,17 +152,18 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
152 struct of_dma *ofdma; 152 struct of_dma *ofdma;
153 struct dma_chan *chan; 153 struct dma_chan *chan;
154 int count, i; 154 int count, i;
155 int ret_no_channel = -ENODEV;
155 156
156 if (!np || !name) { 157 if (!np || !name) {
157 pr_err("%s: not enough information provided\n", __func__); 158 pr_err("%s: not enough information provided\n", __func__);
158 return NULL; 159 return ERR_PTR(-ENODEV);
159 } 160 }
160 161
161 count = of_property_count_strings(np, "dma-names"); 162 count = of_property_count_strings(np, "dma-names");
162 if (count < 0) { 163 if (count < 0) {
163 pr_err("%s: dma-names property of node '%s' missing or empty\n", 164 pr_err("%s: dma-names property of node '%s' missing or empty\n",
164 __func__, np->full_name); 165 __func__, np->full_name);
165 return NULL; 166 return ERR_PTR(-ENODEV);
166 } 167 }
167 168
168 for (i = 0; i < count; i++) { 169 for (i = 0; i < count; i++) {
@@ -172,10 +173,12 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
172 mutex_lock(&of_dma_lock); 173 mutex_lock(&of_dma_lock);
173 ofdma = of_dma_find_controller(&dma_spec); 174 ofdma = of_dma_find_controller(&dma_spec);
174 175
175 if (ofdma) 176 if (ofdma) {
176 chan = ofdma->of_dma_xlate(&dma_spec, ofdma); 177 chan = ofdma->of_dma_xlate(&dma_spec, ofdma);
177 else 178 } else {
179 ret_no_channel = -EPROBE_DEFER;
178 chan = NULL; 180 chan = NULL;
181 }
179 182
180 mutex_unlock(&of_dma_lock); 183 mutex_unlock(&of_dma_lock);
181 184
@@ -185,7 +188,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
185 return chan; 188 return chan;
186 } 189 }
187 190
188 return NULL; 191 return ERR_PTR(ret_no_channel);
189} 192}
190 193
191/** 194/**
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 41cf0c399288..ed92b30a02fd 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -22,6 +22,7 @@
22#define LINUX_DMAENGINE_H 22#define LINUX_DMAENGINE_H
23 23
24#include <linux/device.h> 24#include <linux/device.h>
25#include <linux/err.h>
25#include <linux/uio.h> 26#include <linux/uio.h>
26#include <linux/bug.h> 27#include <linux/bug.h>
27#include <linux/scatterlist.h> 28#include <linux/scatterlist.h>
@@ -1040,6 +1041,8 @@ enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
1040void dma_issue_pending_all(void); 1041void dma_issue_pending_all(void);
1041struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, 1042struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
1042 dma_filter_fn fn, void *fn_param); 1043 dma_filter_fn fn, void *fn_param);
1044struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
1045 const char *name);
1043struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name); 1046struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name);
1044void dma_release_channel(struct dma_chan *chan); 1047void dma_release_channel(struct dma_chan *chan);
1045#else 1048#else
@@ -1063,6 +1066,11 @@ static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
1063{ 1066{
1064 return NULL; 1067 return NULL;
1065} 1068}
1069static inline struct dma_chan *dma_request_slave_channel_reason(
1070 struct device *dev, const char *name)
1071{
1072 return ERR_PTR(-ENODEV);
1073}
1066static inline struct dma_chan *dma_request_slave_channel(struct device *dev, 1074static inline struct dma_chan *dma_request_slave_channel(struct device *dev,
1067 const char *name) 1075 const char *name)
1068{ 1076{
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index 15017311f2e9..eb73a3a39ec2 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -114,6 +114,10 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
114 * @compat_filter_fn: Will be used as the filter function when requesting a 114 * @compat_filter_fn: Will be used as the filter function when requesting a
115 * channel for platforms which do not use devicetree. The filter parameter 115 * channel for platforms which do not use devicetree. The filter parameter
116 * will be the DAI's DMA data. 116 * will be the DAI's DMA data.
117 * @dma_dev: If set, request DMA channel on this device rather than the DAI
118 * device.
119 * @chan_names: If set, these custom DMA channel names will be requested at
120 * registration time.
117 * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM. 121 * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM.
118 * @prealloc_buffer_size: Size of the preallocated audio buffer. 122 * @prealloc_buffer_size: Size of the preallocated audio buffer.
119 * 123 *
@@ -130,6 +134,8 @@ struct snd_dmaengine_pcm_config {
130 struct snd_soc_pcm_runtime *rtd, 134 struct snd_soc_pcm_runtime *rtd,
131 struct snd_pcm_substream *substream); 135 struct snd_pcm_substream *substream);
132 dma_filter_fn compat_filter_fn; 136 dma_filter_fn compat_filter_fn;
137 struct device *dma_dev;
138 const char *chan_names[SNDRV_PCM_STREAM_LAST + 1];
133 139
134 const struct snd_pcm_hardware *pcm_hardware; 140 const struct snd_pcm_hardware *pcm_hardware;
135 unsigned int prealloc_buffer_size; 141 unsigned int prealloc_buffer_size;
@@ -140,6 +146,10 @@ int snd_dmaengine_pcm_register(struct device *dev,
140 unsigned int flags); 146 unsigned int flags);
141void snd_dmaengine_pcm_unregister(struct device *dev); 147void snd_dmaengine_pcm_unregister(struct device *dev);
142 148
149int devm_snd_dmaengine_pcm_register(struct device *dev,
150 const struct snd_dmaengine_pcm_config *config,
151 unsigned int flags);
152
143int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, 153int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
144 struct snd_pcm_hw_params *params, 154 struct snd_pcm_hw_params *params,
145 struct dma_slave_config *slave_config); 155 struct dma_slave_config *slave_config);
diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c
index 3449c1e909ae..7ac745df1412 100644
--- a/sound/soc/soc-devres.c
+++ b/sound/soc/soc-devres.c
@@ -12,6 +12,7 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/moduleparam.h> 13#include <linux/moduleparam.h>
14#include <sound/soc.h> 14#include <sound/soc.h>
15#include <sound/dmaengine_pcm.h>
15 16
16static void devm_component_release(struct device *dev, void *res) 17static void devm_component_release(struct device *dev, void *res)
17{ 18{
@@ -84,3 +85,43 @@ int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card)
84 return ret; 85 return ret;
85} 86}
86EXPORT_SYMBOL_GPL(devm_snd_soc_register_card); 87EXPORT_SYMBOL_GPL(devm_snd_soc_register_card);
88
89#ifdef CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM
90
91static void devm_dmaengine_pcm_release(struct device *dev, void *res)
92{
93 snd_dmaengine_pcm_unregister(*(struct device **)res);
94}
95
96/**
97 * devm_snd_dmaengine_pcm_register - resource managed dmaengine PCM registration
98 * @dev: The parent device for the PCM device
99 * @config: Platform specific PCM configuration
100 * @flags: Platform specific quirks
101 *
102 * Register a dmaengine based PCM device with automatic unregistration when the
103 * device is unregistered.
104 */
105int devm_snd_dmaengine_pcm_register(struct device *dev,
106 const struct snd_dmaengine_pcm_config *config, unsigned int flags)
107{
108 struct device **ptr;
109 int ret;
110
111 ptr = devres_alloc(devm_dmaengine_pcm_release, sizeof(*ptr), GFP_KERNEL);
112 if (!ptr)
113 return -ENOMEM;
114
115 ret = snd_dmaengine_pcm_register(dev, config, flags);
116 if (ret == 0) {
117 *ptr = dev;
118 devres_add(dev, ptr);
119 } else {
120 devres_free(ptr);
121 }
122
123 return ret;
124}
125EXPORT_SYMBOL_GPL(devm_snd_dmaengine_pcm_register);
126
127#endif
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 41949af3baae..2a6c569d991f 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -137,6 +137,9 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
137 hw.buffer_bytes_max = SIZE_MAX; 137 hw.buffer_bytes_max = SIZE_MAX;
138 hw.fifo_size = dma_data->fifo_size; 138 hw.fifo_size = dma_data->fifo_size;
139 139
140 if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
141 hw.info |= SNDRV_PCM_INFO_BATCH;
142
140 ret = dma_get_slave_caps(chan, &dma_caps); 143 ret = dma_get_slave_caps(chan, &dma_caps);
141 if (ret == 0) { 144 if (ret == 0) {
142 if (dma_caps.cmd_pause) 145 if (dma_caps.cmd_pause)
@@ -284,25 +287,54 @@ static const char * const dmaengine_pcm_dma_channel_names[] = {
284 [SNDRV_PCM_STREAM_CAPTURE] = "rx", 287 [SNDRV_PCM_STREAM_CAPTURE] = "rx",
285}; 288};
286 289
287static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, 290static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
288 struct device *dev) 291 struct device *dev, const struct snd_dmaengine_pcm_config *config)
289{ 292{
290 unsigned int i; 293 unsigned int i;
294 const char *name;
295 struct dma_chan *chan;
291 296
292 if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | 297 if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT |
293 SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || 298 SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) ||
294 !dev->of_node) 299 !dev->of_node)
295 return; 300 return 0;
301
302 if (config && config->dma_dev) {
303 /*
304 * If this warning is seen, it probably means that your Linux
305 * device structure does not match your HW device structure.
306 * It would be best to refactor the Linux device structure to
307 * correctly match the HW structure.
308 */
309 dev_warn(dev, "DMA channels sourced from device %s",
310 dev_name(config->dma_dev));
311 dev = config->dma_dev;
312 }
296 313
297 if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) { 314 for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE;
298 pcm->chan[0] = dma_request_slave_channel(dev, "rx-tx"); 315 i++) {
299 pcm->chan[1] = pcm->chan[0]; 316 if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
300 } else { 317 name = "rx-tx";
301 for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { 318 else
302 pcm->chan[i] = dma_request_slave_channel(dev, 319 name = dmaengine_pcm_dma_channel_names[i];
303 dmaengine_pcm_dma_channel_names[i]); 320 if (config && config->chan_names[i])
321 name = config->chan_names[i];
322 chan = dma_request_slave_channel_reason(dev, name);
323 if (IS_ERR(chan)) {
324 if (PTR_ERR(chan) == -EPROBE_DEFER)
325 return -EPROBE_DEFER;
326 pcm->chan[i] = NULL;
327 } else {
328 pcm->chan[i] = chan;
304 } 329 }
330 if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
331 break;
305 } 332 }
333
334 if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
335 pcm->chan[1] = pcm->chan[0];
336
337 return 0;
306} 338}
307 339
308static void dmaengine_pcm_release_chan(struct dmaengine_pcm *pcm) 340static void dmaengine_pcm_release_chan(struct dmaengine_pcm *pcm)
@@ -338,7 +370,9 @@ int snd_dmaengine_pcm_register(struct device *dev,
338 pcm->config = config; 370 pcm->config = config;
339 pcm->flags = flags; 371 pcm->flags = flags;
340 372
341 dmaengine_pcm_request_chan_of(pcm, dev); 373 ret = dmaengine_pcm_request_chan_of(pcm, dev, config);
374 if (ret)
375 goto err_free_dma;
342 376
343 if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) 377 if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
344 ret = snd_soc_add_platform(dev, &pcm->platform, 378 ret = snd_soc_add_platform(dev, &pcm->platform,