aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/samsung/i2s.c81
1 files changed, 51 insertions, 30 deletions
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 20cc51fc76ae..05fc2f0e91ca 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -472,17 +472,22 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
472{ 472{
473 struct i2s_dai *i2s = to_info(dai); 473 struct i2s_dai *i2s = to_info(dai);
474 struct i2s_dai *other = get_other_dai(i2s); 474 struct i2s_dai *other = get_other_dai(i2s);
475 u32 mod = readl(i2s->addr + I2SMOD);
476 const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; 475 const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
477 unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; 476 unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
478 unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; 477 unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
478 u32 mod, mask, val = 0;
479
480 spin_lock(i2s->lock);
481 mod = readl(i2s->addr + I2SMOD);
482 spin_unlock(i2s->lock);
479 483
480 switch (clk_id) { 484 switch (clk_id) {
481 case SAMSUNG_I2S_OPCLK: 485 case SAMSUNG_I2S_OPCLK:
482 mod &= ~MOD_OPCLK_MASK; 486 mask = MOD_OPCLK_MASK;
483 mod |= dir; 487 val = dir;
484 break; 488 break;
485 case SAMSUNG_I2S_CDCLK: 489 case SAMSUNG_I2S_CDCLK:
490 mask = 1 << i2s_regs->cdclkcon_off;
486 /* Shouldn't matter in GATING(CLOCK_IN) mode */ 491 /* Shouldn't matter in GATING(CLOCK_IN) mode */
487 if (dir == SND_SOC_CLOCK_IN) 492 if (dir == SND_SOC_CLOCK_IN)
488 rfs = 0; 493 rfs = 0;
@@ -499,15 +504,15 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
499 } 504 }
500 505
501 if (dir == SND_SOC_CLOCK_IN) 506 if (dir == SND_SOC_CLOCK_IN)
502 mod |= 1 << i2s_regs->cdclkcon_off; 507 val = 1 << i2s_regs->cdclkcon_off;
503 else
504 mod &= ~(1 << i2s_regs->cdclkcon_off);
505 508
506 i2s->rfs = rfs; 509 i2s->rfs = rfs;
507 break; 510 break;
508 511
509 case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */ 512 case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
510 case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */ 513 case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
514 mask = 1 << i2s_regs->rclksrc_off;
515
511 if ((i2s->quirks & QUIRK_NO_MUXPSR) 516 if ((i2s->quirks & QUIRK_NO_MUXPSR)
512 || (clk_id == SAMSUNG_I2S_RCLKSRC_0)) 517 || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
513 clk_id = 0; 518 clk_id = 0;
@@ -557,18 +562,19 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
557 return 0; 562 return 0;
558 } 563 }
559 564
560 if (clk_id == 0) 565 if (clk_id == 1)
561 mod &= ~(1 << i2s_regs->rclksrc_off); 566 val = 1 << i2s_regs->rclksrc_off;
562 else
563 mod |= 1 << i2s_regs->rclksrc_off;
564
565 break; 567 break;
566 default: 568 default:
567 dev_err(&i2s->pdev->dev, "We don't serve that!\n"); 569 dev_err(&i2s->pdev->dev, "We don't serve that!\n");
568 return -EINVAL; 570 return -EINVAL;
569 } 571 }
570 572
573 spin_lock(i2s->lock);
574 mod = readl(i2s->addr + I2SMOD);
575 mod = (mod & ~mask) | val;
571 writel(mod, i2s->addr + I2SMOD); 576 writel(mod, i2s->addr + I2SMOD);
577 spin_unlock(i2s->lock);
572 578
573 return 0; 579 return 0;
574} 580}
@@ -577,9 +583,8 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
577 unsigned int fmt) 583 unsigned int fmt)
578{ 584{
579 struct i2s_dai *i2s = to_info(dai); 585 struct i2s_dai *i2s = to_info(dai);
580 u32 mod = readl(i2s->addr + I2SMOD);
581 int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; 586 int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
582 u32 tmp = 0; 587 u32 mod, tmp = 0;
583 588
584 lrp_shift = i2s->variant_regs->lrp_off; 589 lrp_shift = i2s->variant_regs->lrp_off;
585 sdf_shift = i2s->variant_regs->sdf_off; 590 sdf_shift = i2s->variant_regs->sdf_off;
@@ -639,12 +644,15 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
639 return -EINVAL; 644 return -EINVAL;
640 } 645 }
641 646
647 spin_lock(i2s->lock);
648 mod = readl(i2s->addr + I2SMOD);
642 /* 649 /*
643 * Don't change the I2S mode if any controller is active on this 650 * Don't change the I2S mode if any controller is active on this
644 * channel. 651 * channel.
645 */ 652 */
646 if (any_active(i2s) && 653 if (any_active(i2s) &&
647 ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { 654 ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
655 spin_unlock(i2s->lock);
648 dev_err(&i2s->pdev->dev, 656 dev_err(&i2s->pdev->dev,
649 "%s:%d Other DAI busy\n", __func__, __LINE__); 657 "%s:%d Other DAI busy\n", __func__, __LINE__);
650 return -EAGAIN; 658 return -EAGAIN;
@@ -653,6 +661,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
653 mod &= ~(sdf_mask | lrp_rlow | mod_slave); 661 mod &= ~(sdf_mask | lrp_rlow | mod_slave);
654 mod |= tmp; 662 mod |= tmp;
655 writel(mod, i2s->addr + I2SMOD); 663 writel(mod, i2s->addr + I2SMOD);
664 spin_unlock(i2s->lock);
656 665
657 return 0; 666 return 0;
658} 667}
@@ -661,16 +670,16 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
661 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 670 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
662{ 671{
663 struct i2s_dai *i2s = to_info(dai); 672 struct i2s_dai *i2s = to_info(dai);
664 u32 mod = readl(i2s->addr + I2SMOD); 673 u32 mod, mask = 0, val = 0;
665 674
666 if (!is_secondary(i2s)) 675 if (!is_secondary(i2s))
667 mod &= ~(MOD_DC2_EN | MOD_DC1_EN); 676 mask |= (MOD_DC2_EN | MOD_DC1_EN);
668 677
669 switch (params_channels(params)) { 678 switch (params_channels(params)) {
670 case 6: 679 case 6:
671 mod |= MOD_DC2_EN; 680 val |= MOD_DC2_EN;
672 case 4: 681 case 4:
673 mod |= MOD_DC1_EN; 682 val |= MOD_DC1_EN;
674 break; 683 break;
675 case 2: 684 case 2:
676 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 685 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -692,44 +701,49 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
692 } 701 }
693 702
694 if (is_secondary(i2s)) 703 if (is_secondary(i2s))
695 mod &= ~MOD_BLCS_MASK; 704 mask |= MOD_BLCS_MASK;
696 else 705 else
697 mod &= ~MOD_BLCP_MASK; 706 mask |= MOD_BLCP_MASK;
698 707
699 if (is_manager(i2s)) 708 if (is_manager(i2s))
700 mod &= ~MOD_BLC_MASK; 709 mask |= MOD_BLC_MASK;
701 710
702 switch (params_width(params)) { 711 switch (params_width(params)) {
703 case 8: 712 case 8:
704 if (is_secondary(i2s)) 713 if (is_secondary(i2s))
705 mod |= MOD_BLCS_8BIT; 714 val |= MOD_BLCS_8BIT;
706 else 715 else
707 mod |= MOD_BLCP_8BIT; 716 val |= MOD_BLCP_8BIT;
708 if (is_manager(i2s)) 717 if (is_manager(i2s))
709 mod |= MOD_BLC_8BIT; 718 val |= MOD_BLC_8BIT;
710 break; 719 break;
711 case 16: 720 case 16:
712 if (is_secondary(i2s)) 721 if (is_secondary(i2s))
713 mod |= MOD_BLCS_16BIT; 722 val |= MOD_BLCS_16BIT;
714 else 723 else
715 mod |= MOD_BLCP_16BIT; 724 val |= MOD_BLCP_16BIT;
716 if (is_manager(i2s)) 725 if (is_manager(i2s))
717 mod |= MOD_BLC_16BIT; 726 val |= MOD_BLC_16BIT;
718 break; 727 break;
719 case 24: 728 case 24:
720 if (is_secondary(i2s)) 729 if (is_secondary(i2s))
721 mod |= MOD_BLCS_24BIT; 730 val |= MOD_BLCS_24BIT;
722 else 731 else
723 mod |= MOD_BLCP_24BIT; 732 val |= MOD_BLCP_24BIT;
724 if (is_manager(i2s)) 733 if (is_manager(i2s))
725 mod |= MOD_BLC_24BIT; 734 val |= MOD_BLC_24BIT;
726 break; 735 break;
727 default: 736 default:
728 dev_err(&i2s->pdev->dev, "Format(%d) not supported\n", 737 dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
729 params_format(params)); 738 params_format(params));
730 return -EINVAL; 739 return -EINVAL;
731 } 740 }
741
742 spin_lock(i2s->lock);
743 mod = readl(i2s->addr + I2SMOD);
744 mod = (mod & ~mask) | val;
732 writel(mod, i2s->addr + I2SMOD); 745 writel(mod, i2s->addr + I2SMOD);
746 spin_unlock(i2s->lock);
733 747
734 samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); 748 samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
735 749
@@ -979,6 +993,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
979{ 993{
980 struct i2s_dai *i2s = to_info(dai); 994 struct i2s_dai *i2s = to_info(dai);
981 struct i2s_dai *other = get_other_dai(i2s); 995 struct i2s_dai *other = get_other_dai(i2s);
996 unsigned long flags;
982 997
983 if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */ 998 if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */
984 samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, 999 samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
@@ -999,11 +1014,14 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
999 i2s->rfs = 0; 1014 i2s->rfs = 0;
1000 i2s->bfs = 0; 1015 i2s->bfs = 0;
1001 i2s->rclk_srcrate = 0; 1016 i2s->rclk_srcrate = 0;
1017
1018 spin_lock_irqsave(i2s->lock, flags);
1002 i2s_txctrl(i2s, 0); 1019 i2s_txctrl(i2s, 0);
1003 i2s_rxctrl(i2s, 0); 1020 i2s_rxctrl(i2s, 0);
1004 i2s_fifo(i2s, FIC_TXFLUSH); 1021 i2s_fifo(i2s, FIC_TXFLUSH);
1005 i2s_fifo(other, FIC_TXFLUSH); 1022 i2s_fifo(other, FIC_TXFLUSH);
1006 i2s_fifo(i2s, FIC_RXFLUSH); 1023 i2s_fifo(i2s, FIC_RXFLUSH);
1024 spin_unlock_irqrestore(i2s->lock, flags);
1007 1025
1008 /* Gate CDCLK by default */ 1026 /* Gate CDCLK by default */
1009 if (!is_opened(other)) 1027 if (!is_opened(other))
@@ -1018,8 +1036,11 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
1018 struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); 1036 struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
1019 1037
1020 if (!is_secondary(i2s)) { 1038 if (!is_secondary(i2s)) {
1021 if (i2s->quirks & QUIRK_NEED_RSTCLR) 1039 if (i2s->quirks & QUIRK_NEED_RSTCLR) {
1040 spin_lock(i2s->lock);
1022 writel(0, i2s->addr + I2SCON); 1041 writel(0, i2s->addr + I2SCON);
1042 spin_unlock(i2s->lock);
1043 }
1023 } 1044 }
1024 1045
1025 return 0; 1046 return 0;