1 // SPDX-License-Identifier: GPL-2.0-only
3 * Au12x0/Au1550 PSC ALSA ASoC audio support.
5 * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
6 * Manuel Lauss <manuel.lauss@gmail.com>
8 * DMA glue for Au1x-PSC audio.
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16 #include <linux/dma-mapping.h>
18 #include <sound/core.h>
19 #include <sound/pcm.h>
20 #include <sound/pcm_params.h>
21 #include <sound/soc.h>
23 #include <asm/mach-au1x00/au1000.h>
24 #include <asm/mach-au1x00/au1xxx_dbdma.h>
25 #include <asm/mach-au1x00/au1xxx_psc.h>
31 #define DRV_NAME "dbdma2"
33 #define MSG(x...) printk(KERN_INFO "au1xpsc_pcm: " x)
37 #define DBG(x...) do {} while (0)
40 struct au1xpsc_audio_dmadata
{
41 /* DDMA control data */
42 unsigned int ddma_id
; /* DDMA direction ID for this PSC */
43 u32 ddma_chan
; /* DDMA context */
45 /* PCM context (for irq handlers) */
46 struct snd_pcm_substream
*substream
;
47 unsigned long curr_period
; /* current segment DDMA is working on */
48 unsigned long q_period
; /* queue period(s) */
49 dma_addr_t dma_area
; /* address of queued DMA area */
50 dma_addr_t dma_area_s
; /* start address of DMA area */
51 unsigned long pos
; /* current byte position being played */
52 unsigned long periods
; /* number of SG segments in total */
53 unsigned long period_bytes
; /* size in bytes of one SG segment */
60 * These settings are somewhat okay, at least on my machine audio plays
61 * almost skip-free. Especially the 64kB buffer seems to help a LOT.
63 #define AU1XPSC_PERIOD_MIN_BYTES 1024
64 #define AU1XPSC_BUFFER_MIN_BYTES 65536
66 /* PCM hardware DMA capabilities - platform specific */
67 static const struct snd_pcm_hardware au1xpsc_pcm_hardware
= {
68 .info
= SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
69 SNDRV_PCM_INFO_INTERLEAVED
| SNDRV_PCM_INFO_BATCH
,
70 .period_bytes_min
= AU1XPSC_PERIOD_MIN_BYTES
,
71 .period_bytes_max
= 4096 * 1024 - 1,
73 .periods_max
= 4096, /* 2 to as-much-as-you-like */
74 .buffer_bytes_max
= 4096 * 1024 - 1,
75 .fifo_size
= 16, /* fifo entries of AC97/I2S PSC */
78 static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata
*cd
)
80 au1xxx_dbdma_put_source(cd
->ddma_chan
, cd
->dma_area
,
81 cd
->period_bytes
, DDMA_FLAGS_IE
);
83 /* update next-to-queue period */
85 cd
->dma_area
+= cd
->period_bytes
;
86 if (cd
->q_period
>= cd
->periods
) {
88 cd
->dma_area
= cd
->dma_area_s
;
92 static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata
*cd
)
94 au1xxx_dbdma_put_dest(cd
->ddma_chan
, cd
->dma_area
,
95 cd
->period_bytes
, DDMA_FLAGS_IE
);
97 /* update next-to-queue period */
99 cd
->dma_area
+= cd
->period_bytes
;
100 if (cd
->q_period
>= cd
->periods
) {
102 cd
->dma_area
= cd
->dma_area_s
;
106 static void au1x_pcm_dmatx_cb(int irq
, void *dev_id
)
108 struct au1xpsc_audio_dmadata
*cd
= dev_id
;
110 cd
->pos
+= cd
->period_bytes
;
111 if (++cd
->curr_period
>= cd
->periods
) {
115 snd_pcm_period_elapsed(cd
->substream
);
116 au1x_pcm_queue_tx(cd
);
119 static void au1x_pcm_dmarx_cb(int irq
, void *dev_id
)
121 struct au1xpsc_audio_dmadata
*cd
= dev_id
;
123 cd
->pos
+= cd
->period_bytes
;
124 if (++cd
->curr_period
>= cd
->periods
) {
128 snd_pcm_period_elapsed(cd
->substream
);
129 au1x_pcm_queue_rx(cd
);
132 static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata
*pcd
)
134 if (pcd
->ddma_chan
) {
135 au1xxx_dbdma_stop(pcd
->ddma_chan
);
136 au1xxx_dbdma_reset(pcd
->ddma_chan
);
137 au1xxx_dbdma_chan_free(pcd
->ddma_chan
);
143 /* in case of missing DMA ring or changed TX-source / RX-dest bit widths,
144 * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according
145 * to ALSA-supplied sample depth. This is due to limitations in the dbdma api
146 * (cannot adjust source/dest widths of already allocated descriptor ring).
148 static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata
*pcd
,
149 int stype
, int msbits
)
151 /* DMA only in 8/16/32 bit widths */
155 /* check current config: correct bits and descriptors allocated? */
156 if ((pcd
->ddma_chan
) && (msbits
== pcd
->msbits
))
157 goto out
; /* all ok! */
159 au1x_pcm_dbdma_free(pcd
);
161 if (stype
== SNDRV_PCM_STREAM_CAPTURE
)
162 pcd
->ddma_chan
= au1xxx_dbdma_chan_alloc(pcd
->ddma_id
,
164 au1x_pcm_dmarx_cb
, (void *)pcd
);
166 pcd
->ddma_chan
= au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS
,
168 au1x_pcm_dmatx_cb
, (void *)pcd
);
173 au1xxx_dbdma_set_devwidth(pcd
->ddma_chan
, msbits
);
174 au1xxx_dbdma_ring_alloc(pcd
->ddma_chan
, 2);
176 pcd
->msbits
= msbits
;
178 au1xxx_dbdma_stop(pcd
->ddma_chan
);
179 au1xxx_dbdma_reset(pcd
->ddma_chan
);
185 static inline struct au1xpsc_audio_dmadata
*to_dmadata(struct snd_pcm_substream
*ss
)
187 struct snd_soc_pcm_runtime
*rtd
= ss
->private_data
;
188 struct snd_soc_component
*component
= snd_soc_rtdcom_lookup(rtd
, DRV_NAME
);
189 struct au1xpsc_audio_dmadata
*pcd
= snd_soc_component_get_drvdata(component
);
190 return &pcd
[ss
->stream
];
193 static int au1xpsc_pcm_hw_params(struct snd_pcm_substream
*substream
,
194 struct snd_pcm_hw_params
*params
)
196 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
197 struct au1xpsc_audio_dmadata
*pcd
;
200 ret
= snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
204 stype
= substream
->stream
;
205 pcd
= to_dmadata(substream
);
207 DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %zu "
208 "runtime->min_align %lu\n",
209 (unsigned long)runtime
->dma_area
,
210 (unsigned long)runtime
->dma_addr
, runtime
->dma_bytes
,
213 DBG("bits %d frags %d frag_bytes %d is_rx %d\n", params
->msbits
,
214 params_periods(params
), params_period_bytes(params
), stype
);
216 ret
= au1x_pcm_dbdma_realloc(pcd
, stype
, params
->msbits
);
218 MSG("DDMA channel (re)alloc failed!\n");
222 pcd
->substream
= substream
;
223 pcd
->period_bytes
= params_period_bytes(params
);
224 pcd
->periods
= params_periods(params
);
225 pcd
->dma_area_s
= pcd
->dma_area
= runtime
->dma_addr
;
227 pcd
->curr_period
= 0;
235 static int au1xpsc_pcm_hw_free(struct snd_pcm_substream
*substream
)
237 snd_pcm_lib_free_pages(substream
);
241 static int au1xpsc_pcm_prepare(struct snd_pcm_substream
*substream
)
243 struct au1xpsc_audio_dmadata
*pcd
= to_dmadata(substream
);
245 au1xxx_dbdma_reset(pcd
->ddma_chan
);
247 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
) {
248 au1x_pcm_queue_rx(pcd
);
249 au1x_pcm_queue_rx(pcd
);
251 au1x_pcm_queue_tx(pcd
);
252 au1x_pcm_queue_tx(pcd
);
258 static int au1xpsc_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
260 u32 c
= to_dmadata(substream
)->ddma_chan
;
263 case SNDRV_PCM_TRIGGER_START
:
264 case SNDRV_PCM_TRIGGER_RESUME
:
265 au1xxx_dbdma_start(c
);
267 case SNDRV_PCM_TRIGGER_STOP
:
268 case SNDRV_PCM_TRIGGER_SUSPEND
:
269 au1xxx_dbdma_stop(c
);
277 static snd_pcm_uframes_t
278 au1xpsc_pcm_pointer(struct snd_pcm_substream
*substream
)
280 return bytes_to_frames(substream
->runtime
, to_dmadata(substream
)->pos
);
283 static int au1xpsc_pcm_open(struct snd_pcm_substream
*substream
)
285 struct au1xpsc_audio_dmadata
*pcd
= to_dmadata(substream
);
286 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
287 int stype
= substream
->stream
, *dmaids
;
289 dmaids
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
291 return -ENODEV
; /* whoa, has ordering changed? */
293 pcd
->ddma_id
= dmaids
[stype
];
295 snd_soc_set_runtime_hwparams(substream
, &au1xpsc_pcm_hardware
);
299 static int au1xpsc_pcm_close(struct snd_pcm_substream
*substream
)
301 au1x_pcm_dbdma_free(to_dmadata(substream
));
305 static const struct snd_pcm_ops au1xpsc_pcm_ops
= {
306 .open
= au1xpsc_pcm_open
,
307 .close
= au1xpsc_pcm_close
,
308 .ioctl
= snd_pcm_lib_ioctl
,
309 .hw_params
= au1xpsc_pcm_hw_params
,
310 .hw_free
= au1xpsc_pcm_hw_free
,
311 .prepare
= au1xpsc_pcm_prepare
,
312 .trigger
= au1xpsc_pcm_trigger
,
313 .pointer
= au1xpsc_pcm_pointer
,
316 static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime
*rtd
)
318 struct snd_card
*card
= rtd
->card
->snd_card
;
319 struct snd_pcm
*pcm
= rtd
->pcm
;
321 snd_pcm_lib_preallocate_pages_for_all(pcm
, SNDRV_DMA_TYPE_DEV
,
322 card
->dev
, AU1XPSC_BUFFER_MIN_BYTES
, (4096 * 1024) - 1);
327 /* au1xpsc audio platform */
328 static struct snd_soc_component_driver au1xpsc_soc_component
= {
330 .ops
= &au1xpsc_pcm_ops
,
331 .pcm_new
= au1xpsc_pcm_new
,
334 static int au1xpsc_pcm_drvprobe(struct platform_device
*pdev
)
336 struct au1xpsc_audio_dmadata
*dmadata
;
338 dmadata
= devm_kcalloc(&pdev
->dev
,
339 2, sizeof(struct au1xpsc_audio_dmadata
),
344 platform_set_drvdata(pdev
, dmadata
);
346 return devm_snd_soc_register_component(&pdev
->dev
,
347 &au1xpsc_soc_component
, NULL
, 0);
350 static struct platform_driver au1xpsc_pcm_driver
= {
352 .name
= "au1xpsc-pcm",
354 .probe
= au1xpsc_pcm_drvprobe
,
357 module_platform_driver(au1xpsc_pcm_driver
);
359 MODULE_LICENSE("GPL");
360 MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
361 MODULE_AUTHOR("Manuel Lauss");