diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2013-10-08 09:07:59 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-10-19 16:26:06 -0400 |
commit | c0de42bf595238e9dd593405ebc2992cc8470732 (patch) | |
tree | 310c4d89773307ce86f6df8f377c3e56f423bc38 | |
parent | 61e6cfa80de5760bbe406f4e815b7739205754d2 (diff) |
ASoC: dmaengine-pcm: Add support for querying DMA capabilities
Currently each platform making use the the generic dmaengine PCM driver still
needs to provide a custom snd_pcm_hardware struct which specifies the
capabilities of the DMA controller, e.g. the maximum period size that can be
supported. This patch adds code which uses the newly introduced
dma_get_slave_caps() API to query this information from the dmaengine driver.
The new code path will only be taken if the 'pcm_hardware' field of the
snd_dmaengine_pcm_config struct is NULL.
The patch also introduces a new 'fifo_size' field to the
snd_dmaengine_dai_dma_data struct which is used to initialize the
snd_pcm_hardware 'fifo_size' field and needs to be set by the DAI driver.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r-- | include/sound/dmaengine_pcm.h | 2 | ||||
-rw-r--r-- | sound/soc/soc-generic-dmaengine-pcm.c | 55 |
2 files changed, 47 insertions, 10 deletions
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index f11c35cd5532..83b2c3e95a1a 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h | |||
@@ -61,6 +61,7 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) | |||
61 | * @slave_id: Slave requester id for the DMA channel. | 61 | * @slave_id: Slave requester id for the DMA channel. |
62 | * @filter_data: Custom DMA channel filter data, this will usually be used when | 62 | * @filter_data: Custom DMA channel filter data, this will usually be used when |
63 | * requesting the DMA channel. | 63 | * requesting the DMA channel. |
64 | * @fifo_size: FIFO size of the DAI controller in bytes | ||
64 | */ | 65 | */ |
65 | struct snd_dmaengine_dai_dma_data { | 66 | struct snd_dmaengine_dai_dma_data { |
66 | dma_addr_t addr; | 67 | dma_addr_t addr; |
@@ -68,6 +69,7 @@ struct snd_dmaengine_dai_dma_data { | |||
68 | u32 maxburst; | 69 | u32 maxburst; |
69 | unsigned int slave_id; | 70 | unsigned int slave_id; |
70 | void *filter_data; | 71 | void *filter_data; |
72 | unsigned int fifo_size; | ||
71 | }; | 73 | }; |
72 | 74 | ||
73 | void snd_dmaengine_pcm_set_config_from_dai_data( | 75 | void snd_dmaengine_pcm_set_config_from_dai_data( |
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index e29ec3cd84b1..c39e19e84c8a 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c | |||
@@ -36,6 +36,15 @@ static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p) | |||
36 | return container_of(p, struct dmaengine_pcm, platform); | 36 | return container_of(p, struct dmaengine_pcm, platform); |
37 | } | 37 | } |
38 | 38 | ||
39 | static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, | ||
40 | struct snd_pcm_substream *substream) | ||
41 | { | ||
42 | if (!pcm->chan[substream->stream]) | ||
43 | return NULL; | ||
44 | |||
45 | return pcm->chan[substream->stream]->device->dev; | ||
46 | } | ||
47 | |||
39 | /** | 48 | /** |
40 | * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback | 49 | * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback |
41 | * @substream: PCM substream | 50 | * @substream: PCM substream |
@@ -92,28 +101,54 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream, | |||
92 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | 101 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); |
93 | } | 102 | } |
94 | 103 | ||
95 | static int dmaengine_pcm_open(struct snd_pcm_substream *substream) | 104 | static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substream) |
96 | { | 105 | { |
97 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 106 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
98 | struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); | 107 | struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); |
108 | struct device *dma_dev = dmaengine_dma_dev(pcm, substream); | ||
99 | struct dma_chan *chan = pcm->chan[substream->stream]; | 109 | struct dma_chan *chan = pcm->chan[substream->stream]; |
110 | struct snd_dmaengine_dai_dma_data *dma_data; | ||
111 | struct dma_slave_caps dma_caps; | ||
112 | struct snd_pcm_hardware hw; | ||
100 | int ret; | 113 | int ret; |
101 | 114 | ||
102 | ret = snd_soc_set_runtime_hwparams(substream, | 115 | if (pcm->config->pcm_hardware) |
116 | return snd_soc_set_runtime_hwparams(substream, | ||
103 | pcm->config->pcm_hardware); | 117 | pcm->config->pcm_hardware); |
104 | if (ret) | ||
105 | return ret; | ||
106 | 118 | ||
107 | return snd_dmaengine_pcm_open(substream, chan); | 119 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); |
120 | |||
121 | memset(&hw, 0, sizeof(hw)); | ||
122 | hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | ||
123 | SNDRV_PCM_INFO_INTERLEAVED; | ||
124 | hw.periods_min = 2; | ||
125 | hw.periods_max = UINT_MAX; | ||
126 | hw.period_bytes_min = 256; | ||
127 | hw.period_bytes_max = dma_get_max_seg_size(dma_dev); | ||
128 | hw.buffer_bytes_max = SIZE_MAX; | ||
129 | hw.fifo_size = dma_data->fifo_size; | ||
130 | |||
131 | ret = dma_get_slave_caps(chan, &dma_caps); | ||
132 | if (ret == 0) { | ||
133 | if (dma_caps.cmd_pause) | ||
134 | hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; | ||
135 | } | ||
136 | |||
137 | return snd_soc_set_runtime_hwparams(substream, &hw); | ||
108 | } | 138 | } |
109 | 139 | ||
110 | static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, | 140 | static int dmaengine_pcm_open(struct snd_pcm_substream *substream) |
111 | struct snd_pcm_substream *substream) | ||
112 | { | 141 | { |
113 | if (!pcm->chan[substream->stream]) | 142 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
114 | return NULL; | 143 | struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); |
144 | struct dma_chan *chan = pcm->chan[substream->stream]; | ||
145 | int ret; | ||
115 | 146 | ||
116 | return pcm->chan[substream->stream]->device->dev; | 147 | ret = dmaengine_pcm_set_runtime_hwparams(substream); |
148 | if (ret) | ||
149 | return ret; | ||
150 | |||
151 | return snd_dmaengine_pcm_open(substream, chan); | ||
117 | } | 152 | } |
118 | 153 | ||
119 | static void dmaengine_pcm_free(struct snd_pcm *pcm) | 154 | static void dmaengine_pcm_free(struct snd_pcm *pcm) |