aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/pxa/pxa-ssp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/pxa/pxa-ssp.c')
-rw-r--r--sound/soc/pxa/pxa-ssp.c150
1 files changed, 81 insertions, 69 deletions
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 73cb6b4c2f2d..b0bf40973d5b 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
828static 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
785struct snd_soc_dai pxa_ssp_dai[] = { 841struct 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};
914EXPORT_SYMBOL_GPL(pxa_ssp_dai); 926EXPORT_SYMBOL_GPL(pxa_ssp_dai);