2 * Au12x0/Au1550 PSC ALSA ASoC audio support.
4 * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
5 * Manuel Lauss <manuel.lauss@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * DMA glue for Au1x-PSC audio.
13 * NOTE: all of these drivers can only work with a SINGLE instance
14 * of a PSC. Multiple independent audio devices are impossible
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/platform_device.h>
22 #include <linux/slab.h>
23 #include <linux/dma-mapping.h>
25 #include <sound/core.h>
26 #include <sound/pcm.h>
27 #include <sound/pcm_params.h>
28 #include <sound/soc.h>
30 #include <asm/mach-au1x00/au1000.h>
31 #include <asm/mach-au1x00/au1xxx_dbdma.h>
32 #include <asm/mach-au1x00/au1xxx_psc.h>
38 #define MSG(x...) printk(KERN_INFO "au1xpsc_pcm: " x)
42 #define DBG(x...) do {} while (0)
45 struct au1xpsc_audio_dmadata
{
46 /* DDMA control data */
47 unsigned int ddma_id
; /* DDMA direction ID for this PSC */
48 u32 ddma_chan
; /* DDMA context */
50 /* PCM context (for irq handlers) */
51 struct snd_pcm_substream
*substream
;
52 unsigned long curr_period
; /* current segment DDMA is working on */
53 unsigned long q_period
; /* queue period(s) */
54 dma_addr_t dma_area
; /* address of queued DMA area */
55 dma_addr_t dma_area_s
; /* start address of DMA area */
56 unsigned long pos
; /* current byte position being played */
57 unsigned long periods
; /* number of SG segments in total */
58 unsigned long period_bytes
; /* size in bytes of one SG segment */
64 /* instance data. There can be only one, MacLeod!!!! */
65 static struct au1xpsc_audio_dmadata
*au1xpsc_audio_pcmdma
[2];
68 * These settings are somewhat okay, at least on my machine audio plays
69 * almost skip-free. Especially the 64kB buffer seems to help a LOT.
71 #define AU1XPSC_PERIOD_MIN_BYTES 1024
72 #define AU1XPSC_BUFFER_MIN_BYTES 65536
74 #define AU1XPSC_PCM_FMTS \
75 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
76 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
77 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
78 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \
79 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \
82 /* PCM hardware DMA capabilities - platform specific */
83 static const struct snd_pcm_hardware au1xpsc_pcm_hardware
= {
84 .info
= SNDRV_PCM_INFO_MMAP
| SNDRV_PCM_INFO_MMAP_VALID
|
85 SNDRV_PCM_INFO_INTERLEAVED
| SNDRV_PCM_INFO_BATCH
,
86 .formats
= AU1XPSC_PCM_FMTS
,
87 .period_bytes_min
= AU1XPSC_PERIOD_MIN_BYTES
,
88 .period_bytes_max
= 4096 * 1024 - 1,
90 .periods_max
= 4096, /* 2 to as-much-as-you-like */
91 .buffer_bytes_max
= 4096 * 1024 - 1,
92 .fifo_size
= 16, /* fifo entries of AC97/I2S PSC */
95 static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata
*cd
)
97 au1xxx_dbdma_put_source(cd
->ddma_chan
, cd
->dma_area
,
98 cd
->period_bytes
, DDMA_FLAGS_IE
);
100 /* update next-to-queue period */
102 cd
->dma_area
+= cd
->period_bytes
;
103 if (cd
->q_period
>= cd
->periods
) {
105 cd
->dma_area
= cd
->dma_area_s
;
109 static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata
*cd
)
111 au1xxx_dbdma_put_dest(cd
->ddma_chan
, cd
->dma_area
,
112 cd
->period_bytes
, DDMA_FLAGS_IE
);
114 /* update next-to-queue period */
116 cd
->dma_area
+= cd
->period_bytes
;
117 if (cd
->q_period
>= cd
->periods
) {
119 cd
->dma_area
= cd
->dma_area_s
;
123 static void au1x_pcm_dmatx_cb(int irq
, void *dev_id
)
125 struct au1xpsc_audio_dmadata
*cd
= dev_id
;
127 cd
->pos
+= cd
->period_bytes
;
128 if (++cd
->curr_period
>= cd
->periods
) {
132 snd_pcm_period_elapsed(cd
->substream
);
133 au1x_pcm_queue_tx(cd
);
136 static void au1x_pcm_dmarx_cb(int irq
, void *dev_id
)
138 struct au1xpsc_audio_dmadata
*cd
= dev_id
;
140 cd
->pos
+= cd
->period_bytes
;
141 if (++cd
->curr_period
>= cd
->periods
) {
145 snd_pcm_period_elapsed(cd
->substream
);
146 au1x_pcm_queue_rx(cd
);
149 static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata
*pcd
)
151 if (pcd
->ddma_chan
) {
152 au1xxx_dbdma_stop(pcd
->ddma_chan
);
153 au1xxx_dbdma_reset(pcd
->ddma_chan
);
154 au1xxx_dbdma_chan_free(pcd
->ddma_chan
);
160 /* in case of missing DMA ring or changed TX-source / RX-dest bit widths,
161 * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according
162 * to ALSA-supplied sample depth. This is due to limitations in the dbdma api
163 * (cannot adjust source/dest widths of already allocated descriptor ring).
165 static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata
*pcd
,
166 int stype
, int msbits
)
168 /* DMA only in 8/16/32 bit widths */
172 /* check current config: correct bits and descriptors allocated? */
173 if ((pcd
->ddma_chan
) && (msbits
== pcd
->msbits
))
174 goto out
; /* all ok! */
176 au1x_pcm_dbdma_free(pcd
);
179 pcd
->ddma_chan
= au1xxx_dbdma_chan_alloc(pcd
->ddma_id
,
181 au1x_pcm_dmarx_cb
, (void *)pcd
);
183 pcd
->ddma_chan
= au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS
,
185 au1x_pcm_dmatx_cb
, (void *)pcd
);
190 au1xxx_dbdma_set_devwidth(pcd
->ddma_chan
, msbits
);
191 au1xxx_dbdma_ring_alloc(pcd
->ddma_chan
, 2);
193 pcd
->msbits
= msbits
;
195 au1xxx_dbdma_stop(pcd
->ddma_chan
);
196 au1xxx_dbdma_reset(pcd
->ddma_chan
);
202 static int au1xpsc_pcm_hw_params(struct snd_pcm_substream
*substream
,
203 struct snd_pcm_hw_params
*params
)
205 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
206 struct au1xpsc_audio_dmadata
*pcd
;
209 ret
= snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
213 stype
= SUBSTREAM_TYPE(substream
);
214 pcd
= au1xpsc_audio_pcmdma
[stype
];
216 DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
217 "runtime->min_align %d\n",
218 (unsigned long)runtime
->dma_area
,
219 (unsigned long)runtime
->dma_addr
, runtime
->dma_bytes
,
222 DBG("bits %d frags %d frag_bytes %d is_rx %d\n", params
->msbits
,
223 params_periods(params
), params_period_bytes(params
), stype
);
225 ret
= au1x_pcm_dbdma_realloc(pcd
, stype
, params
->msbits
);
227 MSG("DDMA channel (re)alloc failed!\n");
231 pcd
->substream
= substream
;
232 pcd
->period_bytes
= params_period_bytes(params
);
233 pcd
->periods
= params_periods(params
);
234 pcd
->dma_area_s
= pcd
->dma_area
= runtime
->dma_addr
;
236 pcd
->curr_period
= 0;
244 static int au1xpsc_pcm_hw_free(struct snd_pcm_substream
*substream
)
246 snd_pcm_lib_free_pages(substream
);
250 static int au1xpsc_pcm_prepare(struct snd_pcm_substream
*substream
)
252 struct au1xpsc_audio_dmadata
*pcd
=
253 au1xpsc_audio_pcmdma
[SUBSTREAM_TYPE(substream
)];
255 au1xxx_dbdma_reset(pcd
->ddma_chan
);
257 if (SUBSTREAM_TYPE(substream
) == PCM_RX
) {
258 au1x_pcm_queue_rx(pcd
);
259 au1x_pcm_queue_rx(pcd
);
261 au1x_pcm_queue_tx(pcd
);
262 au1x_pcm_queue_tx(pcd
);
268 static int au1xpsc_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
270 u32 c
= au1xpsc_audio_pcmdma
[SUBSTREAM_TYPE(substream
)]->ddma_chan
;
273 case SNDRV_PCM_TRIGGER_START
:
274 case SNDRV_PCM_TRIGGER_RESUME
:
275 au1xxx_dbdma_start(c
);
277 case SNDRV_PCM_TRIGGER_STOP
:
278 case SNDRV_PCM_TRIGGER_SUSPEND
:
279 au1xxx_dbdma_stop(c
);
287 static snd_pcm_uframes_t
288 au1xpsc_pcm_pointer(struct snd_pcm_substream
*substream
)
290 return bytes_to_frames(substream
->runtime
,
291 au1xpsc_audio_pcmdma
[SUBSTREAM_TYPE(substream
)]->pos
);
294 static int au1xpsc_pcm_open(struct snd_pcm_substream
*substream
)
296 snd_soc_set_runtime_hwparams(substream
, &au1xpsc_pcm_hardware
);
300 static int au1xpsc_pcm_close(struct snd_pcm_substream
*substream
)
302 au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma
[SUBSTREAM_TYPE(substream
)]);
306 static struct snd_pcm_ops au1xpsc_pcm_ops
= {
307 .open
= au1xpsc_pcm_open
,
308 .close
= au1xpsc_pcm_close
,
309 .ioctl
= snd_pcm_lib_ioctl
,
310 .hw_params
= au1xpsc_pcm_hw_params
,
311 .hw_free
= au1xpsc_pcm_hw_free
,
312 .prepare
= au1xpsc_pcm_prepare
,
313 .trigger
= au1xpsc_pcm_trigger
,
314 .pointer
= au1xpsc_pcm_pointer
,
317 static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm
*pcm
)
319 snd_pcm_lib_preallocate_free_for_all(pcm
);
322 static int au1xpsc_pcm_new(struct snd_card
*card
,
323 struct snd_soc_dai
*dai
,
326 snd_pcm_lib_preallocate_pages_for_all(pcm
, SNDRV_DMA_TYPE_DEV
,
327 card
->dev
, AU1XPSC_BUFFER_MIN_BYTES
, (4096 * 1024) - 1);
332 static int au1xpsc_pcm_probe(struct platform_device
*pdev
)
334 if (!au1xpsc_audio_pcmdma
[PCM_TX
] || !au1xpsc_audio_pcmdma
[PCM_RX
])
340 static int au1xpsc_pcm_remove(struct platform_device
*pdev
)
345 /* au1xpsc audio platform */
346 struct snd_soc_platform au1xpsc_soc_platform
= {
347 .name
= "au1xpsc-pcm-dbdma",
348 .probe
= au1xpsc_pcm_probe
,
349 .remove
= au1xpsc_pcm_remove
,
350 .pcm_ops
= &au1xpsc_pcm_ops
,
351 .pcm_new
= au1xpsc_pcm_new
,
352 .pcm_free
= au1xpsc_pcm_free_dma_buffers
,
354 EXPORT_SYMBOL_GPL(au1xpsc_soc_platform
);
356 static int __devinit
au1xpsc_pcm_drvprobe(struct platform_device
*pdev
)
361 if (au1xpsc_audio_pcmdma
[PCM_TX
] || au1xpsc_audio_pcmdma
[PCM_RX
])
365 au1xpsc_audio_pcmdma
[PCM_TX
]
366 = kzalloc(sizeof(struct au1xpsc_audio_dmadata
), GFP_KERNEL
);
367 if (!au1xpsc_audio_pcmdma
[PCM_TX
])
370 r
= platform_get_resource(pdev
, IORESOURCE_DMA
, 0);
375 (au1xpsc_audio_pcmdma
[PCM_TX
])->ddma_id
= r
->start
;
378 au1xpsc_audio_pcmdma
[PCM_RX
]
379 = kzalloc(sizeof(struct au1xpsc_audio_dmadata
), GFP_KERNEL
);
380 if (!au1xpsc_audio_pcmdma
[PCM_RX
])
383 r
= platform_get_resource(pdev
, IORESOURCE_DMA
, 1);
388 (au1xpsc_audio_pcmdma
[PCM_RX
])->ddma_id
= r
->start
;
390 ret
= snd_soc_register_platform(&au1xpsc_soc_platform
);
395 kfree(au1xpsc_audio_pcmdma
[PCM_RX
]);
396 au1xpsc_audio_pcmdma
[PCM_RX
] = NULL
;
398 kfree(au1xpsc_audio_pcmdma
[PCM_TX
]);
399 au1xpsc_audio_pcmdma
[PCM_TX
] = NULL
;
403 static int __devexit
au1xpsc_pcm_drvremove(struct platform_device
*pdev
)
407 snd_soc_unregister_platform(&au1xpsc_soc_platform
);
409 for (i
= 0; i
< 2; i
++) {
410 if (au1xpsc_audio_pcmdma
[i
]) {
411 au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma
[i
]);
412 kfree(au1xpsc_audio_pcmdma
[i
]);
413 au1xpsc_audio_pcmdma
[i
] = NULL
;
420 static struct platform_driver au1xpsc_pcm_driver
= {
422 .name
= "au1xpsc-pcm",
423 .owner
= THIS_MODULE
,
425 .probe
= au1xpsc_pcm_drvprobe
,
426 .remove
= __devexit_p(au1xpsc_pcm_drvremove
),
429 static int __init
au1xpsc_audio_dbdma_load(void)
431 au1xpsc_audio_pcmdma
[PCM_TX
] = NULL
;
432 au1xpsc_audio_pcmdma
[PCM_RX
] = NULL
;
433 return platform_driver_register(&au1xpsc_pcm_driver
);
436 static void __exit
au1xpsc_audio_dbdma_unload(void)
438 platform_driver_unregister(&au1xpsc_pcm_driver
);
441 module_init(au1xpsc_audio_dbdma_load
);
442 module_exit(au1xpsc_audio_dbdma_unload
);
445 struct platform_device
*au1xpsc_pcm_add(struct platform_device
*pdev
)
447 struct resource
*res
, *r
;
448 struct platform_device
*pd
;
452 r
= platform_get_resource(pdev
, IORESOURCE_DMA
, 0);
457 r
= platform_get_resource(pdev
, IORESOURCE_DMA
, 1);
462 res
= kzalloc(sizeof(struct resource
) * 2, GFP_KERNEL
);
466 res
[0].start
= res
[0].end
= id
[0];
467 res
[1].start
= res
[1].end
= id
[1];
468 res
[0].flags
= res
[1].flags
= IORESOURCE_DMA
;
470 pd
= platform_device_alloc("au1xpsc-pcm", -1);
475 pd
->num_resources
= 2;
477 ret
= platform_device_add(pd
);
481 platform_device_put(pd
);
486 EXPORT_SYMBOL_GPL(au1xpsc_pcm_add
);
488 void au1xpsc_pcm_destroy(struct platform_device
*dmapd
)
491 platform_device_unregister(dmapd
);
493 EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy
);
495 MODULE_LICENSE("GPL");
496 MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
497 MODULE_AUTHOR("Manuel Lauss");