diff options
author | Mika Westerberg <mika.westerberg@iki.fi> | 2011-05-29 06:10:04 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-06-08 17:45:59 -0400 |
commit | 51e2cc0c51298a89fc2f583d7c0a2660f7a16f37 (patch) | |
tree | 495367c20f19ac8e78b5ef6b545328f827b9927f /sound/soc/ep93xx | |
parent | e791e3455f1b7e92f0b66f460ade9c7a2299ac7e (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.c | 4 | ||||
-rw-r--r-- | sound/soc/ep93xx/ep93xx-i2s.c | 4 | ||||
-rw-r--r-- | sound/soc/ep93xx/ep93xx-pcm.c | 137 |
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 | ||
107 | static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = { | 107 | static 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 | ||
112 | static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = { | 112 | static 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 | ||
117 | static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info, | 117 | static 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 { | |||
70 | struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = { | 70 | struct 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 | ||
54 | struct ep93xx_runtime_data | 55 | struct 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 | ||
64 | static void ep93xx_pcm_period_elapsed(unsigned long data) | 64 | static 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 | ||
70 | static 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 | ||
75 | static void ep93xx_pcm_buffer_finished(void *cookie, | 75 | static 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 | ||
95 | static int ep93xx_pcm_open(struct snd_pcm_substream *substream) | 87 | static 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 | ||
140 | static 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 | |||
163 | static 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 | |||
140 | static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream, | 171 | static 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 | ||
169 | static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 190 | static 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: |