aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sh
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sh')
-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}