aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/atmel/atmel_ssc_dai.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/atmel/atmel_ssc_dai.c')
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c148
1 files changed, 123 insertions, 25 deletions
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index c85844d4845b..5d230cee3fa7 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -205,8 +205,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
205static int atmel_ssc_startup(struct snd_pcm_substream *substream, 205static int atmel_ssc_startup(struct snd_pcm_substream *substream,
206 struct snd_soc_dai *dai) 206 struct snd_soc_dai *dai)
207{ 207{
208 struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 208 struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
209 struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
210 int dir_mask; 209 int dir_mask;
211 210
212 pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", 211 pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
@@ -235,8 +234,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
235static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, 234static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
236 struct snd_soc_dai *dai) 235 struct snd_soc_dai *dai)
237{ 236{
238 struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 237 struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
239 struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
240 struct atmel_pcm_dma_params *dma_params; 238 struct atmel_pcm_dma_params *dma_params;
241 int dir, dir_mask; 239 int dir, dir_mask;
242 240
@@ -338,7 +336,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
338 struct snd_soc_dai *dai) 336 struct snd_soc_dai *dai)
339{ 337{
340 struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 338 struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
341 int id = rtd->dai->cpu_dai->id; 339 int id = dai->id;
342 struct atmel_ssc_info *ssc_p = &ssc_info[id]; 340 struct atmel_ssc_info *ssc_p = &ssc_info[id];
343 struct atmel_pcm_dma_params *dma_params; 341 struct atmel_pcm_dma_params *dma_params;
344 int dir, channels, bits; 342 int dir, channels, bits;
@@ -368,7 +366,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
368 * function. It should not be used for other purposes 366 * function. It should not be used for other purposes
369 * as it is common to all substreams. 367 * as it is common to all substreams.
370 */ 368 */
371 snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_params); 369 snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
372 370
373 channels = params_channels(params); 371 channels = params_channels(params);
374 372
@@ -605,8 +603,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
605static int atmel_ssc_prepare(struct snd_pcm_substream *substream, 603static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
606 struct snd_soc_dai *dai) 604 struct snd_soc_dai *dai)
607{ 605{
608 struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 606 struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
609 struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
610 struct atmel_pcm_dma_params *dma_params; 607 struct atmel_pcm_dma_params *dma_params;
611 int dir; 608 int dir;
612 609
@@ -690,6 +687,32 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
690# define atmel_ssc_resume NULL 687# define atmel_ssc_resume NULL
691#endif /* CONFIG_PM */ 688#endif /* CONFIG_PM */
692 689
690static int atmel_ssc_probe(struct snd_soc_dai *dai)
691{
692 struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
693 int ret = 0;
694
695 snd_soc_dai_set_drvdata(dai, ssc_p);
696
697 /*
698 * Request SSC device
699 */
700 ssc_p->ssc = ssc_request(dai->id);
701 if (IS_ERR(ssc_p->ssc)) {
702 printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
703 ret = PTR_ERR(ssc_p->ssc);
704 }
705
706 return ret;
707}
708
709static int atmel_ssc_remove(struct snd_soc_dai *dai)
710{
711 struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
712
713 ssc_free(ssc_p->ssc);
714 return 0;
715}
693 716
694#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) 717#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
695 718
@@ -705,9 +728,11 @@ static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
705 .set_clkdiv = atmel_ssc_set_dai_clkdiv, 728 .set_clkdiv = atmel_ssc_set_dai_clkdiv,
706}; 729};
707 730
708struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { 731static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
709 { .name = "atmel-ssc0", 732 {
710 .id = 0, 733 .name = "atmel-ssc-dai.0",
734 .probe = atmel_ssc_probe,
735 .remove = atmel_ssc_remove,
711 .suspend = atmel_ssc_suspend, 736 .suspend = atmel_ssc_suspend,
712 .resume = atmel_ssc_resume, 737 .resume = atmel_ssc_resume,
713 .playback = { 738 .playback = {
@@ -721,11 +746,12 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
721 .rates = ATMEL_SSC_RATES, 746 .rates = ATMEL_SSC_RATES,
722 .formats = ATMEL_SSC_FORMATS,}, 747 .formats = ATMEL_SSC_FORMATS,},
723 .ops = &atmel_ssc_dai_ops, 748 .ops = &atmel_ssc_dai_ops,
724 .private_data = &ssc_info[0],
725 }, 749 },
726#if NUM_SSC_DEVICES == 3 750#if NUM_SSC_DEVICES == 3
727 { .name = "atmel-ssc1", 751 {
728 .id = 1, 752 .name = "atmel-ssc-dai.1",
753 .probe = atmel_ssc_probe,
754 .remove = atmel_ssc_remove,
729 .suspend = atmel_ssc_suspend, 755 .suspend = atmel_ssc_suspend,
730 .resume = atmel_ssc_resume, 756 .resume = atmel_ssc_resume,
731 .playback = { 757 .playback = {
@@ -739,10 +765,11 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
739 .rates = ATMEL_SSC_RATES, 765 .rates = ATMEL_SSC_RATES,
740 .formats = ATMEL_SSC_FORMATS,}, 766 .formats = ATMEL_SSC_FORMATS,},
741 .ops = &atmel_ssc_dai_ops, 767 .ops = &atmel_ssc_dai_ops,
742 .private_data = &ssc_info[1],
743 }, 768 },
744 { .name = "atmel-ssc2", 769 {
745 .id = 2, 770 .name = "atmel-ssc-dai.2",
771 .probe = atmel_ssc_probe,
772 .remove = atmel_ssc_remove,
746 .suspend = atmel_ssc_suspend, 773 .suspend = atmel_ssc_suspend,
747 .resume = atmel_ssc_resume, 774 .resume = atmel_ssc_resume,
748 .playback = { 775 .playback = {
@@ -756,23 +783,94 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
756 .rates = ATMEL_SSC_RATES, 783 .rates = ATMEL_SSC_RATES,
757 .formats = ATMEL_SSC_FORMATS,}, 784 .formats = ATMEL_SSC_FORMATS,},
758 .ops = &atmel_ssc_dai_ops, 785 .ops = &atmel_ssc_dai_ops,
759 .private_data = &ssc_info[2],
760 }, 786 },
761#endif 787#endif
762}; 788};
763EXPORT_SYMBOL_GPL(atmel_ssc_dai);
764 789
765static int __init atmel_ssc_modinit(void) 790static __devinit int asoc_ssc_probe(struct platform_device *pdev)
791{
792 BUG_ON(pdev->id < 0);
793 BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
794 return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
795}
796
797static int __devexit asoc_ssc_remove(struct platform_device *pdev)
798{
799 snd_soc_unregister_dai(&pdev->dev);
800 return 0;
801}
802
803static struct platform_driver asoc_ssc_driver = {
804 .driver = {
805 .name = "atmel-ssc-dai",
806 .owner = THIS_MODULE,
807 },
808
809 .probe = asoc_ssc_probe,
810 .remove = __devexit_p(asoc_ssc_remove),
811};
812
813/**
814 * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
815 */
816int atmel_ssc_set_audio(int ssc_id)
817{
818 struct ssc_device *ssc;
819 static struct platform_device *dma_pdev;
820 struct platform_device *ssc_pdev;
821 int ret;
822
823 if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
824 return -EINVAL;
825
826 /* Allocate a dummy device for DMA if we don't have one already */
827 if (!dma_pdev) {
828 dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
829 if (!dma_pdev)
830 return -ENOMEM;
831
832 ret = platform_device_add(dma_pdev);
833 if (ret < 0) {
834 platform_device_put(dma_pdev);
835 dma_pdev = NULL;
836 return ret;
837 }
838 }
839
840 ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
841 if (!ssc_pdev) {
842 ssc_free(ssc);
843 return -ENOMEM;
844 }
845
846 /* If we can grab the SSC briefly to parent the DAI device off it */
847 ssc = ssc_request(ssc_id);
848 if (IS_ERR(ssc))
849 pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
850 PTR_ERR(ssc));
851 else
852 ssc_pdev->dev.parent = &(ssc->pdev->dev);
853 ssc_free(ssc);
854
855 ret = platform_device_add(ssc_pdev);
856 if (ret < 0)
857 platform_device_put(ssc_pdev);
858
859 return ret;
860}
861EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
862
863static int __init snd_atmel_ssc_init(void)
766{ 864{
767 return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); 865 return platform_driver_register(&asoc_ssc_driver);
768} 866}
769module_init(atmel_ssc_modinit); 867module_init(snd_atmel_ssc_init);
770 868
771static void __exit atmel_ssc_modexit(void) 869static void __exit snd_atmel_ssc_exit(void)
772{ 870{
773 snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); 871 platform_driver_unregister(&asoc_ssc_driver);
774} 872}
775module_exit(atmel_ssc_modexit); 873module_exit(snd_atmel_ssc_exit);
776 874
777/* Module information */ 875/* Module information */
778MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); 876MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");