aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sh/rcar/ssi.c
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2013-07-28 21:59:02 -0400
committerMark Brown <broonie@linaro.org>2013-08-06 12:56:13 -0400
commit849fc82a6f4f32b4c8c502bb7c4a68df51170232 (patch)
tree59745fe7d701eec3504c166a949fdad5cad467cb /sound/soc/sh/rcar/ssi.c
parent0a4d94c07ce782e645a8c0484d52221758b4c398 (diff)
ASoC: rsnd: SSI supports DMA transfer
This patch adds DMAEngine transfer on SSI. But, it transfers sound data from memory to SSI directly without using HPBIF at this time. It will be updated soon Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/sh/rcar/ssi.c')
-rw-r--r--sound/soc/sh/rcar/ssi.c110
1 files changed, 107 insertions, 3 deletions
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index c48a6c7cd08e..2079ccf5f322 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -19,6 +19,7 @@
19 * SSICR 19 * SSICR
20 */ 20 */
21#define FORCE (1 << 31) /* Fixed */ 21#define FORCE (1 << 31) /* Fixed */
22#define DMEN (1 << 28) /* DMA Enable */
22#define UIEN (1 << 27) /* Underflow Interrupt Enable */ 23#define UIEN (1 << 27) /* Underflow Interrupt Enable */
23#define OIEN (1 << 26) /* Overflow Interrupt Enable */ 24#define OIEN (1 << 26) /* Overflow Interrupt Enable */
24#define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ 25#define IIEN (1 << 25) /* Idle Mode Interrupt Enable */
@@ -51,6 +52,11 @@
51#define IIRQ (1 << 25) /* Idle Mode Interrupt Status */ 52#define IIRQ (1 << 25) /* Idle Mode Interrupt Status */
52#define DIRQ (1 << 24) /* Data Interrupt Status Flag */ 53#define DIRQ (1 << 24) /* Data Interrupt Status Flag */
53 54
55/*
56 * SSIWSR
57 */
58#define CONT (1 << 8) /* WS Continue Function */
59
54struct rsnd_ssi { 60struct rsnd_ssi {
55 struct clk *clk; 61 struct clk *clk;
56 struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ 62 struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
@@ -63,6 +69,7 @@ struct rsnd_ssi {
63 u32 cr_clk; 69 u32 cr_clk;
64 u32 cr_etc; 70 u32 cr_etc;
65 int err; 71 int err;
72 int dma_offset;
66 unsigned int usrcnt; 73 unsigned int usrcnt;
67 unsigned int rate; 74 unsigned int rate;
68}; 75};
@@ -83,7 +90,10 @@ struct rsnd_ssiu {
83 90
84#define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr) 91#define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr)
85#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) 92#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
86#define rsnd_ssi_is_pio(ssi) ((ssi)->info->pio_irq > 0) 93#define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
94#define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0)
95#define rsnd_ssi_dma_available(ssi) \
96 rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
87#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) 97#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
88#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) 98#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
89#define rsnd_ssi_mode_flags(p) ((p)->info->flags) 99#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
@@ -477,6 +487,79 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
477 .stop = rsnd_ssi_pio_stop, 487 .stop = rsnd_ssi_pio_stop,
478}; 488};
479 489
490static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len)
491{
492 struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
493 struct rsnd_dai_stream *io = ssi->io;
494 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
495
496 *len = io->byte_per_period;
497 *buf = runtime->dma_addr +
498 rsnd_dai_pointer_offset(io, ssi->dma_offset + *len);
499 ssi->dma_offset = *len; /* it cares A/B plane */
500
501 return 0;
502}
503
504static int rsnd_ssi_dma_complete(struct rsnd_dma *dma)
505{
506 struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
507 struct rsnd_dai_stream *io = ssi->io;
508 u32 status = rsnd_mod_read(&ssi->mod, SSISR);
509
510 rsnd_ssi_record_error(ssi, status);
511
512 rsnd_dai_pointer_update(ssi->io, io->byte_per_period);
513
514 return 0;
515}
516
517static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
518 struct rsnd_dai *rdai,
519 struct rsnd_dai_stream *io)
520{
521 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
522 struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
523
524 /* enable DMA transfer */
525 ssi->cr_etc = DMEN;
526 ssi->dma_offset = 0;
527
528 rsnd_dma_start(dma);
529
530 rsnd_ssi_hw_start(ssi, ssi->rdai, io);
531
532 /* enable WS continue */
533 if (rsnd_rdai_is_clk_master(rdai))
534 rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
535
536 return 0;
537}
538
539static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
540 struct rsnd_dai *rdai,
541 struct rsnd_dai_stream *io)
542{
543 struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
544 struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
545
546 ssi->cr_etc = 0;
547
548 rsnd_ssi_hw_stop(ssi, rdai);
549
550 rsnd_dma_stop(dma);
551
552 return 0;
553}
554
555static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
556 .name = "ssi (dma)",
557 .init = rsnd_ssi_init,
558 .quit = rsnd_ssi_quit,
559 .start = rsnd_ssi_dma_start,
560 .stop = rsnd_ssi_dma_stop,
561};
562
480/* 563/*
481 * Non SSI 564 * Non SSI
482 */ 565 */
@@ -574,9 +657,26 @@ int rsnd_ssi_probe(struct platform_device *pdev,
574 ops = &rsnd_ssi_non_ops; 657 ops = &rsnd_ssi_non_ops;
575 658
576 /* 659 /*
660 * SSI DMA case
661 */
662 if (pinfo->dma_id > 0) {
663 ret = rsnd_dma_init(
664 priv, rsnd_mod_to_dma(&ssi->mod),
665 (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY),
666 pinfo->dma_id,
667 rsnd_ssi_dma_inquiry,
668 rsnd_ssi_dma_complete);
669 if (ret < 0)
670 dev_info(dev, "SSI DMA failed. try PIO transter\n");
671 else
672 ops = &rsnd_ssi_dma_ops;
673 }
674
675 /*
577 * SSI PIO case 676 * SSI PIO case
578 */ 677 */
579 if (rsnd_ssi_is_pio(ssi)) { 678 if (!rsnd_ssi_dma_available(ssi) &&
679 rsnd_ssi_pio_available(ssi)) {
580 ret = devm_request_irq(dev, pinfo->pio_irq, 680 ret = devm_request_irq(dev, pinfo->pio_irq,
581 &rsnd_ssi_pio_interrupt, 681 &rsnd_ssi_pio_interrupt,
582 IRQF_SHARED, 682 IRQF_SHARED,
@@ -605,6 +705,10 @@ void rsnd_ssi_remove(struct platform_device *pdev,
605 struct rsnd_ssi *ssi; 705 struct rsnd_ssi *ssi;
606 int i; 706 int i;
607 707
608 for_each_rsnd_ssi(ssi, priv, i) 708 for_each_rsnd_ssi(ssi, priv, i) {
609 clk_put(ssi->clk); 709 clk_put(ssi->clk);
710 if (rsnd_ssi_dma_available(ssi))
711 rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod));
712 }
713
610} 714}