25 #include <linux/module.h>
38 #define GET_MAX_PERIODS(buf_bytes, period_bytes) \
39 ((buf_bytes) / (period_bytes))
40 #define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \
41 ((buf_addr) + ((period_num) * (period_bytes)))
43 #define RWF_STM_RD 0x01
44 #define RWF_STM_WT 0x02
49 static int siu_pcm_stmwrite_stop(
struct siu_port *
port_info)
53 struct siu_stream *siu_stream = &port_info->playback;
56 if (!siu_stream->rw_flg)
60 stfifo = siu_read32(base + SIU_STFIFO);
61 siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18);
62 pr_debug(
"%s: STFIFO %x -> %x\n", __func__,
63 stfifo, stfifo & ~0x0c180c18);
66 siu_stream->rw_flg = 0;
71 static int siu_pcm_stmwrite_start(
struct siu_port *
port_info)
73 struct siu_stream *siu_stream = &port_info->playback;
75 if (siu_stream->rw_flg)
79 port_info->playback.cur_period = 0;
85 tasklet_schedule(&siu_stream->tasklet);
90 static void siu_dma_tx_complete(
void *
arg)
92 struct siu_stream *siu_stream =
arg;
94 if (!siu_stream->rw_flg)
98 if (++siu_stream->cur_period >=
100 siu_stream->period_bytes))
101 siu_stream->cur_period = 0;
103 pr_debug(
"%s: done period #%d (%u/%u bytes), cookie %d\n",
104 __func__, siu_stream->cur_period,
105 siu_stream->cur_period * siu_stream->period_bytes,
106 siu_stream->buf_bytes, siu_stream->cookie);
108 tasklet_schedule(&siu_stream->tasklet);
114 static int siu_pcm_wr_set(
struct siu_port *port_info,
119 struct siu_stream *siu_stream = &port_info->playback;
133 desc = dmaengine_prep_slave_sg(siu_stream->chan,
136 dev_err(dev,
"Failed to allocate a dma descriptor\n");
140 desc->
callback = siu_dma_tx_complete;
144 dev_err(dev,
"Failed to submit a dma transfer\n");
148 siu_stream->tx_desc = desc;
151 dma_async_issue_pending(siu_stream->chan);
154 stfifo = siu_read32(base + SIU_STFIFO);
155 siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18));
156 dev_dbg(dev,
"%s: STFIFO %x -> %x\n", __func__,
157 stfifo, stfifo | (port_info->stfifo & 0x0c180c18));
162 static int siu_pcm_rd_set(
struct siu_port *port_info,
167 struct siu_stream *siu_stream = &port_info->capture;
169 struct device *dev = substream->
pcm->card->dev;
175 dev_dbg(dev,
"%s: %u@%llx\n", __func__, size, (
unsigned long long)buff);
183 desc = dmaengine_prep_slave_sg(siu_stream->chan,
186 dev_err(dev,
"Failed to allocate dma descriptor\n");
190 desc->
callback = siu_dma_tx_complete;
194 dev_err(dev,
"Failed to submit dma descriptor\n");
198 siu_stream->tx_desc = desc;
201 dma_async_issue_pending(siu_stream->chan);
204 stfifo = siu_read32(base + SIU_STFIFO);
205 siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) |
206 (port_info->stfifo & 0x13071307));
207 dev_dbg(dev,
"%s: STFIFO %x -> %x\n", __func__,
208 stfifo, stfifo | (port_info->stfifo & 0x13071307));
213 static void siu_io_tasklet(
unsigned long data)
215 struct siu_stream *siu_stream = (
struct siu_stream *)data;
217 struct device *dev = substream->
pcm->card->dev;
219 struct siu_port *port_info = siu_port_info(substream);
221 dev_dbg(dev,
"%s: flags %x\n", __func__, siu_stream->rw_flg);
223 if (!siu_stream->rw_flg) {
224 dev_dbg(dev,
"%s: stream inactive\n", __func__);
234 siu_stream->cur_period,
235 siu_stream->period_bytes);
237 siu_stream->cur_period,
238 siu_stream->period_bytes);
239 count = siu_stream->period_bytes;
242 siu_pcm_rd_set(port_info, buff, count);
244 siu_pcm_wr_set(port_info,
246 siu_stream->cur_period,
247 siu_stream->period_bytes),
248 siu_stream->period_bytes);
253 static int siu_pcm_stmread_start(
struct siu_port *port_info)
255 struct siu_stream *siu_stream = &port_info->capture;
257 if (siu_stream->xfer_cnt > 0x1000000)
259 if (siu_stream->rw_flg)
263 siu_stream->cur_period = 0;
268 tasklet_schedule(&siu_stream->tasklet);
273 static int siu_pcm_stmread_stop(
struct siu_port *port_info)
277 struct siu_stream *siu_stream = &port_info->capture;
278 struct device *dev = siu_stream->substream->pcm->card->dev;
281 if (!siu_stream->rw_flg)
285 stfifo = siu_read32(base + SIU_STFIFO);
286 siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307);
287 dev_dbg(dev,
"%s: STFIFO %x -> %x\n", __func__,
288 stfifo, stfifo & ~0x13071307);
291 siu_stream->rw_flg = 0;
303 dev_dbg(dev,
"%s: port=%d\n", __func__, info->port_id);
307 dev_err(dev,
"snd_pcm_lib_malloc_pages() failed\n");
315 struct siu_port *port_info = siu_port_info(ss);
317 struct siu_stream *siu_stream;
320 siu_stream = &port_info->playback;
322 siu_stream = &port_info->capture;
324 dev_dbg(dev,
"%s: port=%d\n", __func__, info->port_id);
345 struct siu_port *port_info = siu_port_info(ss);
346 struct siu_stream *siu_stream;
355 dev_dbg(dev,
"%s, port=%d@%p\n", __func__, port, port_info);
358 siu_stream = &port_info->playback;
359 param = &siu_stream->param;
363 siu_stream = &port_info->capture;
364 param = &siu_stream->param;
371 if (!siu_stream->chan) {
372 dev_err(dev,
"DMA channel allocation failed!\n");
376 siu_stream->substream =
ss;
385 struct siu_port *port_info = siu_port_info(ss);
386 struct siu_stream *siu_stream;
388 dev_dbg(dev,
"%s: port=%d\n", __func__, info->port_id);
391 siu_stream = &port_info->playback;
393 siu_stream = &port_info->capture;
396 siu_stream->chan =
NULL;
398 siu_stream->substream =
NULL;
406 struct siu_port *port_info = siu_port_info(ss);
409 struct siu_stream *siu_stream;
413 siu_stream = &port_info->playback;
415 siu_stream = &port_info->capture;
417 rt = siu_stream->substream->runtime;
419 siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss);
420 siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss);
422 dev_dbg(dev,
"%s: port=%d, %d channels, period=%u bytes\n", __func__,
423 info->port_id, rt->
channels, siu_stream->period_bytes);
426 if (siu_stream->buf_bytes % siu_stream->period_bytes) {
427 dev_err(dev,
"%s() - buffer=%d not multiple of period=%d\n",
428 __func__, siu_stream->buf_bytes,
429 siu_stream->period_bytes);
433 xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes);
434 if (!xfer_cnt || xfer_cnt > 0x1000000)
437 siu_stream->format = rt->
format;
438 siu_stream->xfer_cnt = xfer_cnt;
440 dev_dbg(dev,
"port=%d buf=%lx buf_bytes=%d period_bytes=%d "
441 "format=%d channels=%d xfer_cnt=%d\n", info->port_id,
442 (
unsigned long)rt->
dma_addr, siu_stream->buf_bytes,
443 siu_stream->period_bytes,
444 siu_stream->format, rt->
channels, (
int)xfer_cnt);
453 struct siu_port *port_info = siu_port_info(ss);
456 dev_dbg(dev,
"%s: port=%d@%p, cmd=%d\n", __func__,
457 info->port_id, port_info, cmd);
462 ret = siu_pcm_stmwrite_start(port_info);
464 ret = siu_pcm_stmread_start(port_info);
467 dev_warn(dev,
"%s: start failed on port=%d\n",
468 __func__, info->port_id);
473 siu_pcm_stmwrite_stop(port_info);
475 siu_pcm_stmread_stop(port_info);
480 dev_err(dev,
"%s() unsupported cmd=%d\n", __func__, cmd);
496 struct siu_port *port_info = siu_port_info(ss);
499 struct siu_stream *siu_stream;
502 siu_stream = &port_info->playback;
504 siu_stream = &port_info->capture;
511 siu_stream->cur_period,
512 siu_stream->period_bytes) - rt->
dma_addr;
515 "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n",
516 __func__, info->port_id, siu_read32(base + SIU_EVNTC),
517 siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes,
520 if (ptr >= siu_stream->buf_bytes)
523 return bytes_to_frames(ss->
runtime, ptr);
537 if (pdev->
id < 0 || pdev->
id >= SIU_PORT_NUM)
540 info->port_id = pdev->
id;
548 for (i = pdev->
id; i < pdev->
id + 1; i++) {
557 SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX);
560 "snd_pcm_lib_preallocate_pages_for_all() err=%d",
565 (*port_info)->pcm = pcm;
568 tasklet_init(&(*port_info)->playback.tasklet, siu_io_tasklet,
569 (
unsigned long)&(*port_info)->playback);
570 tasklet_init(&(*port_info)->capture.tasklet, siu_io_tasklet,
571 (
unsigned long)&(*port_info)->capture);
574 dev_info(card->
dev,
"SuperH SIU driver initialized.\n");
579 dev_err(card->
dev,
"SIU: failed to initialize.\n");
583 static void siu_pcm_free(
struct snd_pcm *pcm)
598 .open = siu_pcm_open,
599 .close = siu_pcm_close,
601 .hw_params = siu_pcm_hw_params,
602 .hw_free = siu_pcm_hw_free,
603 .prepare = siu_pcm_prepare,
604 .trigger = siu_pcm_trigger,
605 .pointer = siu_pcm_pointer_dma,
610 .pcm_new = siu_pcm_new,
611 .pcm_free = siu_pcm_free,