diff options
-rw-r--r-- | sound/soc/samsung/i2s.c | 81 |
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; |