aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/imx/imx-ssi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/imx/imx-ssi.c')
-rw-r--r--sound/soc/imx/imx-ssi.c182
1 files changed, 93 insertions, 89 deletions
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index c81da05a4f11..61fceb09cdb5 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -16,7 +16,7 @@
16 * sane processor vendors have a FIFO per AC97 slot, the i.MX has only 16 * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
17 * one FIFO which combines all valid receive slots. We cannot even select 17 * one FIFO which combines all valid receive slots. We cannot even select
18 * which slots we want to receive. The WM9712 with which this driver 18 * which slots we want to receive. The WM9712 with which this driver
19 * was developped with always sends GPIO status data in slot 12 which 19 * was developed with always sends GPIO status data in slot 12 which
20 * we receive in our (PCM-) data stream. The only chance we have is to 20 * we receive in our (PCM-) data stream. The only chance we have is to
21 * manually skip this data in the FIQ handler. With sampling rates different 21 * manually skip this data in the FIQ handler. With sampling rates different
22 * from 48000Hz not every frame has valid receive data, so the ratio 22 * from 48000Hz not every frame has valid receive data, so the ratio
@@ -61,7 +61,7 @@
61static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, 61static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
62 unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) 62 unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
63{ 63{
64 struct imx_ssi *ssi = cpu_dai->private_data; 64 struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
65 u32 sccr; 65 u32 sccr;
66 66
67 sccr = readl(ssi->base + SSI_STCCR); 67 sccr = readl(ssi->base + SSI_STCCR);
@@ -86,7 +86,7 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
86 */ 86 */
87static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) 87static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
88{ 88{
89 struct imx_ssi *ssi = cpu_dai->private_data; 89 struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
90 u32 strcr = 0, scr; 90 u32 strcr = 0, scr;
91 91
92 scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET); 92 scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
@@ -108,7 +108,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
108 break; 108 break;
109 case SND_SOC_DAIFMT_DSP_B: 109 case SND_SOC_DAIFMT_DSP_B:
110 /* data on rising edge of bclk, frame high with data */ 110 /* data on rising edge of bclk, frame high with data */
111 strcr |= SSI_STCR_TFSL; 111 strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0;
112 break; 112 break;
113 case SND_SOC_DAIFMT_DSP_A: 113 case SND_SOC_DAIFMT_DSP_A:
114 /* data on rising edge of bclk, frame high 1clk before data */ 114 /* data on rising edge of bclk, frame high 1clk before data */
@@ -164,7 +164,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
164static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai, 164static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
165 int clk_id, unsigned int freq, int dir) 165 int clk_id, unsigned int freq, int dir)
166{ 166{
167 struct imx_ssi *ssi = cpu_dai->private_data; 167 struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
168 u32 scr; 168 u32 scr;
169 169
170 scr = readl(ssi->base + SSI_SCR); 170 scr = readl(ssi->base + SSI_SCR);
@@ -192,7 +192,7 @@ static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
192static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, 192static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
193 int div_id, int div) 193 int div_id, int div)
194{ 194{
195 struct imx_ssi *ssi = cpu_dai->private_data; 195 struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
196 u32 stccr, srccr; 196 u32 stccr, srccr;
197 197
198 stccr = readl(ssi->base + SSI_STCCR); 198 stccr = readl(ssi->base + SSI_STCCR);
@@ -241,7 +241,7 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
241 struct snd_pcm_hw_params *params, 241 struct snd_pcm_hw_params *params,
242 struct snd_soc_dai *cpu_dai) 242 struct snd_soc_dai *cpu_dai)
243{ 243{
244 struct imx_ssi *ssi = cpu_dai->private_data; 244 struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
245 struct imx_pcm_dma_params *dma_data; 245 struct imx_pcm_dma_params *dma_data;
246 u32 reg, sccr; 246 u32 reg, sccr;
247 247
@@ -282,9 +282,7 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
282static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd, 282static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
283 struct snd_soc_dai *dai) 283 struct snd_soc_dai *dai)
284{ 284{
285 struct snd_soc_pcm_runtime *rtd = substream->private_data; 285 struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
286 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
287 struct imx_ssi *ssi = cpu_dai->private_data;
288 unsigned int sier_bits, sier; 286 unsigned int sier_bits, sier;
289 unsigned int scr; 287 unsigned int scr;
290 288
@@ -353,22 +351,6 @@ static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
353 .trigger = imx_ssi_trigger, 351 .trigger = imx_ssi_trigger,
354}; 352};
355 353
356static struct snd_soc_dai imx_ssi_dai = {
357 .playback = {
358 .channels_min = 2,
359 .channels_max = 2,
360 .rates = SNDRV_PCM_RATE_8000_96000,
361 .formats = SNDRV_PCM_FMTBIT_S16_LE,
362 },
363 .capture = {
364 .channels_min = 2,
365 .channels_max = 2,
366 .rates = SNDRV_PCM_RATE_8000_96000,
367 .formats = SNDRV_PCM_FMTBIT_S16_LE,
368 },
369 .ops = &imx_ssi_pcm_dai_ops,
370};
371
372int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, 354int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
373 struct vm_area_struct *vma) 355 struct vm_area_struct *vma)
374{ 356{
@@ -384,6 +366,7 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
384 runtime->dma_bytes); 366 runtime->dma_bytes);
385 return ret; 367 return ret;
386} 368}
369EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
387 370
388static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) 371static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
389{ 372{
@@ -415,14 +398,14 @@ int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
415 card->dev->dma_mask = &imx_pcm_dmamask; 398 card->dev->dma_mask = &imx_pcm_dmamask;
416 if (!card->dev->coherent_dma_mask) 399 if (!card->dev->coherent_dma_mask)
417 card->dev->coherent_dma_mask = DMA_BIT_MASK(32); 400 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
418 if (dai->playback.channels_min) { 401 if (dai->driver->playback.channels_min) {
419 ret = imx_pcm_preallocate_dma_buffer(pcm, 402 ret = imx_pcm_preallocate_dma_buffer(pcm,
420 SNDRV_PCM_STREAM_PLAYBACK); 403 SNDRV_PCM_STREAM_PLAYBACK);
421 if (ret) 404 if (ret)
422 goto out; 405 goto out;
423 } 406 }
424 407
425 if (dai->capture.channels_min) { 408 if (dai->driver->capture.channels_min) {
426 ret = imx_pcm_preallocate_dma_buffer(pcm, 409 ret = imx_pcm_preallocate_dma_buffer(pcm,
427 SNDRV_PCM_STREAM_CAPTURE); 410 SNDRV_PCM_STREAM_CAPTURE);
428 if (ret) 411 if (ret)
@@ -432,6 +415,7 @@ int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
432out: 415out:
433 return ret; 416 return ret;
434} 417}
418EXPORT_SYMBOL_GPL(imx_pcm_new);
435 419
436void imx_pcm_free(struct snd_pcm *pcm) 420void imx_pcm_free(struct snd_pcm *pcm)
437{ 421{
@@ -453,14 +437,41 @@ void imx_pcm_free(struct snd_pcm *pcm)
453 buf->area = NULL; 437 buf->area = NULL;
454 } 438 }
455} 439}
440EXPORT_SYMBOL_GPL(imx_pcm_free);
441
442static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
443{
444 struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
445 uint32_t val;
446
447 snd_soc_dai_set_drvdata(dai, ssi);
456 448
457struct snd_soc_platform imx_soc_platform = { 449 val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
458 .name = "imx-audio", 450 SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
451 writel(val, ssi->base + SSI_SFCSR);
452
453 return 0;
454}
455
456static struct snd_soc_dai_driver imx_ssi_dai = {
457 .probe = imx_ssi_dai_probe,
458 .playback = {
459 .channels_min = 1,
460 .channels_max = 2,
461 .rates = SNDRV_PCM_RATE_8000_96000,
462 .formats = SNDRV_PCM_FMTBIT_S16_LE,
463 },
464 .capture = {
465 .channels_min = 1,
466 .channels_max = 2,
467 .rates = SNDRV_PCM_RATE_8000_96000,
468 .formats = SNDRV_PCM_FMTBIT_S16_LE,
469 },
470 .ops = &imx_ssi_pcm_dai_ops,
459}; 471};
460EXPORT_SYMBOL_GPL(imx_soc_platform);
461 472
462static struct snd_soc_dai imx_ac97_dai = { 473static struct snd_soc_dai_driver imx_ac97_dai = {
463 .name = "AC97", 474 .probe = imx_ssi_dai_probe,
464 .ac97_control = 1, 475 .ac97_control = 1,
465 .playback = { 476 .playback = {
466 .stream_name = "AC97 Playback", 477 .stream_name = "AC97 Playback",
@@ -580,25 +591,18 @@ struct snd_ac97_bus_ops soc_ac97_ops = {
580}; 591};
581EXPORT_SYMBOL_GPL(soc_ac97_ops); 592EXPORT_SYMBOL_GPL(soc_ac97_ops);
582 593
583struct snd_soc_dai imx_ssi_pcm_dai[2];
584EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
585
586static int imx_ssi_probe(struct platform_device *pdev) 594static int imx_ssi_probe(struct platform_device *pdev)
587{ 595{
588 struct resource *res; 596 struct resource *res;
589 struct imx_ssi *ssi; 597 struct imx_ssi *ssi;
590 struct imx_ssi_platform_data *pdata = pdev->dev.platform_data; 598 struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
591 struct snd_soc_platform *platform;
592 int ret = 0; 599 int ret = 0;
593 unsigned int val; 600 struct snd_soc_dai_driver *dai;
594 struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
595
596 if (dai->id >= ARRAY_SIZE(imx_ssi_pcm_dai))
597 return -EINVAL;
598 601
599 ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); 602 ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
600 if (!ssi) 603 if (!ssi)
601 return -ENOMEM; 604 return -ENOMEM;
605 dev_set_drvdata(&pdev->dev, ssi);
602 606
603 if (pdata) { 607 if (pdata) {
604 ssi->ac97_reset = pdata->ac97_reset; 608 ssi->ac97_reset = pdata->ac97_reset;
@@ -643,15 +647,18 @@ static int imx_ssi_probe(struct platform_device *pdev)
643 } 647 }
644 ac97_ssi = ssi; 648 ac97_ssi = ssi;
645 setup_channel_to_ac97(ssi); 649 setup_channel_to_ac97(ssi);
646 memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai)); 650 dai = &imx_ac97_dai;
647 } else 651 } else
648 memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai)); 652 dai = &imx_ssi_dai;
649 653
650 writel(0x0, ssi->base + SSI_SIER); 654 writel(0x0, ssi->base + SSI_SIER);
651 655
652 ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0; 656 ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
653 ssi->dma_params_tx.dma_addr = res->start + SSI_STX0; 657 ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
654 658
659 ssi->dma_params_tx.burstsize = 4;
660 ssi->dma_params_rx.burstsize = 4;
661
655 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); 662 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
656 if (res) 663 if (res)
657 ssi->dma_params_tx.dma = res->start; 664 ssi->dma_params_tx.dma = res->start;
@@ -660,37 +667,50 @@ static int imx_ssi_probe(struct platform_device *pdev)
660 if (res) 667 if (res)
661 ssi->dma_params_rx.dma = res->start; 668 ssi->dma_params_rx.dma = res->start;
662 669
663 dai->id = pdev->id; 670 platform_set_drvdata(pdev, ssi);
664 dai->dev = &pdev->dev;
665 dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
666 dai->private_data = ssi;
667
668 if ((cpu_is_mx27() || cpu_is_mx21()) &&
669 !(ssi->flags & IMX_SSI_USE_AC97) &&
670 (ssi->flags & IMX_SSI_DMA)) {
671 ssi->flags |= IMX_SSI_DMA;
672 platform = imx_ssi_dma_mx2_init(pdev, ssi);
673 } else
674 platform = imx_ssi_fiq_init(pdev, ssi);
675
676 imx_soc_platform.pcm_ops = platform->pcm_ops;
677 imx_soc_platform.pcm_new = platform->pcm_new;
678 imx_soc_platform.pcm_free = platform->pcm_free;
679
680 val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
681 SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
682 writel(val, ssi->base + SSI_SFCSR);
683 671
684 ret = snd_soc_register_dai(dai); 672 ret = snd_soc_register_dai(&pdev->dev, dai);
685 if (ret) { 673 if (ret) {
686 dev_err(&pdev->dev, "register DAI failed\n"); 674 dev_err(&pdev->dev, "register DAI failed\n");
687 goto failed_register; 675 goto failed_register;
688 } 676 }
689 677
690 platform_set_drvdata(pdev, ssi); 678 ssi->soc_platform_pdev_fiq = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
679 if (!ssi->soc_platform_pdev_fiq) {
680 ret = -ENOMEM;
681 goto failed_pdev_fiq_alloc;
682 }
683
684 platform_set_drvdata(ssi->soc_platform_pdev_fiq, ssi);
685 ret = platform_device_add(ssi->soc_platform_pdev_fiq);
686 if (ret) {
687 dev_err(&pdev->dev, "failed to add platform device\n");
688 goto failed_pdev_fiq_add;
689 }
690
691 ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", pdev->id);
692 if (!ssi->soc_platform_pdev) {
693 ret = -ENOMEM;
694 goto failed_pdev_alloc;
695 }
696
697 platform_set_drvdata(ssi->soc_platform_pdev, ssi);
698 ret = platform_device_add(ssi->soc_platform_pdev);
699 if (ret) {
700 dev_err(&pdev->dev, "failed to add platform device\n");
701 goto failed_pdev_add;
702 }
691 703
692 return 0; 704 return 0;
693 705
706failed_pdev_add:
707 platform_device_put(ssi->soc_platform_pdev);
708failed_pdev_alloc:
709 platform_device_del(ssi->soc_platform_pdev_fiq);
710failed_pdev_fiq_add:
711 platform_device_put(ssi->soc_platform_pdev_fiq);
712failed_pdev_fiq_alloc:
713 snd_soc_unregister_dai(&pdev->dev);
694failed_register: 714failed_register:
695failed_ac97: 715failed_ac97:
696 iounmap(ssi->base); 716 iounmap(ssi->base);
@@ -709,16 +729,15 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev)
709{ 729{
710 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 730 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
711 struct imx_ssi *ssi = platform_get_drvdata(pdev); 731 struct imx_ssi *ssi = platform_get_drvdata(pdev);
712 struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
713 732
714 snd_soc_unregister_dai(dai); 733 platform_device_unregister(ssi->soc_platform_pdev);
734 platform_device_unregister(ssi->soc_platform_pdev_fiq);
735
736 snd_soc_unregister_dai(&pdev->dev);
715 737
716 if (ssi->flags & IMX_SSI_USE_AC97) 738 if (ssi->flags & IMX_SSI_USE_AC97)
717 ac97_ssi = NULL; 739 ac97_ssi = NULL;
718 740
719 if (!(ssi->flags & IMX_SSI_DMA))
720 imx_ssi_fiq_exit(pdev, ssi);
721
722 iounmap(ssi->base); 741 iounmap(ssi->base);
723 release_mem_region(res->start, resource_size(res)); 742 release_mem_region(res->start, resource_size(res));
724 clk_disable(ssi->clk); 743 clk_disable(ssi->clk);
@@ -733,34 +752,19 @@ static struct platform_driver imx_ssi_driver = {
733 .remove = __devexit_p(imx_ssi_remove), 752 .remove = __devexit_p(imx_ssi_remove),
734 753
735 .driver = { 754 .driver = {
736 .name = DRV_NAME, 755 .name = "imx-ssi",
737 .owner = THIS_MODULE, 756 .owner = THIS_MODULE,
738 }, 757 },
739}; 758};
740 759
741static int __init imx_ssi_init(void) 760static int __init imx_ssi_init(void)
742{ 761{
743 int ret; 762 return platform_driver_register(&imx_ssi_driver);
744
745 ret = snd_soc_register_platform(&imx_soc_platform);
746 if (ret) {
747 pr_err("failed to register soc platform: %d\n", ret);
748 return ret;
749 }
750
751 ret = platform_driver_register(&imx_ssi_driver);
752 if (ret) {
753 snd_soc_unregister_platform(&imx_soc_platform);
754 return ret;
755 }
756
757 return 0;
758} 763}
759 764
760static void __exit imx_ssi_exit(void) 765static void __exit imx_ssi_exit(void)
761{ 766{
762 platform_driver_unregister(&imx_ssi_driver); 767 platform_driver_unregister(&imx_ssi_driver);
763 snd_soc_unregister_platform(&imx_soc_platform);
764} 768}
765 769
766module_init(imx_ssi_init); 770module_init(imx_ssi_init);
@@ -770,4 +774,4 @@ module_exit(imx_ssi_exit);
770MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>"); 774MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
771MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface"); 775MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
772MODULE_LICENSE("GPL"); 776MODULE_LICENSE("GPL");
773 777MODULE_ALIAS("platform:imx-ssi");