aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/ep93xx
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@iki.fi>2011-05-29 06:10:04 -0400
committerGrant Likely <grant.likely@secretlab.ca>2011-06-08 17:45:59 -0400
commit51e2cc0c51298a89fc2f583d7c0a2660f7a16f37 (patch)
tree495367c20f19ac8e78b5ef6b545328f827b9927f /sound/soc/ep93xx
parente791e3455f1b7e92f0b66f460ade9c7a2299ac7e (diff)
ASoC: ep93xx: convert to use the DMA engine API
Now that we have the EP93xx DMA engine driver in place, we convert the ASoC drivers (I2S, AC97 and PCM) to take advantage of this new API. There are no functional changes. Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi> Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com> Acked-by: Liam Girdwood <lrg@ti.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'sound/soc/ep93xx')
-rw-r--r--sound/soc/ep93xx/ep93xx-ac97.c4
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.c4
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.c137
3 files changed, 81 insertions, 64 deletions
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
index 104e95cda0ad..c7417c76552b 100644
--- a/sound/soc/ep93xx/ep93xx-ac97.c
+++ b/sound/soc/ep93xx/ep93xx-ac97.c
@@ -106,12 +106,12 @@ static struct ep93xx_ac97_info *ep93xx_ac97_info;
106 106
107static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = { 107static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
108 .name = "ac97-pcm-out", 108 .name = "ac97-pcm-out",
109 .dma_port = EP93XX_DMA_M2P_PORT_AAC1, 109 .dma_port = EP93XX_DMA_AAC1,
110}; 110};
111 111
112static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = { 112static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
113 .name = "ac97-pcm-in", 113 .name = "ac97-pcm-in",
114 .dma_port = EP93XX_DMA_M2P_PORT_AAC1, 114 .dma_port = EP93XX_DMA_AAC1,
115}; 115};
116 116
117static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info, 117static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index 042f4e93746f..30df42568dbb 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -70,11 +70,11 @@ struct ep93xx_i2s_info {
70struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = { 70struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
71 [SNDRV_PCM_STREAM_PLAYBACK] = { 71 [SNDRV_PCM_STREAM_PLAYBACK] = {
72 .name = "i2s-pcm-out", 72 .name = "i2s-pcm-out",
73 .dma_port = EP93XX_DMA_M2P_PORT_I2S1, 73 .dma_port = EP93XX_DMA_I2S1,
74 }, 74 },
75 [SNDRV_PCM_STREAM_CAPTURE] = { 75 [SNDRV_PCM_STREAM_CAPTURE] = {
76 .name = "i2s-pcm-in", 76 .name = "i2s-pcm-in",
77 .dma_port = EP93XX_DMA_M2P_PORT_I2S1, 77 .dma_port = EP93XX_DMA_I2S1,
78 }, 78 },
79}; 79};
80 80
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
index a456e491155f..a07f99c9c375 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.c
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -16,6 +16,7 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/device.h> 17#include <linux/device.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/dmaengine.h>
19#include <linux/dma-mapping.h> 20#include <linux/dma-mapping.h>
20 21
21#include <sound/core.h> 22#include <sound/core.h>
@@ -53,43 +54,34 @@ static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
53 54
54struct ep93xx_runtime_data 55struct ep93xx_runtime_data
55{ 56{
56 struct ep93xx_dma_m2p_client cl;
57 struct ep93xx_pcm_dma_params *params;
58 int pointer_bytes; 57 int pointer_bytes;
59 struct tasklet_struct period_tasklet;
60 int periods; 58 int periods;
61 struct ep93xx_dma_buffer buf[32]; 59 int period_bytes;
60 struct dma_chan *dma_chan;
61 struct ep93xx_dma_data dma_data;
62}; 62};
63 63
64static void ep93xx_pcm_period_elapsed(unsigned long data) 64static void ep93xx_pcm_dma_callback(void *data)
65{ 65{
66 struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; 66 struct snd_pcm_substream *substream = data;
67 snd_pcm_period_elapsed(substream); 67 struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
68}
69 68
70static void ep93xx_pcm_buffer_started(void *cookie, 69 rtd->pointer_bytes += rtd->period_bytes;
71 struct ep93xx_dma_buffer *buf) 70 rtd->pointer_bytes %= rtd->period_bytes * rtd->periods;
72{ 71
72 snd_pcm_period_elapsed(substream);
73} 73}
74 74
75static void ep93xx_pcm_buffer_finished(void *cookie, 75static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
76 struct ep93xx_dma_buffer *buf,
77 int bytes, int error)
78{ 76{
79 struct snd_pcm_substream *substream = cookie; 77 struct ep93xx_dma_data *data = filter_param;
80 struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
81
82 if (buf == rtd->buf + rtd->periods - 1)
83 rtd->pointer_bytes = 0;
84 else
85 rtd->pointer_bytes += buf->size;
86 78
87 if (!error) { 79 if (data->direction == ep93xx_dma_chan_direction(chan)) {
88 ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf); 80 chan->private = data;
89 tasklet_schedule(&rtd->period_tasklet); 81 return true;
90 } else {
91 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
92 } 82 }
83
84 return false;
93} 85}
94 86
95static int ep93xx_pcm_open(struct snd_pcm_substream *substream) 87static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
@@ -98,30 +90,38 @@ static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
98 struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai; 90 struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
99 struct ep93xx_pcm_dma_params *dma_params; 91 struct ep93xx_pcm_dma_params *dma_params;
100 struct ep93xx_runtime_data *rtd; 92 struct ep93xx_runtime_data *rtd;
93 dma_cap_mask_t mask;
101 int ret; 94 int ret;
102 95
103 dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream); 96 ret = snd_pcm_hw_constraint_integer(substream->runtime,
97 SNDRV_PCM_HW_PARAM_PERIODS);
98 if (ret < 0)
99 return ret;
100
104 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); 101 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
105 102
106 rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); 103 rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
107 if (!rtd) 104 if (!rtd)
108 return -ENOMEM; 105 return -ENOMEM;
109 106
110 memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet)); 107 dma_cap_zero(mask);
111 rtd->period_tasklet.func = ep93xx_pcm_period_elapsed; 108 dma_cap_set(DMA_SLAVE, mask);
112 rtd->period_tasklet.data = (unsigned long)substream; 109 dma_cap_set(DMA_CYCLIC, mask);
113 110
114 rtd->cl.name = dma_params->name; 111 dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
115 rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR | 112 rtd->dma_data.port = dma_params->dma_port;
116 ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 113 rtd->dma_data.name = dma_params->name;
117 EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX); 114
118 rtd->cl.cookie = substream; 115 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
119 rtd->cl.buffer_started = ep93xx_pcm_buffer_started; 116 rtd->dma_data.direction = DMA_TO_DEVICE;
120 rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished; 117 else
121 ret = ep93xx_dma_m2p_client_register(&rtd->cl); 118 rtd->dma_data.direction = DMA_FROM_DEVICE;
122 if (ret < 0) { 119
120 rtd->dma_chan = dma_request_channel(mask, ep93xx_pcm_dma_filter,
121 &rtd->dma_data);
122 if (!rtd->dma_chan) {
123 kfree(rtd); 123 kfree(rtd);
124 return ret; 124 return -EINVAL;
125 } 125 }
126 126
127 substream->runtime->private_data = rtd; 127 substream->runtime->private_data = rtd;
@@ -132,31 +132,52 @@ static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
132{ 132{
133 struct ep93xx_runtime_data *rtd = substream->runtime->private_data; 133 struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
134 134
135 ep93xx_dma_m2p_client_unregister(&rtd->cl); 135 dma_release_channel(rtd->dma_chan);
136 kfree(rtd); 136 kfree(rtd);
137 return 0; 137 return 0;
138} 138}
139 139
140static int ep93xx_pcm_dma_submit(struct snd_pcm_substream *substream)
141{
142 struct snd_pcm_runtime *runtime = substream->runtime;
143 struct ep93xx_runtime_data *rtd = runtime->private_data;
144 struct dma_chan *chan = rtd->dma_chan;
145 struct dma_device *dma_dev = chan->device;
146 struct dma_async_tx_descriptor *desc;
147
148 rtd->pointer_bytes = 0;
149 desc = dma_dev->device_prep_dma_cyclic(chan, runtime->dma_addr,
150 rtd->period_bytes * rtd->periods,
151 rtd->period_bytes,
152 rtd->dma_data.direction);
153 if (!desc)
154 return -EINVAL;
155
156 desc->callback = ep93xx_pcm_dma_callback;
157 desc->callback_param = substream;
158
159 dmaengine_submit(desc);
160 return 0;
161}
162
163static void ep93xx_pcm_dma_flush(struct snd_pcm_substream *substream)
164{
165 struct snd_pcm_runtime *runtime = substream->runtime;
166 struct ep93xx_runtime_data *rtd = runtime->private_data;
167
168 dmaengine_terminate_all(rtd->dma_chan);
169}
170
140static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream, 171static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
141 struct snd_pcm_hw_params *params) 172 struct snd_pcm_hw_params *params)
142{ 173{
143 struct snd_pcm_runtime *runtime = substream->runtime; 174 struct snd_pcm_runtime *runtime = substream->runtime;
144 struct ep93xx_runtime_data *rtd = runtime->private_data; 175 struct ep93xx_runtime_data *rtd = runtime->private_data;
145 size_t totsize = params_buffer_bytes(params);
146 size_t period = params_period_bytes(params);
147 int i;
148 176
149 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 177 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
150 runtime->dma_bytes = totsize;
151
152 rtd->periods = (totsize + period - 1) / period;
153 for (i = 0; i < rtd->periods; i++) {
154 rtd->buf[i].bus_addr = runtime->dma_addr + (i * period);
155 rtd->buf[i].size = period;
156 if ((i + 1) * period > totsize)
157 rtd->buf[i].size = totsize - (i * period);
158 }
159 178
179 rtd->periods = params_periods(params);
180 rtd->period_bytes = params_period_bytes(params);
160 return 0; 181 return 0;
161} 182}
162 183
@@ -168,24 +189,20 @@ static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
168 189
169static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 190static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
170{ 191{
171 struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
172 int ret; 192 int ret;
173 int i;
174 193
175 ret = 0; 194 ret = 0;
176 switch (cmd) { 195 switch (cmd) {
177 case SNDRV_PCM_TRIGGER_START: 196 case SNDRV_PCM_TRIGGER_START:
178 case SNDRV_PCM_TRIGGER_RESUME: 197 case SNDRV_PCM_TRIGGER_RESUME:
179 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 198 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
180 rtd->pointer_bytes = 0; 199 ret = ep93xx_pcm_dma_submit(substream);
181 for (i = 0; i < rtd->periods; i++)
182 ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i);
183 break; 200 break;
184 201
185 case SNDRV_PCM_TRIGGER_STOP: 202 case SNDRV_PCM_TRIGGER_STOP:
186 case SNDRV_PCM_TRIGGER_SUSPEND: 203 case SNDRV_PCM_TRIGGER_SUSPEND:
187 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 204 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
188 ep93xx_dma_m2p_flush(&rtd->cl); 205 ep93xx_pcm_dma_flush(substream);
189 break; 206 break;
190 207
191 default: 208 default: