Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Mika Westerberg and committed by
Grant Likely
51e2cc0c e791e345

+80 -63
+2 -2
sound/soc/ep93xx/ep93xx-ac97.c
··· 106 106 107 107 static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = { 108 108 .name = "ac97-pcm-out", 109 - .dma_port = EP93XX_DMA_M2P_PORT_AAC1, 109 + .dma_port = EP93XX_DMA_AAC1, 110 110 }; 111 111 112 112 static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = { 113 113 .name = "ac97-pcm-in", 114 - .dma_port = EP93XX_DMA_M2P_PORT_AAC1, 114 + .dma_port = EP93XX_DMA_AAC1, 115 115 }; 116 116 117 117 static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
+2 -2
sound/soc/ep93xx/ep93xx-i2s.c
··· 70 70 struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = { 71 71 [SNDRV_PCM_STREAM_PLAYBACK] = { 72 72 .name = "i2s-pcm-out", 73 - .dma_port = EP93XX_DMA_M2P_PORT_I2S1, 73 + .dma_port = EP93XX_DMA_I2S1, 74 74 }, 75 75 [SNDRV_PCM_STREAM_CAPTURE] = { 76 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
+76 -59
sound/soc/ep93xx/ep93xx-pcm.c
··· 16 16 #include <linux/init.h> 17 17 #include <linux/device.h> 18 18 #include <linux/slab.h> 19 + #include <linux/dmaengine.h> 19 20 #include <linux/dma-mapping.h> 20 21 21 22 #include <sound/core.h> ··· 54 53 55 54 struct ep93xx_runtime_data 56 55 { 57 - struct ep93xx_dma_m2p_client cl; 58 - struct ep93xx_pcm_dma_params *params; 59 56 int pointer_bytes; 60 - struct tasklet_struct period_tasklet; 61 57 int periods; 62 - struct ep93xx_dma_buffer buf[32]; 58 + int period_bytes; 59 + struct dma_chan *dma_chan; 60 + struct ep93xx_dma_data dma_data; 63 61 }; 64 62 65 - static void ep93xx_pcm_period_elapsed(unsigned long data) 63 + static void ep93xx_pcm_dma_callback(void *data) 66 64 { 67 - struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; 65 + struct snd_pcm_substream *substream = data; 66 + struct ep93xx_runtime_data *rtd = substream->runtime->private_data; 67 + 68 + rtd->pointer_bytes += rtd->period_bytes; 69 + rtd->pointer_bytes %= rtd->period_bytes * rtd->periods; 70 + 68 71 snd_pcm_period_elapsed(substream); 69 72 } 70 73 71 - static void ep93xx_pcm_buffer_started(void *cookie, 72 - struct ep93xx_dma_buffer *buf) 74 + static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param) 73 75 { 74 - } 76 + struct ep93xx_dma_data *data = filter_param; 75 77 76 - static void ep93xx_pcm_buffer_finished(void *cookie, 77 - struct ep93xx_dma_buffer *buf, 78 - int bytes, int error) 79 - { 80 - struct snd_pcm_substream *substream = cookie; 81 - struct ep93xx_runtime_data *rtd = substream->runtime->private_data; 82 - 83 - if (buf == rtd->buf + rtd->periods - 1) 84 - rtd->pointer_bytes = 0; 85 - else 86 - rtd->pointer_bytes += buf->size; 87 - 88 - if (!error) { 89 - ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf); 90 - tasklet_schedule(&rtd->period_tasklet); 91 - } else { 92 - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); 78 + if (data->direction == ep93xx_dma_chan_direction(chan)) { 79 + chan->private = data; 80 + return true; 93 81 } 82 + 83 + return false; 94 84 } 95 85 96 86 static int ep93xx_pcm_open(struct snd_pcm_substream *substream) ··· 90 98 struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai; 91 99 struct ep93xx_pcm_dma_params *dma_params; 92 100 struct ep93xx_runtime_data *rtd; 101 + dma_cap_mask_t mask; 93 102 int ret; 94 103 95 - dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream); 104 + ret = snd_pcm_hw_constraint_integer(substream->runtime, 105 + SNDRV_PCM_HW_PARAM_PERIODS); 106 + if (ret < 0) 107 + return ret; 108 + 96 109 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); 97 110 98 111 rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); 99 112 if (!rtd) 100 113 return -ENOMEM; 101 114 102 - memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet)); 103 - rtd->period_tasklet.func = ep93xx_pcm_period_elapsed; 104 - rtd->period_tasklet.data = (unsigned long)substream; 115 + dma_cap_zero(mask); 116 + dma_cap_set(DMA_SLAVE, mask); 117 + dma_cap_set(DMA_CYCLIC, mask); 105 118 106 - rtd->cl.name = dma_params->name; 107 - rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR | 108 - ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 109 - EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX); 110 - rtd->cl.cookie = substream; 111 - rtd->cl.buffer_started = ep93xx_pcm_buffer_started; 112 - rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished; 113 - ret = ep93xx_dma_m2p_client_register(&rtd->cl); 114 - if (ret < 0) { 119 + dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream); 120 + rtd->dma_data.port = dma_params->dma_port; 121 + rtd->dma_data.name = dma_params->name; 122 + 123 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 124 + rtd->dma_data.direction = DMA_TO_DEVICE; 125 + else 126 + rtd->dma_data.direction = DMA_FROM_DEVICE; 127 + 128 + rtd->dma_chan = dma_request_channel(mask, ep93xx_pcm_dma_filter, 129 + &rtd->dma_data); 130 + if (!rtd->dma_chan) { 115 131 kfree(rtd); 116 - return ret; 132 + return -EINVAL; 117 133 } 118 134 119 135 substream->runtime->private_data = rtd; ··· 132 132 { 133 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 136 kfree(rtd); 137 137 return 0; 138 + } 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); 138 169 } 139 170 140 171 static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream, ··· 173 142 { 174 143 struct snd_pcm_runtime *runtime = substream->runtime; 175 144 struct ep93xx_runtime_data *rtd = runtime->private_data; 176 - size_t totsize = params_buffer_bytes(params); 177 - size_t period = params_period_bytes(params); 178 - int i; 179 145 180 146 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 181 - runtime->dma_bytes = totsize; 182 147 183 - rtd->periods = (totsize + period - 1) / period; 184 - for (i = 0; i < rtd->periods; i++) { 185 - rtd->buf[i].bus_addr = runtime->dma_addr + (i * period); 186 - rtd->buf[i].size = period; 187 - if ((i + 1) * period > totsize) 188 - rtd->buf[i].size = totsize - (i * period); 189 - } 190 - 148 + rtd->periods = params_periods(params); 149 + rtd->period_bytes = params_period_bytes(params); 191 150 return 0; 192 151 } 193 152 ··· 189 168 190 169 static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 191 170 { 192 - struct ep93xx_runtime_data *rtd = substream->runtime->private_data; 193 171 int ret; 194 - int i; 195 172 196 173 ret = 0; 197 174 switch (cmd) { 198 175 case SNDRV_PCM_TRIGGER_START: 199 176 case SNDRV_PCM_TRIGGER_RESUME: 200 177 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 201 - rtd->pointer_bytes = 0; 202 - for (i = 0; i < rtd->periods; i++) 203 - ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i); 178 + ret = ep93xx_pcm_dma_submit(substream); 204 179 break; 205 180 206 181 case SNDRV_PCM_TRIGGER_STOP: 207 182 case SNDRV_PCM_TRIGGER_SUSPEND: 208 183 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 209 - ep93xx_dma_m2p_flush(&rtd->cl); 184 + ep93xx_pcm_dma_flush(substream); 210 185 break; 211 186 212 187 default: