1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24a161d23SManuel Lauss /*
34a161d23SManuel Lauss * Au12x0/Au1550 PSC ALSA ASoC audio support.
44a161d23SManuel Lauss *
54a161d23SManuel Lauss * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
60f83d639SManuel Lauss * Manuel Lauss <manuel.lauss@gmail.com>
74a161d23SManuel Lauss *
84a161d23SManuel Lauss * DMA glue for Au1x-PSC audio.
94a161d23SManuel Lauss */
104a161d23SManuel Lauss
114a161d23SManuel Lauss
124a161d23SManuel Lauss #include <linux/module.h>
134a161d23SManuel Lauss #include <linux/init.h>
144a161d23SManuel Lauss #include <linux/platform_device.h>
154a161d23SManuel Lauss #include <linux/slab.h>
164a161d23SManuel Lauss #include <linux/dma-mapping.h>
174a161d23SManuel Lauss
184a161d23SManuel Lauss #include <sound/core.h>
194a161d23SManuel Lauss #include <sound/pcm.h>
204a161d23SManuel Lauss #include <sound/pcm_params.h>
214a161d23SManuel Lauss #include <sound/soc.h>
224a161d23SManuel Lauss
234a161d23SManuel Lauss #include <asm/mach-au1x00/au1000.h>
244a161d23SManuel Lauss #include <asm/mach-au1x00/au1xxx_dbdma.h>
254a161d23SManuel Lauss #include <asm/mach-au1x00/au1xxx_psc.h>
264a161d23SManuel Lauss
274a161d23SManuel Lauss #include "psc.h"
284a161d23SManuel Lauss
294a161d23SManuel Lauss /*#define PCM_DEBUG*/
304a161d23SManuel Lauss
31abf33c7aSKuninori Morimoto #define DRV_NAME "dbdma2"
32abf33c7aSKuninori Morimoto
334a161d23SManuel Lauss #define MSG(x...) printk(KERN_INFO "au1xpsc_pcm: " x)
344a161d23SManuel Lauss #ifdef PCM_DEBUG
354a161d23SManuel Lauss #define DBG MSG
364a161d23SManuel Lauss #else
374a161d23SManuel Lauss #define DBG(x...) do {} while (0)
384a161d23SManuel Lauss #endif
394a161d23SManuel Lauss
404a161d23SManuel Lauss struct au1xpsc_audio_dmadata {
414a161d23SManuel Lauss /* DDMA control data */
424a161d23SManuel Lauss unsigned int ddma_id; /* DDMA direction ID for this PSC */
434a161d23SManuel Lauss u32 ddma_chan; /* DDMA context */
444a161d23SManuel Lauss
454a161d23SManuel Lauss /* PCM context (for irq handlers) */
464a161d23SManuel Lauss struct snd_pcm_substream *substream;
474a161d23SManuel Lauss unsigned long curr_period; /* current segment DDMA is working on */
484a161d23SManuel Lauss unsigned long q_period; /* queue period(s) */
49963accbcSManuel Lauss dma_addr_t dma_area; /* address of queued DMA area */
50963accbcSManuel Lauss dma_addr_t dma_area_s; /* start address of DMA area */
514a161d23SManuel Lauss unsigned long pos; /* current byte position being played */
524a161d23SManuel Lauss unsigned long periods; /* number of SG segments in total */
534a161d23SManuel Lauss unsigned long period_bytes; /* size in bytes of one SG segment */
544a161d23SManuel Lauss
554a161d23SManuel Lauss /* runtime data */
564a161d23SManuel Lauss int msbits;
574a161d23SManuel Lauss };
584a161d23SManuel Lauss
594a161d23SManuel Lauss /*
604a161d23SManuel Lauss * These settings are somewhat okay, at least on my machine audio plays
614a161d23SManuel Lauss * almost skip-free. Especially the 64kB buffer seems to help a LOT.
624a161d23SManuel Lauss */
634a161d23SManuel Lauss #define AU1XPSC_PERIOD_MIN_BYTES 1024
644a161d23SManuel Lauss #define AU1XPSC_BUFFER_MIN_BYTES 65536
654a161d23SManuel Lauss
664a161d23SManuel Lauss /* PCM hardware DMA capabilities - platform specific */
674a161d23SManuel Lauss static const struct snd_pcm_hardware au1xpsc_pcm_hardware = {
684a161d23SManuel Lauss .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
692008f137STakashi Iwai SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
704a161d23SManuel Lauss .period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES,
714a161d23SManuel Lauss .period_bytes_max = 4096 * 1024 - 1,
724a161d23SManuel Lauss .periods_min = 2,
734a161d23SManuel Lauss .periods_max = 4096, /* 2 to as-much-as-you-like */
744a161d23SManuel Lauss .buffer_bytes_max = 4096 * 1024 - 1,
754a161d23SManuel Lauss .fifo_size = 16, /* fifo entries of AC97/I2S PSC */
764a161d23SManuel Lauss };
774a161d23SManuel Lauss
au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata * cd)784a161d23SManuel Lauss static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd)
794a161d23SManuel Lauss {
80963accbcSManuel Lauss au1xxx_dbdma_put_source(cd->ddma_chan, cd->dma_area,
814a161d23SManuel Lauss cd->period_bytes, DDMA_FLAGS_IE);
824a161d23SManuel Lauss
834a161d23SManuel Lauss /* update next-to-queue period */
844a161d23SManuel Lauss ++cd->q_period;
854a161d23SManuel Lauss cd->dma_area += cd->period_bytes;
864a161d23SManuel Lauss if (cd->q_period >= cd->periods) {
874a161d23SManuel Lauss cd->q_period = 0;
884a161d23SManuel Lauss cd->dma_area = cd->dma_area_s;
894a161d23SManuel Lauss }
904a161d23SManuel Lauss }
914a161d23SManuel Lauss
au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata * cd)924a161d23SManuel Lauss static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd)
934a161d23SManuel Lauss {
94963accbcSManuel Lauss au1xxx_dbdma_put_dest(cd->ddma_chan, cd->dma_area,
954a161d23SManuel Lauss cd->period_bytes, DDMA_FLAGS_IE);
964a161d23SManuel Lauss
974a161d23SManuel Lauss /* update next-to-queue period */
984a161d23SManuel Lauss ++cd->q_period;
994a161d23SManuel Lauss cd->dma_area += cd->period_bytes;
1004a161d23SManuel Lauss if (cd->q_period >= cd->periods) {
1014a161d23SManuel Lauss cd->q_period = 0;
1024a161d23SManuel Lauss cd->dma_area = cd->dma_area_s;
1034a161d23SManuel Lauss }
1044a161d23SManuel Lauss }
1054a161d23SManuel Lauss
au1x_pcm_dmatx_cb(int irq,void * dev_id)1064a161d23SManuel Lauss static void au1x_pcm_dmatx_cb(int irq, void *dev_id)
1074a161d23SManuel Lauss {
1084a161d23SManuel Lauss struct au1xpsc_audio_dmadata *cd = dev_id;
1094a161d23SManuel Lauss
1104a161d23SManuel Lauss cd->pos += cd->period_bytes;
1114a161d23SManuel Lauss if (++cd->curr_period >= cd->periods) {
1124a161d23SManuel Lauss cd->pos = 0;
1134a161d23SManuel Lauss cd->curr_period = 0;
1144a161d23SManuel Lauss }
1154a161d23SManuel Lauss snd_pcm_period_elapsed(cd->substream);
1164a161d23SManuel Lauss au1x_pcm_queue_tx(cd);
1174a161d23SManuel Lauss }
1184a161d23SManuel Lauss
au1x_pcm_dmarx_cb(int irq,void * dev_id)1194a161d23SManuel Lauss static void au1x_pcm_dmarx_cb(int irq, void *dev_id)
1204a161d23SManuel Lauss {
1214a161d23SManuel Lauss struct au1xpsc_audio_dmadata *cd = dev_id;
1224a161d23SManuel Lauss
1234a161d23SManuel Lauss cd->pos += cd->period_bytes;
1244a161d23SManuel Lauss if (++cd->curr_period >= cd->periods) {
1254a161d23SManuel Lauss cd->pos = 0;
1264a161d23SManuel Lauss cd->curr_period = 0;
1274a161d23SManuel Lauss }
1284a161d23SManuel Lauss snd_pcm_period_elapsed(cd->substream);
1294a161d23SManuel Lauss au1x_pcm_queue_rx(cd);
1304a161d23SManuel Lauss }
1314a161d23SManuel Lauss
au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata * pcd)1324a161d23SManuel Lauss static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata *pcd)
1334a161d23SManuel Lauss {
1344a161d23SManuel Lauss if (pcd->ddma_chan) {
1354a161d23SManuel Lauss au1xxx_dbdma_stop(pcd->ddma_chan);
1364a161d23SManuel Lauss au1xxx_dbdma_reset(pcd->ddma_chan);
1374a161d23SManuel Lauss au1xxx_dbdma_chan_free(pcd->ddma_chan);
1384a161d23SManuel Lauss pcd->ddma_chan = 0;
1394a161d23SManuel Lauss pcd->msbits = 0;
1404a161d23SManuel Lauss }
1414a161d23SManuel Lauss }
1424a161d23SManuel Lauss
1434a161d23SManuel Lauss /* in case of missing DMA ring or changed TX-source / RX-dest bit widths,
1444a161d23SManuel Lauss * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according
1454a161d23SManuel Lauss * to ALSA-supplied sample depth. This is due to limitations in the dbdma api
1464a161d23SManuel Lauss * (cannot adjust source/dest widths of already allocated descriptor ring).
1474a161d23SManuel Lauss */
au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata * pcd,int stype,int msbits)1484a161d23SManuel Lauss static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd,
1494a161d23SManuel Lauss int stype, int msbits)
1504a161d23SManuel Lauss {
1514a161d23SManuel Lauss /* DMA only in 8/16/32 bit widths */
1524a161d23SManuel Lauss if (msbits == 24)
1534a161d23SManuel Lauss msbits = 32;
1544a161d23SManuel Lauss
1554a161d23SManuel Lauss /* check current config: correct bits and descriptors allocated? */
1564a161d23SManuel Lauss if ((pcd->ddma_chan) && (msbits == pcd->msbits))
1574a161d23SManuel Lauss goto out; /* all ok! */
1584a161d23SManuel Lauss
1594a161d23SManuel Lauss au1x_pcm_dbdma_free(pcd);
1604a161d23SManuel Lauss
16125942fdcSManuel Lauss if (stype == SNDRV_PCM_STREAM_CAPTURE)
1624a161d23SManuel Lauss pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id,
1634a161d23SManuel Lauss DSCR_CMD0_ALWAYS,
1644a161d23SManuel Lauss au1x_pcm_dmarx_cb, (void *)pcd);
1654a161d23SManuel Lauss else
1664a161d23SManuel Lauss pcd->ddma_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS,
1674a161d23SManuel Lauss pcd->ddma_id,
1684a161d23SManuel Lauss au1x_pcm_dmatx_cb, (void *)pcd);
1694a161d23SManuel Lauss
1704a161d23SManuel Lauss if (!pcd->ddma_chan)
171c19a28e1SFernando Carrijo return -ENOMEM;
1724a161d23SManuel Lauss
1734a161d23SManuel Lauss au1xxx_dbdma_set_devwidth(pcd->ddma_chan, msbits);
1744a161d23SManuel Lauss au1xxx_dbdma_ring_alloc(pcd->ddma_chan, 2);
1754a161d23SManuel Lauss
1764a161d23SManuel Lauss pcd->msbits = msbits;
1774a161d23SManuel Lauss
1784a161d23SManuel Lauss au1xxx_dbdma_stop(pcd->ddma_chan);
1794a161d23SManuel Lauss au1xxx_dbdma_reset(pcd->ddma_chan);
1804a161d23SManuel Lauss
1814a161d23SManuel Lauss out:
1824a161d23SManuel Lauss return 0;
1834a161d23SManuel Lauss }
1844a161d23SManuel Lauss
to_dmadata(struct snd_pcm_substream * ss,struct snd_soc_component * component)18558c2dbe1SKuninori Morimoto static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss,
18658c2dbe1SKuninori Morimoto struct snd_soc_component *component)
187ffc4fdbbSManuel Lauss {
188abf33c7aSKuninori Morimoto struct au1xpsc_audio_dmadata *pcd = snd_soc_component_get_drvdata(component);
18925942fdcSManuel Lauss return &pcd[ss->stream];
190ffc4fdbbSManuel Lauss }
191ffc4fdbbSManuel Lauss
au1xpsc_pcm_hw_params(struct snd_soc_component * component,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)19258c2dbe1SKuninori Morimoto static int au1xpsc_pcm_hw_params(struct snd_soc_component *component,
19358c2dbe1SKuninori Morimoto struct snd_pcm_substream *substream,
1944a161d23SManuel Lauss struct snd_pcm_hw_params *params)
1954a161d23SManuel Lauss {
1964a161d23SManuel Lauss struct snd_pcm_runtime *runtime = substream->runtime;
1974a161d23SManuel Lauss struct au1xpsc_audio_dmadata *pcd;
1984a161d23SManuel Lauss int stype, ret;
1994a161d23SManuel Lauss
20025942fdcSManuel Lauss stype = substream->stream;
20158c2dbe1SKuninori Morimoto pcd = to_dmadata(substream, component);
2024a161d23SManuel Lauss
203896491b3SHeinrich Schuchardt DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %zu "
204896491b3SHeinrich Schuchardt "runtime->min_align %lu\n",
2054a161d23SManuel Lauss (unsigned long)runtime->dma_area,
2064a161d23SManuel Lauss (unsigned long)runtime->dma_addr, runtime->dma_bytes,
2074a161d23SManuel Lauss runtime->min_align);
2084a161d23SManuel Lauss
2094a161d23SManuel Lauss DBG("bits %d frags %d frag_bytes %d is_rx %d\n", params->msbits,
2104a161d23SManuel Lauss params_periods(params), params_period_bytes(params), stype);
2114a161d23SManuel Lauss
2124a161d23SManuel Lauss ret = au1x_pcm_dbdma_realloc(pcd, stype, params->msbits);
2134a161d23SManuel Lauss if (ret) {
2144a161d23SManuel Lauss MSG("DDMA channel (re)alloc failed!\n");
2154a161d23SManuel Lauss goto out;
2164a161d23SManuel Lauss }
2174a161d23SManuel Lauss
2184a161d23SManuel Lauss pcd->substream = substream;
2194a161d23SManuel Lauss pcd->period_bytes = params_period_bytes(params);
2204a161d23SManuel Lauss pcd->periods = params_periods(params);
221963accbcSManuel Lauss pcd->dma_area_s = pcd->dma_area = runtime->dma_addr;
2224a161d23SManuel Lauss pcd->q_period = 0;
2234a161d23SManuel Lauss pcd->curr_period = 0;
2244a161d23SManuel Lauss pcd->pos = 0;
2254a161d23SManuel Lauss
2264a161d23SManuel Lauss ret = 0;
2274a161d23SManuel Lauss out:
2284a161d23SManuel Lauss return ret;
2294a161d23SManuel Lauss }
2304a161d23SManuel Lauss
au1xpsc_pcm_prepare(struct snd_soc_component * component,struct snd_pcm_substream * substream)23158c2dbe1SKuninori Morimoto static int au1xpsc_pcm_prepare(struct snd_soc_component *component,
23258c2dbe1SKuninori Morimoto struct snd_pcm_substream *substream)
2334a161d23SManuel Lauss {
23458c2dbe1SKuninori Morimoto struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream, component);
2354a161d23SManuel Lauss
2364a161d23SManuel Lauss au1xxx_dbdma_reset(pcd->ddma_chan);
2374a161d23SManuel Lauss
23825942fdcSManuel Lauss if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
2394a161d23SManuel Lauss au1x_pcm_queue_rx(pcd);
2404a161d23SManuel Lauss au1x_pcm_queue_rx(pcd);
2414a161d23SManuel Lauss } else {
2424a161d23SManuel Lauss au1x_pcm_queue_tx(pcd);
2434a161d23SManuel Lauss au1x_pcm_queue_tx(pcd);
2444a161d23SManuel Lauss }
2454a161d23SManuel Lauss
2464a161d23SManuel Lauss return 0;
2474a161d23SManuel Lauss }
2484a161d23SManuel Lauss
au1xpsc_pcm_trigger(struct snd_soc_component * component,struct snd_pcm_substream * substream,int cmd)24958c2dbe1SKuninori Morimoto static int au1xpsc_pcm_trigger(struct snd_soc_component *component,
25058c2dbe1SKuninori Morimoto struct snd_pcm_substream *substream, int cmd)
2514a161d23SManuel Lauss {
25258c2dbe1SKuninori Morimoto u32 c = to_dmadata(substream, component)->ddma_chan;
2534a161d23SManuel Lauss
2544a161d23SManuel Lauss switch (cmd) {
2554a161d23SManuel Lauss case SNDRV_PCM_TRIGGER_START:
2564a161d23SManuel Lauss case SNDRV_PCM_TRIGGER_RESUME:
2574a161d23SManuel Lauss au1xxx_dbdma_start(c);
2584a161d23SManuel Lauss break;
2594a161d23SManuel Lauss case SNDRV_PCM_TRIGGER_STOP:
2604a161d23SManuel Lauss case SNDRV_PCM_TRIGGER_SUSPEND:
2614a161d23SManuel Lauss au1xxx_dbdma_stop(c);
2624a161d23SManuel Lauss break;
2634a161d23SManuel Lauss default:
2644a161d23SManuel Lauss return -EINVAL;
2654a161d23SManuel Lauss }
2664a161d23SManuel Lauss return 0;
2674a161d23SManuel Lauss }
2684a161d23SManuel Lauss
2694a161d23SManuel Lauss static snd_pcm_uframes_t
au1xpsc_pcm_pointer(struct snd_soc_component * component,struct snd_pcm_substream * substream)27058c2dbe1SKuninori Morimoto au1xpsc_pcm_pointer(struct snd_soc_component *component,
27158c2dbe1SKuninori Morimoto struct snd_pcm_substream *substream)
2724a161d23SManuel Lauss {
27358c2dbe1SKuninori Morimoto return bytes_to_frames(substream->runtime,
27458c2dbe1SKuninori Morimoto to_dmadata(substream, component)->pos);
2754a161d23SManuel Lauss }
2764a161d23SManuel Lauss
au1xpsc_pcm_open(struct snd_soc_component * component,struct snd_pcm_substream * substream)27758c2dbe1SKuninori Morimoto static int au1xpsc_pcm_open(struct snd_soc_component *component,
27858c2dbe1SKuninori Morimoto struct snd_pcm_substream *substream)
2794a161d23SManuel Lauss {
28058c2dbe1SKuninori Morimoto struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream, component);
281*e287d046SKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
28225942fdcSManuel Lauss int stype = substream->stream, *dmaids;
2835b0912beSManuel Lauss
28411a828faSKuninori Morimoto dmaids = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
2855b0912beSManuel Lauss if (!dmaids)
2865b0912beSManuel Lauss return -ENODEV; /* whoa, has ordering changed? */
2875b0912beSManuel Lauss
2885b0912beSManuel Lauss pcd->ddma_id = dmaids[stype];
2895b0912beSManuel Lauss
2904a161d23SManuel Lauss snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware);
2914a161d23SManuel Lauss return 0;
2924a161d23SManuel Lauss }
2934a161d23SManuel Lauss
au1xpsc_pcm_close(struct snd_soc_component * component,struct snd_pcm_substream * substream)29458c2dbe1SKuninori Morimoto static int au1xpsc_pcm_close(struct snd_soc_component *component,
29558c2dbe1SKuninori Morimoto struct snd_pcm_substream *substream)
2964a161d23SManuel Lauss {
29758c2dbe1SKuninori Morimoto au1x_pcm_dbdma_free(to_dmadata(substream, component));
2984a161d23SManuel Lauss return 0;
2994a161d23SManuel Lauss }
3004a161d23SManuel Lauss
au1xpsc_pcm_new(struct snd_soc_component * component,struct snd_soc_pcm_runtime * rtd)30158c2dbe1SKuninori Morimoto static int au1xpsc_pcm_new(struct snd_soc_component *component,
30258c2dbe1SKuninori Morimoto struct snd_soc_pcm_runtime *rtd)
3034a161d23SManuel Lauss {
304552d1ef6SLiam Girdwood struct snd_card *card = rtd->card->snd_card;
305552d1ef6SLiam Girdwood struct snd_pcm *pcm = rtd->pcm;
306552d1ef6SLiam Girdwood
307fe9912acSTakashi Iwai snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
3084a161d23SManuel Lauss card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1);
3094a161d23SManuel Lauss
3104a161d23SManuel Lauss return 0;
3114a161d23SManuel Lauss }
3124a161d23SManuel Lauss
3130f83d639SManuel Lauss /* au1xpsc audio platform */
314abf33c7aSKuninori Morimoto static struct snd_soc_component_driver au1xpsc_soc_component = {
315abf33c7aSKuninori Morimoto .name = DRV_NAME,
31658c2dbe1SKuninori Morimoto .open = au1xpsc_pcm_open,
31758c2dbe1SKuninori Morimoto .close = au1xpsc_pcm_close,
31858c2dbe1SKuninori Morimoto .hw_params = au1xpsc_pcm_hw_params,
31958c2dbe1SKuninori Morimoto .prepare = au1xpsc_pcm_prepare,
32058c2dbe1SKuninori Morimoto .trigger = au1xpsc_pcm_trigger,
32158c2dbe1SKuninori Morimoto .pointer = au1xpsc_pcm_pointer,
32258c2dbe1SKuninori Morimoto .pcm_construct = au1xpsc_pcm_new,
3230f83d639SManuel Lauss };
3240f83d639SManuel Lauss
au1xpsc_pcm_drvprobe(struct platform_device * pdev)3255c658be0SBill Pemberton static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
3260f83d639SManuel Lauss {
327ffc4fdbbSManuel Lauss struct au1xpsc_audio_dmadata *dmadata;
3284a161d23SManuel Lauss
329a86854d0SKees Cook dmadata = devm_kcalloc(&pdev->dev,
330a86854d0SKees Cook 2, sizeof(struct au1xpsc_audio_dmadata),
331be547dd1SJulia Lawall GFP_KERNEL);
332ffc4fdbbSManuel Lauss if (!dmadata)
3334a161d23SManuel Lauss return -ENOMEM;
3344a161d23SManuel Lauss
335ffc4fdbbSManuel Lauss platform_set_drvdata(pdev, dmadata);
3364a161d23SManuel Lauss
337abf33c7aSKuninori Morimoto return devm_snd_soc_register_component(&pdev->dev,
338abf33c7aSKuninori Morimoto &au1xpsc_soc_component, NULL, 0);
3394a161d23SManuel Lauss }
3404a161d23SManuel Lauss
3410f83d639SManuel Lauss static struct platform_driver au1xpsc_pcm_driver = {
3420f83d639SManuel Lauss .driver = {
343ffc4fdbbSManuel Lauss .name = "au1xpsc-pcm",
3440f83d639SManuel Lauss },
3450f83d639SManuel Lauss .probe = au1xpsc_pcm_drvprobe,
3464a161d23SManuel Lauss };
3474a161d23SManuel Lauss
3488a124f9cSAxel Lin module_platform_driver(au1xpsc_pcm_driver);
3490f83d639SManuel Lauss
3504a161d23SManuel Lauss MODULE_LICENSE("GPL");
3514a161d23SManuel Lauss MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
3520f83d639SManuel Lauss MODULE_AUTHOR("Manuel Lauss");
353