2 * Generic TXx9 ACLC platform driver
4 * Copyright (C) 2009 Atsushi Nemoto
6 * Based on RBTX49xx patch from CELF patch archive.
7 * (C) Copyright TOSHIBA CORPORATION 2004-2006
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/platform_device.h>
17 #include <linux/scatterlist.h>
18 #include <linux/slab.h>
19 #include <sound/core.h>
20 #include <sound/pcm.h>
21 #include <sound/pcm_params.h>
22 #include <sound/soc.h>
25 static struct txx9aclc_soc_device
{
26 struct txx9aclc_dmadata dmadata
[2];
27 } txx9aclc_soc_device
;
29 /* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
30 static struct txx9aclc_plat_drvdata
*txx9aclc_drvdata
;
32 static int txx9aclc_dma_init(struct txx9aclc_soc_device
*dev
,
33 struct txx9aclc_dmadata
*dmadata
);
35 static const struct snd_pcm_hardware txx9aclc_pcm_hardware
= {
37 * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
38 * needs more works for noncoherent MIPS.
40 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
41 SNDRV_PCM_INFO_BATCH
|
43 .period_bytes_min
= 1024,
44 .period_bytes_max
= 8 * 1024,
47 .buffer_bytes_max
= 32 * 1024,
50 static int txx9aclc_pcm_hw_params(struct snd_pcm_substream
*substream
,
51 struct snd_pcm_hw_params
*params
)
53 struct snd_soc_pcm_runtime
*rtd
= snd_pcm_substream_chip(substream
);
54 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
55 struct txx9aclc_dmadata
*dmadata
= runtime
->private_data
;
58 ret
= snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
62 dev_dbg(rtd
->platform
->dev
,
63 "runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
64 "runtime->min_align %ld\n",
65 (unsigned long)runtime
->dma_area
,
66 (unsigned long)runtime
->dma_addr
, runtime
->dma_bytes
,
68 dev_dbg(rtd
->platform
->dev
,
69 "periods %d period_bytes %d stream %d\n",
70 params_periods(params
), params_period_bytes(params
),
73 dmadata
->substream
= substream
;
78 static int txx9aclc_pcm_hw_free(struct snd_pcm_substream
*substream
)
80 return snd_pcm_lib_free_pages(substream
);
83 static int txx9aclc_pcm_prepare(struct snd_pcm_substream
*substream
)
85 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
86 struct txx9aclc_dmadata
*dmadata
= runtime
->private_data
;
88 dmadata
->dma_addr
= runtime
->dma_addr
;
89 dmadata
->buffer_bytes
= snd_pcm_lib_buffer_bytes(substream
);
90 dmadata
->period_bytes
= snd_pcm_lib_period_bytes(substream
);
92 if (dmadata
->buffer_bytes
== dmadata
->period_bytes
) {
93 dmadata
->frag_bytes
= dmadata
->period_bytes
>> 1;
96 dmadata
->frag_bytes
= dmadata
->period_bytes
;
97 dmadata
->frags
= dmadata
->buffer_bytes
/ dmadata
->period_bytes
;
99 dmadata
->frag_count
= 0;
104 static void txx9aclc_dma_complete(void *arg
)
106 struct txx9aclc_dmadata
*dmadata
= arg
;
109 /* dma completion handler cannot submit new operations */
110 spin_lock_irqsave(&dmadata
->dma_lock
, flags
);
111 if (dmadata
->frag_count
>= 0) {
113 if (!WARN_ON(dmadata
->dmacount
< 0))
114 tasklet_schedule(&dmadata
->tasklet
);
116 spin_unlock_irqrestore(&dmadata
->dma_lock
, flags
);
119 static struct dma_async_tx_descriptor
*
120 txx9aclc_dma_submit(struct txx9aclc_dmadata
*dmadata
, dma_addr_t buf_dma_addr
)
122 struct dma_chan
*chan
= dmadata
->dma_chan
;
123 struct dma_async_tx_descriptor
*desc
;
124 struct scatterlist sg
;
126 sg_init_table(&sg
, 1);
127 sg_set_page(&sg
, pfn_to_page(PFN_DOWN(buf_dma_addr
)),
128 dmadata
->frag_bytes
, buf_dma_addr
& (PAGE_SIZE
- 1));
129 sg_dma_address(&sg
) = buf_dma_addr
;
130 desc
= dmaengine_prep_slave_sg(chan
, &sg
, 1,
131 dmadata
->substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
132 DMA_MEM_TO_DEV
: DMA_DEV_TO_MEM
,
133 DMA_PREP_INTERRUPT
| DMA_CTRL_ACK
);
135 dev_err(&chan
->dev
->device
, "cannot prepare slave dma\n");
138 desc
->callback
= txx9aclc_dma_complete
;
139 desc
->callback_param
= dmadata
;
140 desc
->tx_submit(desc
);
144 #define NR_DMA_CHAIN 2
146 static void txx9aclc_dma_tasklet(unsigned long data
)
148 struct txx9aclc_dmadata
*dmadata
= (struct txx9aclc_dmadata
*)data
;
149 struct dma_chan
*chan
= dmadata
->dma_chan
;
150 struct dma_async_tx_descriptor
*desc
;
151 struct snd_pcm_substream
*substream
= dmadata
->substream
;
152 u32 ctlbit
= substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
153 ACCTL_AUDODMA
: ACCTL_AUDIDMA
;
157 spin_lock_irqsave(&dmadata
->dma_lock
, flags
);
158 if (dmadata
->frag_count
< 0) {
159 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_drvdata
;
160 void __iomem
*base
= drvdata
->base
;
162 spin_unlock_irqrestore(&dmadata
->dma_lock
, flags
);
163 chan
->device
->device_control(chan
, DMA_TERMINATE_ALL
, 0);
165 for (i
= 0; i
< NR_DMA_CHAIN
; i
++) {
166 desc
= txx9aclc_dma_submit(dmadata
,
167 dmadata
->dma_addr
+ i
* dmadata
->frag_bytes
);
171 dmadata
->dmacount
= NR_DMA_CHAIN
;
172 chan
->device
->device_issue_pending(chan
);
173 spin_lock_irqsave(&dmadata
->dma_lock
, flags
);
174 __raw_writel(ctlbit
, base
+ ACCTLEN
);
175 dmadata
->frag_count
= NR_DMA_CHAIN
% dmadata
->frags
;
176 spin_unlock_irqrestore(&dmadata
->dma_lock
, flags
);
179 if (WARN_ON(dmadata
->dmacount
>= NR_DMA_CHAIN
)) {
180 spin_unlock_irqrestore(&dmadata
->dma_lock
, flags
);
183 while (dmadata
->dmacount
< NR_DMA_CHAIN
) {
185 spin_unlock_irqrestore(&dmadata
->dma_lock
, flags
);
186 desc
= txx9aclc_dma_submit(dmadata
,
188 dmadata
->frag_count
* dmadata
->frag_bytes
);
191 chan
->device
->device_issue_pending(chan
);
193 spin_lock_irqsave(&dmadata
->dma_lock
, flags
);
194 dmadata
->frag_count
++;
195 dmadata
->frag_count
%= dmadata
->frags
;
196 dmadata
->pos
+= dmadata
->frag_bytes
;
197 dmadata
->pos
%= dmadata
->buffer_bytes
;
198 if ((dmadata
->frag_count
* dmadata
->frag_bytes
) %
199 dmadata
->period_bytes
== 0)
200 snd_pcm_period_elapsed(substream
);
202 spin_unlock_irqrestore(&dmadata
->dma_lock
, flags
);
205 static int txx9aclc_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
207 struct txx9aclc_dmadata
*dmadata
= substream
->runtime
->private_data
;
208 struct txx9aclc_plat_drvdata
*drvdata
=txx9aclc_drvdata
;
209 void __iomem
*base
= drvdata
->base
;
212 u32 ctlbit
= substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
213 ACCTL_AUDODMA
: ACCTL_AUDIDMA
;
215 spin_lock_irqsave(&dmadata
->dma_lock
, flags
);
217 case SNDRV_PCM_TRIGGER_START
:
218 dmadata
->frag_count
= -1;
219 tasklet_schedule(&dmadata
->tasklet
);
221 case SNDRV_PCM_TRIGGER_STOP
:
222 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
223 case SNDRV_PCM_TRIGGER_SUSPEND
:
224 __raw_writel(ctlbit
, base
+ ACCTLDIS
);
226 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
227 case SNDRV_PCM_TRIGGER_RESUME
:
228 __raw_writel(ctlbit
, base
+ ACCTLEN
);
233 spin_unlock_irqrestore(&dmadata
->dma_lock
, flags
);
237 static snd_pcm_uframes_t
238 txx9aclc_pcm_pointer(struct snd_pcm_substream
*substream
)
240 struct txx9aclc_dmadata
*dmadata
= substream
->runtime
->private_data
;
242 return bytes_to_frames(substream
->runtime
, dmadata
->pos
);
245 static int txx9aclc_pcm_open(struct snd_pcm_substream
*substream
)
247 struct txx9aclc_soc_device
*dev
= &txx9aclc_soc_device
;
248 struct txx9aclc_dmadata
*dmadata
= &dev
->dmadata
[substream
->stream
];
251 ret
= snd_soc_set_runtime_hwparams(substream
, &txx9aclc_pcm_hardware
);
254 /* ensure that buffer size is a multiple of period size */
255 ret
= snd_pcm_hw_constraint_integer(substream
->runtime
,
256 SNDRV_PCM_HW_PARAM_PERIODS
);
259 substream
->runtime
->private_data
= dmadata
;
263 static int txx9aclc_pcm_close(struct snd_pcm_substream
*substream
)
265 struct txx9aclc_dmadata
*dmadata
= substream
->runtime
->private_data
;
266 struct dma_chan
*chan
= dmadata
->dma_chan
;
268 dmadata
->frag_count
= -1;
269 chan
->device
->device_control(chan
, DMA_TERMINATE_ALL
, 0);
273 static struct snd_pcm_ops txx9aclc_pcm_ops
= {
274 .open
= txx9aclc_pcm_open
,
275 .close
= txx9aclc_pcm_close
,
276 .ioctl
= snd_pcm_lib_ioctl
,
277 .hw_params
= txx9aclc_pcm_hw_params
,
278 .hw_free
= txx9aclc_pcm_hw_free
,
279 .prepare
= txx9aclc_pcm_prepare
,
280 .trigger
= txx9aclc_pcm_trigger
,
281 .pointer
= txx9aclc_pcm_pointer
,
284 static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm
*pcm
)
286 snd_pcm_lib_preallocate_free_for_all(pcm
);
289 static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime
*rtd
)
291 struct snd_card
*card
= rtd
->card
->snd_card
;
292 struct snd_soc_dai
*dai
= rtd
->cpu_dai
;
293 struct snd_pcm
*pcm
= rtd
->pcm
;
294 struct platform_device
*pdev
= to_platform_device(dai
->platform
->dev
);
295 struct txx9aclc_soc_device
*dev
;
300 /* at this point onwards the AC97 component has probed and this will be valid */
301 dev
= snd_soc_dai_get_drvdata(dai
);
303 dev
->dmadata
[0].stream
= SNDRV_PCM_STREAM_PLAYBACK
;
304 dev
->dmadata
[1].stream
= SNDRV_PCM_STREAM_CAPTURE
;
305 for (i
= 0; i
< 2; i
++) {
306 r
= platform_get_resource(pdev
, IORESOURCE_DMA
, i
);
311 dev
->dmadata
[i
].dma_res
= r
;
312 ret
= txx9aclc_dma_init(dev
, &dev
->dmadata
[i
]);
316 return snd_pcm_lib_preallocate_pages_for_all(pcm
, SNDRV_DMA_TYPE_DEV
,
317 card
->dev
, 64 * 1024, 4 * 1024 * 1024);
320 for (i
= 0; i
< 2; i
++) {
321 if (dev
->dmadata
[i
].dma_chan
)
322 dma_release_channel(dev
->dmadata
[i
].dma_chan
);
323 dev
->dmadata
[i
].dma_chan
= NULL
;
328 static bool filter(struct dma_chan
*chan
, void *param
)
330 struct txx9aclc_dmadata
*dmadata
= param
;
334 devname
= kasprintf(GFP_KERNEL
, "%s.%d", dmadata
->dma_res
->name
,
335 (int)dmadata
->dma_res
->start
);
336 if (strcmp(dev_name(chan
->device
->dev
), devname
) == 0) {
337 chan
->private = &dmadata
->dma_slave
;
344 static int txx9aclc_dma_init(struct txx9aclc_soc_device
*dev
,
345 struct txx9aclc_dmadata
*dmadata
)
347 struct txx9aclc_plat_drvdata
*drvdata
=txx9aclc_drvdata
;
348 struct txx9dmac_slave
*ds
= &dmadata
->dma_slave
;
351 spin_lock_init(&dmadata
->dma_lock
);
353 ds
->reg_width
= sizeof(u32
);
354 if (dmadata
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
355 ds
->tx_reg
= drvdata
->physbase
+ ACAUDODAT
;
359 ds
->rx_reg
= drvdata
->physbase
+ ACAUDIDAT
;
362 /* Try to grab a DMA channel */
364 dma_cap_set(DMA_SLAVE
, mask
);
365 dmadata
->dma_chan
= dma_request_channel(mask
, filter
, dmadata
);
366 if (!dmadata
->dma_chan
) {
368 "DMA channel for %s is not available\n",
369 dmadata
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
370 "playback" : "capture");
373 tasklet_init(&dmadata
->tasklet
, txx9aclc_dma_tasklet
,
374 (unsigned long)dmadata
);
378 static int txx9aclc_pcm_probe(struct snd_soc_platform
*platform
)
380 snd_soc_platform_set_drvdata(platform
, &txx9aclc_soc_device
);
384 static int txx9aclc_pcm_remove(struct snd_soc_platform
*platform
)
386 struct txx9aclc_soc_device
*dev
= snd_soc_platform_get_drvdata(platform
);
387 struct txx9aclc_plat_drvdata
*drvdata
= txx9aclc_drvdata
;
388 void __iomem
*base
= drvdata
->base
;
391 /* disable all FIFO DMAs */
392 __raw_writel(ACCTL_AUDODMA
| ACCTL_AUDIDMA
, base
+ ACCTLDIS
);
393 /* dummy R/W to clear pending DMAREQ if any */
394 __raw_writel(__raw_readl(base
+ ACAUDIDAT
), base
+ ACAUDODAT
);
396 for (i
= 0; i
< 2; i
++) {
397 struct txx9aclc_dmadata
*dmadata
= &dev
->dmadata
[i
];
398 struct dma_chan
*chan
= dmadata
->dma_chan
;
400 dmadata
->frag_count
= -1;
401 chan
->device
->device_control(chan
,
402 DMA_TERMINATE_ALL
, 0);
403 dma_release_channel(chan
);
405 dev
->dmadata
[i
].dma_chan
= NULL
;
410 static struct snd_soc_platform_driver txx9aclc_soc_platform
= {
411 .probe
= txx9aclc_pcm_probe
,
412 .remove
= txx9aclc_pcm_remove
,
413 .ops
= &txx9aclc_pcm_ops
,
414 .pcm_new
= txx9aclc_pcm_new
,
415 .pcm_free
= txx9aclc_pcm_free_dma_buffers
,
418 static int txx9aclc_soc_platform_probe(struct platform_device
*pdev
)
420 return snd_soc_register_platform(&pdev
->dev
, &txx9aclc_soc_platform
);
423 static int txx9aclc_soc_platform_remove(struct platform_device
*pdev
)
425 snd_soc_unregister_platform(&pdev
->dev
);
429 static struct platform_driver txx9aclc_pcm_driver
= {
431 .name
= "txx9aclc-pcm-audio",
432 .owner
= THIS_MODULE
,
435 .probe
= txx9aclc_soc_platform_probe
,
436 .remove
= txx9aclc_soc_platform_remove
,
439 module_platform_driver(txx9aclc_pcm_driver
);
441 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
442 MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
443 MODULE_LICENSE("GPL");