diff options
Diffstat (limited to 'sound/soc/pxa/pxa-ssp.c')
-rw-r--r-- | sound/soc/pxa/pxa-ssp.c | 150 |
1 files changed, 81 insertions, 69 deletions
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 1dfdf66fb1f3..7acd3febf8b0 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define DEBUG | ||
2 | /* | 1 | /* |
3 | * pxa-ssp.c -- ALSA Soc Audio Layer | 2 | * pxa-ssp.c -- ALSA Soc Audio Layer |
4 | * | 3 | * |
@@ -21,6 +20,8 @@ | |||
21 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
22 | #include <linux/io.h> | 21 | #include <linux/io.h> |
23 | 22 | ||
23 | #include <asm/irq.h> | ||
24 | |||
24 | #include <sound/core.h> | 25 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
26 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
@@ -221,9 +222,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, | |||
221 | int ret = 0; | 222 | int ret = 0; |
222 | 223 | ||
223 | if (!cpu_dai->active) { | 224 | if (!cpu_dai->active) { |
224 | ret = ssp_init(&priv->dev, cpu_dai->id + 1, SSP_NO_IRQ); | 225 | priv->dev.port = cpu_dai->id + 1; |
225 | if (ret < 0) | 226 | priv->dev.irq = NO_IRQ; |
226 | return ret; | 227 | clk_enable(priv->dev.ssp->clk); |
227 | ssp_disable(&priv->dev); | 228 | ssp_disable(&priv->dev); |
228 | } | 229 | } |
229 | return ret; | 230 | return ret; |
@@ -238,7 +239,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, | |||
238 | 239 | ||
239 | if (!cpu_dai->active) { | 240 | if (!cpu_dai->active) { |
240 | ssp_disable(&priv->dev); | 241 | ssp_disable(&priv->dev); |
241 | ssp_exit(&priv->dev); | 242 | clk_disable(priv->dev.ssp->clk); |
242 | } | 243 | } |
243 | } | 244 | } |
244 | 245 | ||
@@ -298,7 +299,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
298 | int val; | 299 | int val; |
299 | 300 | ||
300 | u32 sscr0 = ssp_read_reg(ssp, SSCR0) & | 301 | u32 sscr0 = ssp_read_reg(ssp, SSCR0) & |
301 | ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); | 302 | ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS); |
302 | 303 | ||
303 | dev_dbg(&ssp->pdev->dev, | 304 | dev_dbg(&ssp->pdev->dev, |
304 | "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", | 305 | "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", |
@@ -326,7 +327,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
326 | case PXA_SSP_CLK_AUDIO: | 327 | case PXA_SSP_CLK_AUDIO: |
327 | priv->sysclk = 0; | 328 | priv->sysclk = 0; |
328 | ssp_set_scr(&priv->dev, 1); | 329 | ssp_set_scr(&priv->dev, 1); |
329 | sscr0 |= SSCR0_ADC; | 330 | sscr0 |= SSCR0_ACS; |
330 | break; | 331 | break; |
331 | default: | 332 | default: |
332 | return -ENODEV; | 333 | return -ENODEV; |
@@ -520,9 +521,20 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
520 | u32 sscr1; | 521 | u32 sscr1; |
521 | u32 sspsp; | 522 | u32 sspsp; |
522 | 523 | ||
524 | /* check if we need to change anything at all */ | ||
525 | if (priv->dai_fmt == fmt) | ||
526 | return 0; | ||
527 | |||
528 | /* we can only change the settings if the port is not in use */ | ||
529 | if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) { | ||
530 | dev_err(&ssp->pdev->dev, | ||
531 | "can't change hardware dai format: stream is in use"); | ||
532 | return -EINVAL; | ||
533 | } | ||
534 | |||
523 | /* reset port settings */ | 535 | /* reset port settings */ |
524 | sscr0 = ssp_read_reg(ssp, SSCR0) & | 536 | sscr0 = ssp_read_reg(ssp, SSCR0) & |
525 | (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); | 537 | (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS); |
526 | sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); | 538 | sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); |
527 | sspsp = 0; | 539 | sspsp = 0; |
528 | 540 | ||
@@ -545,18 +557,18 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
545 | 557 | ||
546 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 558 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
547 | case SND_SOC_DAIFMT_I2S: | 559 | case SND_SOC_DAIFMT_I2S: |
548 | sscr0 |= SSCR0_MOD | SSCR0_PSP; | 560 | sscr0 |= SSCR0_PSP; |
549 | sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; | 561 | sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; |
550 | 562 | ||
563 | /* See hw_params() */ | ||
551 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 564 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
552 | case SND_SOC_DAIFMT_NB_NF: | 565 | case SND_SOC_DAIFMT_NB_NF: |
553 | sspsp |= SSPSP_FSRT; | 566 | sspsp |= SSPSP_SFRMP; |
554 | break; | 567 | break; |
555 | case SND_SOC_DAIFMT_NB_IF: | 568 | case SND_SOC_DAIFMT_NB_IF: |
556 | sspsp |= SSPSP_SFRMP | SSPSP_FSRT; | ||
557 | break; | 569 | break; |
558 | case SND_SOC_DAIFMT_IB_IF: | 570 | case SND_SOC_DAIFMT_IB_IF: |
559 | sspsp |= SSPSP_SFRMP; | 571 | sspsp |= SSPSP_SCMODE(3); |
560 | break; | 572 | break; |
561 | default: | 573 | default: |
562 | return -EINVAL; | 574 | return -EINVAL; |
@@ -642,34 +654,65 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, | |||
642 | sscr0 |= SSCR0_FPCKE; | 654 | sscr0 |= SSCR0_FPCKE; |
643 | #endif | 655 | #endif |
644 | sscr0 |= SSCR0_DataSize(16); | 656 | sscr0 |= SSCR0_DataSize(16); |
645 | if (params_channels(params) > 1) | ||
646 | sscr0 |= SSCR0_EDSS; | ||
647 | break; | 657 | break; |
648 | case SNDRV_PCM_FORMAT_S24_LE: | 658 | case SNDRV_PCM_FORMAT_S24_LE: |
649 | sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); | 659 | sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); |
650 | /* we must be in network mode (2 slots) for 24 bit stereo */ | ||
651 | break; | 660 | break; |
652 | case SNDRV_PCM_FORMAT_S32_LE: | 661 | case SNDRV_PCM_FORMAT_S32_LE: |
653 | sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); | 662 | sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); |
654 | /* we must be in network mode (2 slots) for 32 bit stereo */ | ||
655 | break; | 663 | break; |
656 | } | 664 | } |
657 | ssp_write_reg(ssp, SSCR0, sscr0); | 665 | ssp_write_reg(ssp, SSCR0, sscr0); |
658 | 666 | ||
659 | switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 667 | switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
660 | case SND_SOC_DAIFMT_I2S: | 668 | case SND_SOC_DAIFMT_I2S: |
661 | /* Cleared when the DAI format is set */ | 669 | sspsp = ssp_read_reg(ssp, SSPSP); |
662 | sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width); | 670 | |
671 | if (((sscr0 & SSCR0_SCR) == SSCR0_SerClkDiv(4)) && | ||
672 | (width == 16)) { | ||
673 | /* This is a special case where the bitclk is 64fs | ||
674 | * and we're not dealing with 2*32 bits of audio | ||
675 | * samples. | ||
676 | * | ||
677 | * The SSP values used for that are all found out by | ||
678 | * trying and failing a lot; some of the registers | ||
679 | * needed for that mode are only available on PXA3xx. | ||
680 | */ | ||
681 | |||
682 | #ifdef CONFIG_PXA3xx | ||
683 | if (!cpu_is_pxa3xx()) | ||
684 | return -EINVAL; | ||
685 | |||
686 | sspsp |= SSPSP_SFRMWDTH(width * 2); | ||
687 | sspsp |= SSPSP_SFRMDLY(width * 4); | ||
688 | sspsp |= SSPSP_EDMYSTOP(3); | ||
689 | sspsp |= SSPSP_DMYSTOP(3); | ||
690 | sspsp |= SSPSP_DMYSTRT(1); | ||
691 | #else | ||
692 | return -EINVAL; | ||
693 | #endif | ||
694 | } else { | ||
695 | /* The frame width is the width the LRCLK is | ||
696 | * asserted for; the delay is expressed in | ||
697 | * half cycle units. We need the extra cycle | ||
698 | * because the data starts clocking out one BCLK | ||
699 | * after LRCLK changes polarity. | ||
700 | */ | ||
701 | sspsp |= SSPSP_SFRMWDTH(width + 1); | ||
702 | sspsp |= SSPSP_SFRMDLY((width + 1) * 2); | ||
703 | sspsp |= SSPSP_DMYSTRT(1); | ||
704 | } | ||
705 | |||
663 | ssp_write_reg(ssp, SSPSP, sspsp); | 706 | ssp_write_reg(ssp, SSPSP, sspsp); |
664 | break; | 707 | break; |
665 | default: | 708 | default: |
666 | break; | 709 | break; |
667 | } | 710 | } |
668 | 711 | ||
669 | /* We always use a network mode so we always require TDM slots | 712 | /* When we use a network mode, we always require TDM slots |
670 | * - complain loudly and fail if they've not been set up yet. | 713 | * - complain loudly and fail if they've not been set up yet. |
671 | */ | 714 | */ |
672 | if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) { | 715 | if ((sscr0 & SSCR0_MOD) && !(ssp_read_reg(ssp, SSTSA) & 0xf)) { |
673 | dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); | 716 | dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); |
674 | return -EINVAL; | 717 | return -EINVAL; |
675 | } | 718 | } |
@@ -751,7 +794,7 @@ static int pxa_ssp_probe(struct platform_device *pdev, | |||
751 | if (!priv) | 794 | if (!priv) |
752 | return -ENOMEM; | 795 | return -ENOMEM; |
753 | 796 | ||
754 | priv->dev.ssp = ssp_request(dai->id, "SoC audio"); | 797 | priv->dev.ssp = ssp_request(dai->id + 1, "SoC audio"); |
755 | if (priv->dev.ssp == NULL) { | 798 | if (priv->dev.ssp == NULL) { |
756 | ret = -ENODEV; | 799 | ret = -ENODEV; |
757 | goto err_priv; | 800 | goto err_priv; |
@@ -782,6 +825,19 @@ static void pxa_ssp_remove(struct platform_device *pdev, | |||
782 | SNDRV_PCM_FMTBIT_S24_LE | \ | 825 | SNDRV_PCM_FMTBIT_S24_LE | \ |
783 | SNDRV_PCM_FMTBIT_S32_LE) | 826 | SNDRV_PCM_FMTBIT_S32_LE) |
784 | 827 | ||
828 | static struct snd_soc_dai_ops pxa_ssp_dai_ops = { | ||
829 | .startup = pxa_ssp_startup, | ||
830 | .shutdown = pxa_ssp_shutdown, | ||
831 | .trigger = pxa_ssp_trigger, | ||
832 | .hw_params = pxa_ssp_hw_params, | ||
833 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
834 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
835 | .set_pll = pxa_ssp_set_dai_pll, | ||
836 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
837 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
838 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
839 | }; | ||
840 | |||
785 | struct snd_soc_dai pxa_ssp_dai[] = { | 841 | struct snd_soc_dai pxa_ssp_dai[] = { |
786 | { | 842 | { |
787 | .name = "pxa2xx-ssp1", | 843 | .name = "pxa2xx-ssp1", |
@@ -802,18 +858,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
802 | .rates = PXA_SSP_RATES, | 858 | .rates = PXA_SSP_RATES, |
803 | .formats = PXA_SSP_FORMATS, | 859 | .formats = PXA_SSP_FORMATS, |
804 | }, | 860 | }, |
805 | .ops = { | 861 | .ops = &pxa_ssp_dai_ops, |
806 | .startup = pxa_ssp_startup, | ||
807 | .shutdown = pxa_ssp_shutdown, | ||
808 | .trigger = pxa_ssp_trigger, | ||
809 | .hw_params = pxa_ssp_hw_params, | ||
810 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
811 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
812 | .set_pll = pxa_ssp_set_dai_pll, | ||
813 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
814 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
815 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
816 | }, | ||
817 | }, | 862 | }, |
818 | { .name = "pxa2xx-ssp2", | 863 | { .name = "pxa2xx-ssp2", |
819 | .id = 1, | 864 | .id = 1, |
@@ -833,18 +878,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
833 | .rates = PXA_SSP_RATES, | 878 | .rates = PXA_SSP_RATES, |
834 | .formats = PXA_SSP_FORMATS, | 879 | .formats = PXA_SSP_FORMATS, |
835 | }, | 880 | }, |
836 | .ops = { | 881 | .ops = &pxa_ssp_dai_ops, |
837 | .startup = pxa_ssp_startup, | ||
838 | .shutdown = pxa_ssp_shutdown, | ||
839 | .trigger = pxa_ssp_trigger, | ||
840 | .hw_params = pxa_ssp_hw_params, | ||
841 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
842 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
843 | .set_pll = pxa_ssp_set_dai_pll, | ||
844 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
845 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
846 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
847 | }, | ||
848 | }, | 882 | }, |
849 | { | 883 | { |
850 | .name = "pxa2xx-ssp3", | 884 | .name = "pxa2xx-ssp3", |
@@ -865,18 +899,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
865 | .rates = PXA_SSP_RATES, | 899 | .rates = PXA_SSP_RATES, |
866 | .formats = PXA_SSP_FORMATS, | 900 | .formats = PXA_SSP_FORMATS, |
867 | }, | 901 | }, |
868 | .ops = { | 902 | .ops = &pxa_ssp_dai_ops, |
869 | .startup = pxa_ssp_startup, | ||
870 | .shutdown = pxa_ssp_shutdown, | ||
871 | .trigger = pxa_ssp_trigger, | ||
872 | .hw_params = pxa_ssp_hw_params, | ||
873 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
874 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
875 | .set_pll = pxa_ssp_set_dai_pll, | ||
876 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
877 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
878 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
879 | }, | ||
880 | }, | 903 | }, |
881 | { | 904 | { |
882 | .name = "pxa2xx-ssp4", | 905 | .name = "pxa2xx-ssp4", |
@@ -897,18 +920,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { | |||
897 | .rates = PXA_SSP_RATES, | 920 | .rates = PXA_SSP_RATES, |
898 | .formats = PXA_SSP_FORMATS, | 921 | .formats = PXA_SSP_FORMATS, |
899 | }, | 922 | }, |
900 | .ops = { | 923 | .ops = &pxa_ssp_dai_ops, |
901 | .startup = pxa_ssp_startup, | ||
902 | .shutdown = pxa_ssp_shutdown, | ||
903 | .trigger = pxa_ssp_trigger, | ||
904 | .hw_params = pxa_ssp_hw_params, | ||
905 | .set_sysclk = pxa_ssp_set_dai_sysclk, | ||
906 | .set_clkdiv = pxa_ssp_set_dai_clkdiv, | ||
907 | .set_pll = pxa_ssp_set_dai_pll, | ||
908 | .set_fmt = pxa_ssp_set_dai_fmt, | ||
909 | .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, | ||
910 | .set_tristate = pxa_ssp_set_dai_tristate, | ||
911 | }, | ||
912 | }, | 924 | }, |
913 | }; | 925 | }; |
914 | EXPORT_SYMBOL_GPL(pxa_ssp_dai); | 926 | EXPORT_SYMBOL_GPL(pxa_ssp_dai); |