aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2015-01-07 20:52:36 -0500
committerMark Brown <broonie@kernel.org>2015-01-12 07:59:32 -0500
commitcfcefe01265cbaf5ca7209226d043b07bfa8b587 (patch)
tree6341e03635512f1842a7cd1a7dc62fca43c00aaf
parentddf3335b3e716ab2161e4db5b70984aef35075a3 (diff)
ASoC: rsnd: add recovery support for under/over flow error on SRC
L/R channel will be switched if under/over flow error happen on Renesas R-Car sound device by the HW bugs. Then, HW restart is required for salvage. This patch add salvage support for SRC. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--include/sound/rcar_snd.h1
-rw-r--r--sound/soc/sh/rcar/gen.c15
-rw-r--r--sound/soc/sh/rcar/rsnd.h8
-rw-r--r--sound/soc/sh/rcar/src.c179
4 files changed, 184 insertions, 19 deletions
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
index 83284cae464c..4cecd0c175f6 100644
--- a/include/sound/rcar_snd.h
+++ b/include/sound/rcar_snd.h
@@ -55,6 +55,7 @@ struct rsnd_ssi_platform_info {
55struct rsnd_src_platform_info { 55struct rsnd_src_platform_info {
56 u32 convert_rate; /* sampling rate convert */ 56 u32 convert_rate; /* sampling rate convert */
57 int dma_id; /* for Gen2 SCU */ 57 int dma_id; /* for Gen2 SCU */
58 int irq;
58}; 59};
59 60
60/* 61/*
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 87a6f2d62775..de0685f2abae 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -309,8 +309,13 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
309 RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), 309 RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20),
310 RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), 310 RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
311 RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), 311 RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
312 RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20),
312 RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), 313 RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20),
313 RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), 314 RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20),
315 RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
316 RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
317 RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
318 RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1c4),
314 RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), 319 RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
315 RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), 320 RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
316 RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), 321 RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
@@ -403,6 +408,16 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
403 RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), 408 RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
404 RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), 409 RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
405 RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40), 410 RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40),
411 /*
412 * ADD US
413 *
414 * SRC_STATUS
415 * SRC_INT_EN
416 * SCU_SYS_STATUS0
417 * SCU_SYS_STATUS1
418 * SCU_SYS_INT_EN0
419 * SCU_SYS_INT_EN1
420 */
406 }; 421 };
407 struct rsnd_regmap_field_conf conf_adg[] = { 422 struct rsnd_regmap_field_conf conf_adg[] = {
408 RSND_GEN_S_REG(BRRA, 0x00), 423 RSND_GEN_S_REG(BRRA, 0x00),
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 5826c8abf794..c45700380e59 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -44,6 +44,8 @@ enum rsnd_reg {
44 RSND_REG_SRC_IFSCR, 44 RSND_REG_SRC_IFSCR,
45 RSND_REG_SRC_IFSVR, 45 RSND_REG_SRC_IFSVR,
46 RSND_REG_SRC_SRCCR, 46 RSND_REG_SRC_SRCCR,
47 RSND_REG_SCU_SYS_STATUS0,
48 RSND_REG_SCU_SYS_INT_EN0,
47 RSND_REG_CMD_ROUTE_SLCT, 49 RSND_REG_CMD_ROUTE_SLCT,
48 RSND_REG_DVC_SWRSR, 50 RSND_REG_DVC_SWRSR,
49 RSND_REG_DVC_DVUIR, 51 RSND_REG_DVC_DVUIR,
@@ -94,6 +96,9 @@ enum rsnd_reg {
94 RSND_REG_SHARE23, 96 RSND_REG_SHARE23,
95 RSND_REG_SHARE24, 97 RSND_REG_SHARE24,
96 RSND_REG_SHARE25, 98 RSND_REG_SHARE25,
99 RSND_REG_SHARE26,
100 RSND_REG_SHARE27,
101 RSND_REG_SHARE28,
97 102
98 RSND_REG_MAX, 103 RSND_REG_MAX,
99}; 104};
@@ -135,6 +140,9 @@ enum rsnd_reg {
135#define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 140#define RSND_REG_DVC_VRCTR RSND_REG_SHARE23
136#define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 141#define RSND_REG_DVC_VRPDR RSND_REG_SHARE24
137#define RSND_REG_DVC_VRDBR RSND_REG_SHARE25 142#define RSND_REG_DVC_VRDBR RSND_REG_SHARE25
143#define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26
144#define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27
145#define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28
138 146
139struct rsnd_of_data; 147struct rsnd_of_data;
140struct rsnd_priv; 148struct rsnd_priv;
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index eede3ac6eed2..648b35e7effc 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -12,10 +12,18 @@
12 12
13#define SRC_NAME "src" 13#define SRC_NAME "src"
14 14
15/* SRCx_STATUS */
16#define OUF_SRCO ((1 << 12) | (1 << 13))
17#define OUF_SRCI ((1 << 9) | (1 << 8))
18
19/* SCU_SYSTEM_STATUS0/1 */
20#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id))
21
15struct rsnd_src { 22struct rsnd_src {
16 struct rsnd_src_platform_info *info; /* rcar_snd.h */ 23 struct rsnd_src_platform_info *info; /* rcar_snd.h */
17 struct rsnd_mod mod; 24 struct rsnd_mod mod;
18 struct clk *clk; 25 struct clk *clk;
26 int err;
19}; 27};
20 28
21#define RSND_SRC_NAME_SIZE 16 29#define RSND_SRC_NAME_SIZE 16
@@ -280,6 +288,8 @@ static int rsnd_src_init(struct rsnd_mod *mod,
280 288
281 clk_prepare_enable(src->clk); 289 clk_prepare_enable(src->clk);
282 290
291 src->err = 0;
292
283 /* 293 /*
284 * Initialize the operation of the SRC internal circuits 294 * Initialize the operation of the SRC internal circuits
285 * see rsnd_src_start() 295 * see rsnd_src_start()
@@ -293,9 +303,14 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
293 struct rsnd_dai *rdai) 303 struct rsnd_dai *rdai)
294{ 304{
295 struct rsnd_src *src = rsnd_mod_to_src(mod); 305 struct rsnd_src *src = rsnd_mod_to_src(mod);
306 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
307 struct device *dev = rsnd_priv_to_dev(priv);
296 308
297 clk_disable_unprepare(src->clk); 309 clk_disable_unprepare(src->clk);
298 310
311 if (src->err)
312 dev_warn(dev, "src under/over flow err = %d\n", src->err);
313
299 return 0; 314 return 0;
300} 315}
301 316
@@ -510,6 +525,110 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = {
510/* 525/*
511 * Gen2 functions 526 * Gen2 functions
512 */ 527 */
528#define rsnd_src_irq_enable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 1)
529#define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0)
530static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
531{
532 struct rsnd_src *src = rsnd_mod_to_src(mod);
533 u32 sys_int_val, int_val, sys_int_mask;
534 int irq = src->info->irq;
535 int id = rsnd_mod_id(mod);
536
537 sys_int_val =
538 sys_int_mask = OUF_SRC(id);
539 int_val = 0x3300;
540
541 /*
542 * IRQ is not supported on non-DT
543 * see
544 * rsnd_src_probe_gen2()
545 */
546 if ((irq <= 0) || !enable) {
547 sys_int_val = 0;
548 int_val = 0;
549 }
550
551 rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
552 rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
553 rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
554}
555
556static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
557{
558 u32 val = OUF_SRC(rsnd_mod_id(mod));
559
560 rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val);
561 rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
562}
563
564static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
565{
566 u32 val = OUF_SRC(rsnd_mod_id(mod));
567 bool ret = false;
568
569 if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) ||
570 (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) {
571 struct rsnd_src *src = rsnd_mod_to_src(mod);
572
573 src->err++;
574 ret = true;
575 }
576
577 /* clear error static */
578 rsnd_src_error_clear_gen2(mod);
579
580 return ret;
581}
582
583static int _rsnd_src_start_gen2(struct rsnd_mod *mod)
584{
585 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
586 u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
587
588 rsnd_mod_write(mod, SRC_CTRL, val);
589
590 rsnd_src_error_clear_gen2(mod);
591
592 rsnd_src_start(mod);
593
594 rsnd_src_irq_enable_gen2(mod);
595
596 return 0;
597}
598
599static int _rsnd_src_stop_gen2(struct rsnd_mod *mod)
600{
601 rsnd_src_irq_disable_gen2(mod);
602
603 rsnd_mod_write(mod, SRC_CTRL, 0);
604
605 rsnd_src_error_record_gen2(mod);
606
607 return rsnd_src_stop(mod);
608}
609
610static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
611{
612 struct rsnd_mod *mod = data;
613 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
614
615 if (!io)
616 return IRQ_NONE;
617
618 if (rsnd_src_error_record_gen2(mod)) {
619 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
620 struct device *dev = rsnd_priv_to_dev(priv);
621
622 _rsnd_src_stop_gen2(mod);
623 _rsnd_src_start_gen2(mod);
624
625 dev_dbg(dev, "%s[%d] restart\n",
626 rsnd_mod_name(mod), rsnd_mod_id(mod));
627 }
628
629 return IRQ_HANDLED;
630}
631
513static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, 632static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
514 struct rsnd_dai *rdai) 633 struct rsnd_dai *rdai)
515{ 634{
@@ -588,18 +707,38 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
588 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 707 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
589 struct rsnd_src *src = rsnd_mod_to_src(mod); 708 struct rsnd_src *src = rsnd_mod_to_src(mod);
590 struct device *dev = rsnd_priv_to_dev(priv); 709 struct device *dev = rsnd_priv_to_dev(priv);
710 int irq = src->info->irq;
591 int ret; 711 int ret;
592 712
713 if (irq > 0) {
714 /*
715 * IRQ is not supported on non-DT
716 * see
717 * rsnd_src_irq_enable_gen2()
718 */
719 ret = devm_request_irq(dev, irq,
720 rsnd_src_interrupt_gen2,
721 IRQF_SHARED,
722 dev_name(dev), mod);
723 if (ret)
724 goto rsnd_src_probe_gen2_fail;
725 }
726
593 ret = rsnd_dma_init(priv, 727 ret = rsnd_dma_init(priv,
594 rsnd_mod_to_dma(mod), 728 rsnd_mod_to_dma(mod),
595 rsnd_info_is_playback(priv, src), 729 rsnd_info_is_playback(priv, src),
596 src->info->dma_id); 730 src->info->dma_id);
597 if (ret < 0) 731 if (ret)
598 dev_err(dev, "%s[%d] (Gen2) failed\n", 732 goto rsnd_src_probe_gen2_fail;
599 rsnd_mod_name(mod), rsnd_mod_id(mod)); 733
600 else 734 dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
601 dev_dbg(dev, "%s[%d] (Gen2) is probed\n", 735 rsnd_mod_name(mod), rsnd_mod_id(mod));
602 rsnd_mod_name(mod), rsnd_mod_id(mod)); 736
737 return ret;
738
739rsnd_src_probe_gen2_fail:
740 dev_err(dev, "%s[%d] (Gen2) failed\n",
741 rsnd_mod_name(mod), rsnd_mod_id(mod));
603 742
604 return ret; 743 return ret;
605} 744}
@@ -635,27 +774,21 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod,
635static int rsnd_src_start_gen2(struct rsnd_mod *mod, 774static int rsnd_src_start_gen2(struct rsnd_mod *mod,
636 struct rsnd_dai *rdai) 775 struct rsnd_dai *rdai)
637{ 776{
638 struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); 777 rsnd_dma_start(rsnd_mod_to_dma(mod));
639 struct rsnd_src *src = rsnd_mod_to_src(mod);
640 u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
641
642 rsnd_dma_start(rsnd_mod_to_dma(&src->mod));
643 778
644 rsnd_mod_write(mod, SRC_CTRL, val); 779 return _rsnd_src_start_gen2(mod);
645
646 return rsnd_src_start(mod);
647} 780}
648 781
649static int rsnd_src_stop_gen2(struct rsnd_mod *mod, 782static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
650 struct rsnd_dai *rdai) 783 struct rsnd_dai *rdai)
651{ 784{
652 struct rsnd_src *src = rsnd_mod_to_src(mod); 785 int ret;
653 786
654 rsnd_mod_write(mod, SRC_CTRL, 0); 787 ret = _rsnd_src_stop_gen2(mod);
655 788
656 rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); 789 rsnd_dma_stop(rsnd_mod_to_dma(mod));
657 790
658 return rsnd_src_stop(mod); 791 return ret;
659} 792}
660 793
661static struct rsnd_mod_ops rsnd_src_gen2_ops = { 794static struct rsnd_mod_ops rsnd_src_gen2_ops = {
@@ -681,10 +814,11 @@ static void rsnd_of_parse_src(struct platform_device *pdev,
681 struct rsnd_priv *priv) 814 struct rsnd_priv *priv)
682{ 815{
683 struct device_node *src_node; 816 struct device_node *src_node;
817 struct device_node *np;
684 struct rcar_snd_info *info = rsnd_priv_to_info(priv); 818 struct rcar_snd_info *info = rsnd_priv_to_info(priv);
685 struct rsnd_src_platform_info *src_info; 819 struct rsnd_src_platform_info *src_info;
686 struct device *dev = &pdev->dev; 820 struct device *dev = &pdev->dev;
687 int nr; 821 int nr, i;
688 822
689 if (!of_data) 823 if (!of_data)
690 return; 824 return;
@@ -708,6 +842,13 @@ static void rsnd_of_parse_src(struct platform_device *pdev,
708 info->src_info = src_info; 842 info->src_info = src_info;
709 info->src_info_nr = nr; 843 info->src_info_nr = nr;
710 844
845 i = 0;
846 for_each_child_of_node(src_node, np) {
847 src_info[i].irq = irq_of_parse_and_map(np, 0);
848
849 i++;
850 }
851
711rsnd_of_parse_src_end: 852rsnd_of_parse_src_end:
712 of_node_put(src_node); 853 of_node_put(src_node);
713} 854}