1 // SPDX-License-Identifier: GPL-2.0-only
3 * Au1000/Au1500/Au1100 Audio DMA support.
5 * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
7 * copied almost verbatim from the old ALSA driver, written by
8 * Charles Eidsness <charles@cooper-street.com>
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
15 #include <linux/dma-mapping.h>
16 #include <sound/core.h>
17 #include <sound/pcm.h>
18 #include <sound/pcm_params.h>
19 #include <sound/soc.h>
20 #include <asm/mach-au1x00/au1000.h>
21 #include <asm/mach-au1x00/au1000_dma.h>
25 #define DRV_NAME "au1x_dma"
29 u32 relative_end
; /* relative to start of buffer */
30 struct pcm_period
*next
;
34 struct snd_pcm_substream
*substream
;
36 struct pcm_period
*buffer
;
37 unsigned int period_size
;
41 struct alchemy_pcm_ctx
{
42 struct audio_stream stream
[2]; /* playback & capture */
45 static void au1000_release_dma_link(struct audio_stream
*stream
)
47 struct pcm_period
*pointer
;
48 struct pcm_period
*pointer_next
;
50 stream
->period_size
= 0;
52 pointer
= stream
->buffer
;
56 pointer_next
= pointer
->next
;
58 pointer
= pointer_next
;
59 } while (pointer
!= stream
->buffer
);
60 stream
->buffer
= NULL
;
63 static int au1000_setup_dma_link(struct audio_stream
*stream
,
64 unsigned int period_bytes
,
67 struct snd_pcm_substream
*substream
= stream
->substream
;
68 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
69 struct pcm_period
*pointer
;
70 unsigned long dma_start
;
73 dma_start
= virt_to_phys(runtime
->dma_area
);
75 if (stream
->period_size
== period_bytes
&&
76 stream
->periods
== periods
)
77 return 0; /* not changed */
79 au1000_release_dma_link(stream
);
81 stream
->period_size
= period_bytes
;
82 stream
->periods
= periods
;
84 stream
->buffer
= kmalloc(sizeof(struct pcm_period
), GFP_KERNEL
);
87 pointer
= stream
->buffer
;
88 for (i
= 0; i
< periods
; i
++) {
89 pointer
->start
= (u32
)(dma_start
+ (i
* period_bytes
));
90 pointer
->relative_end
= (u32
) (((i
+1) * period_bytes
) - 0x1);
91 if (i
< periods
- 1) {
92 pointer
->next
= kmalloc(sizeof(struct pcm_period
),
95 au1000_release_dma_link(stream
);
98 pointer
= pointer
->next
;
101 pointer
->next
= stream
->buffer
;
105 static void au1000_dma_stop(struct audio_stream
*stream
)
108 disable_dma(stream
->dma
);
111 static void au1000_dma_start(struct audio_stream
*stream
)
116 init_dma(stream
->dma
);
117 if (get_dma_active_buffer(stream
->dma
) == 0) {
118 clear_dma_done0(stream
->dma
);
119 set_dma_addr0(stream
->dma
, stream
->buffer
->start
);
120 set_dma_count0(stream
->dma
, stream
->period_size
>> 1);
121 set_dma_addr1(stream
->dma
, stream
->buffer
->next
->start
);
122 set_dma_count1(stream
->dma
, stream
->period_size
>> 1);
124 clear_dma_done1(stream
->dma
);
125 set_dma_addr1(stream
->dma
, stream
->buffer
->start
);
126 set_dma_count1(stream
->dma
, stream
->period_size
>> 1);
127 set_dma_addr0(stream
->dma
, stream
->buffer
->next
->start
);
128 set_dma_count0(stream
->dma
, stream
->period_size
>> 1);
130 enable_dma_buffers(stream
->dma
);
131 start_dma(stream
->dma
);
134 static irqreturn_t
au1000_dma_interrupt(int irq
, void *ptr
)
136 struct audio_stream
*stream
= (struct audio_stream
*)ptr
;
137 struct snd_pcm_substream
*substream
= stream
->substream
;
139 switch (get_dma_buffer_done(stream
->dma
)) {
141 stream
->buffer
= stream
->buffer
->next
;
142 clear_dma_done0(stream
->dma
);
143 set_dma_addr0(stream
->dma
, stream
->buffer
->next
->start
);
144 set_dma_count0(stream
->dma
, stream
->period_size
>> 1);
145 enable_dma_buffer0(stream
->dma
);
148 stream
->buffer
= stream
->buffer
->next
;
149 clear_dma_done1(stream
->dma
);
150 set_dma_addr1(stream
->dma
, stream
->buffer
->next
->start
);
151 set_dma_count1(stream
->dma
, stream
->period_size
>> 1);
152 enable_dma_buffer1(stream
->dma
);
154 case (DMA_D0
| DMA_D1
):
155 pr_debug("DMA %d missed interrupt.\n", stream
->dma
);
156 au1000_dma_stop(stream
);
157 au1000_dma_start(stream
);
159 case (~DMA_D0
& ~DMA_D1
):
160 pr_debug("DMA %d empty irq.\n", stream
->dma
);
162 snd_pcm_period_elapsed(substream
);
166 static const struct snd_pcm_hardware alchemy_pcm_hardware
= {
167 .info
= SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
168 SNDRV_PCM_INFO_INTERLEAVED
| SNDRV_PCM_INFO_BATCH
,
169 .period_bytes_min
= 1024,
170 .period_bytes_max
= 16 * 1024 - 1,
173 .buffer_bytes_max
= 128 * 1024,
177 static inline struct alchemy_pcm_ctx
*ss_to_ctx(struct snd_pcm_substream
*ss
,
178 struct snd_soc_component
*component
)
180 return snd_soc_component_get_drvdata(component
);
183 static inline struct audio_stream
*ss_to_as(struct snd_pcm_substream
*ss
,
184 struct snd_soc_component
*component
)
186 struct alchemy_pcm_ctx
*ctx
= ss_to_ctx(ss
, component
);
187 return &(ctx
->stream
[ss
->stream
]);
190 static int alchemy_pcm_open(struct snd_soc_component
*component
,
191 struct snd_pcm_substream
*substream
)
193 struct alchemy_pcm_ctx
*ctx
= ss_to_ctx(substream
, component
);
194 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
195 int *dmaids
, s
= substream
->stream
;
198 dmaids
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
200 return -ENODEV
; /* whoa, has ordering changed? */
203 name
= (s
== SNDRV_PCM_STREAM_PLAYBACK
) ? "audio-tx" : "audio-rx";
204 ctx
->stream
[s
].dma
= request_au1000_dma(dmaids
[s
], name
,
205 au1000_dma_interrupt
, 0,
207 set_dma_mode(ctx
->stream
[s
].dma
,
208 get_dma_mode(ctx
->stream
[s
].dma
) & ~DMA_NC
);
210 ctx
->stream
[s
].substream
= substream
;
211 ctx
->stream
[s
].buffer
= NULL
;
212 snd_soc_set_runtime_hwparams(substream
, &alchemy_pcm_hardware
);
217 static int alchemy_pcm_close(struct snd_soc_component
*component
,
218 struct snd_pcm_substream
*substream
)
220 struct alchemy_pcm_ctx
*ctx
= ss_to_ctx(substream
, component
);
221 int stype
= substream
->stream
;
223 ctx
->stream
[stype
].substream
= NULL
;
224 free_au1000_dma(ctx
->stream
[stype
].dma
);
229 static int alchemy_pcm_hw_params(struct snd_soc_component
*component
,
230 struct snd_pcm_substream
*substream
,
231 struct snd_pcm_hw_params
*hw_params
)
233 struct audio_stream
*stream
= ss_to_as(substream
, component
);
236 err
= snd_pcm_lib_malloc_pages(substream
,
237 params_buffer_bytes(hw_params
));
240 err
= au1000_setup_dma_link(stream
,
241 params_period_bytes(hw_params
),
242 params_periods(hw_params
));
244 snd_pcm_lib_free_pages(substream
);
249 static int alchemy_pcm_hw_free(struct snd_soc_component
*component
,
250 struct snd_pcm_substream
*substream
)
252 struct audio_stream
*stream
= ss_to_as(substream
, component
);
253 au1000_release_dma_link(stream
);
254 return snd_pcm_lib_free_pages(substream
);
257 static int alchemy_pcm_trigger(struct snd_soc_component
*component
,
258 struct snd_pcm_substream
*substream
, int cmd
)
260 struct audio_stream
*stream
= ss_to_as(substream
, component
);
264 case SNDRV_PCM_TRIGGER_START
:
265 au1000_dma_start(stream
);
267 case SNDRV_PCM_TRIGGER_STOP
:
268 au1000_dma_stop(stream
);
277 static snd_pcm_uframes_t
alchemy_pcm_pointer(struct snd_soc_component
*component
,
278 struct snd_pcm_substream
*ss
)
280 struct audio_stream
*stream
= ss_to_as(ss
, component
);
283 location
= get_dma_residue(stream
->dma
);
284 location
= stream
->buffer
->relative_end
- location
;
287 return bytes_to_frames(ss
->runtime
, location
);
290 static int alchemy_pcm_new(struct snd_soc_component
*component
,
291 struct snd_soc_pcm_runtime
*rtd
)
293 struct snd_pcm
*pcm
= rtd
->pcm
;
295 snd_pcm_lib_preallocate_pages_for_all(pcm
, SNDRV_DMA_TYPE_CONTINUOUS
,
296 NULL
, 65536, (4096 * 1024) - 1);
301 static struct snd_soc_component_driver alchemy_pcm_soc_component
= {
303 .open
= alchemy_pcm_open
,
304 .close
= alchemy_pcm_close
,
305 .ioctl
= snd_soc_pcm_lib_ioctl
,
306 .hw_params
= alchemy_pcm_hw_params
,
307 .hw_free
= alchemy_pcm_hw_free
,
308 .trigger
= alchemy_pcm_trigger
,
309 .pointer
= alchemy_pcm_pointer
,
310 .pcm_construct
= alchemy_pcm_new
,
313 static int alchemy_pcm_drvprobe(struct platform_device
*pdev
)
315 struct alchemy_pcm_ctx
*ctx
;
317 ctx
= devm_kzalloc(&pdev
->dev
, sizeof(*ctx
), GFP_KERNEL
);
321 platform_set_drvdata(pdev
, ctx
);
323 return devm_snd_soc_register_component(&pdev
->dev
,
324 &alchemy_pcm_soc_component
, NULL
, 0);
327 static struct platform_driver alchemy_pcmdma_driver
= {
329 .name
= "alchemy-pcm-dma",
331 .probe
= alchemy_pcm_drvprobe
,
334 module_platform_driver(alchemy_pcmdma_driver
);
336 MODULE_LICENSE("GPL");
337 MODULE_DESCRIPTION("Au1000/Au1500/Au1100 Audio DMA driver");
338 MODULE_AUTHOR("Manuel Lauss");