diff options
Diffstat (limited to 'drivers/dma/fsldma.c')
-rw-r--r-- | drivers/dma/fsldma.c | 138 |
1 files changed, 88 insertions, 50 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index e9b263897c03..0b95dcce447e 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c | |||
@@ -370,7 +370,10 @@ static int fsl_dma_alloc_chan_resources(struct dma_chan *chan, | |||
370 | struct dma_client *client) | 370 | struct dma_client *client) |
371 | { | 371 | { |
372 | struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); | 372 | struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); |
373 | LIST_HEAD(tmp_list); | 373 | |
374 | /* Has this channel already been allocated? */ | ||
375 | if (fsl_chan->desc_pool) | ||
376 | return 1; | ||
374 | 377 | ||
375 | /* We need the descriptor to be aligned to 32bytes | 378 | /* We need the descriptor to be aligned to 32bytes |
376 | * for meeting FSL DMA specification requirement. | 379 | * for meeting FSL DMA specification requirement. |
@@ -410,6 +413,8 @@ static void fsl_dma_free_chan_resources(struct dma_chan *chan) | |||
410 | } | 413 | } |
411 | spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); | 414 | spin_unlock_irqrestore(&fsl_chan->desc_lock, flags); |
412 | dma_pool_destroy(fsl_chan->desc_pool); | 415 | dma_pool_destroy(fsl_chan->desc_pool); |
416 | |||
417 | fsl_chan->desc_pool = NULL; | ||
413 | } | 418 | } |
414 | 419 | ||
415 | static struct dma_async_tx_descriptor * | 420 | static struct dma_async_tx_descriptor * |
@@ -786,33 +791,29 @@ static void dma_do_tasklet(unsigned long data) | |||
786 | fsl_chan_ld_cleanup(fsl_chan); | 791 | fsl_chan_ld_cleanup(fsl_chan); |
787 | } | 792 | } |
788 | 793 | ||
789 | static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, | 794 | static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev, |
790 | const struct of_device_id *match) | 795 | struct device_node *node, u32 feature, const char *compatible) |
791 | { | 796 | { |
792 | struct fsl_dma_device *fdev; | ||
793 | struct fsl_dma_chan *new_fsl_chan; | 797 | struct fsl_dma_chan *new_fsl_chan; |
794 | int err; | 798 | int err; |
795 | 799 | ||
796 | fdev = dev_get_drvdata(dev->dev.parent); | ||
797 | BUG_ON(!fdev); | ||
798 | |||
799 | /* alloc channel */ | 800 | /* alloc channel */ |
800 | new_fsl_chan = kzalloc(sizeof(struct fsl_dma_chan), GFP_KERNEL); | 801 | new_fsl_chan = kzalloc(sizeof(struct fsl_dma_chan), GFP_KERNEL); |
801 | if (!new_fsl_chan) { | 802 | if (!new_fsl_chan) { |
802 | dev_err(&dev->dev, "No free memory for allocating " | 803 | dev_err(fdev->dev, "No free memory for allocating " |
803 | "dma channels!\n"); | 804 | "dma channels!\n"); |
804 | return -ENOMEM; | 805 | return -ENOMEM; |
805 | } | 806 | } |
806 | 807 | ||
807 | /* get dma channel register base */ | 808 | /* get dma channel register base */ |
808 | err = of_address_to_resource(dev->node, 0, &new_fsl_chan->reg); | 809 | err = of_address_to_resource(node, 0, &new_fsl_chan->reg); |
809 | if (err) { | 810 | if (err) { |
810 | dev_err(&dev->dev, "Can't get %s property 'reg'\n", | 811 | dev_err(fdev->dev, "Can't get %s property 'reg'\n", |
811 | dev->node->full_name); | 812 | node->full_name); |
812 | goto err_no_reg; | 813 | goto err_no_reg; |
813 | } | 814 | } |
814 | 815 | ||
815 | new_fsl_chan->feature = *(u32 *)match->data; | 816 | new_fsl_chan->feature = feature; |
816 | 817 | ||
817 | if (!fdev->feature) | 818 | if (!fdev->feature) |
818 | fdev->feature = new_fsl_chan->feature; | 819 | fdev->feature = new_fsl_chan->feature; |
@@ -822,13 +823,13 @@ static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, | |||
822 | */ | 823 | */ |
823 | WARN_ON(fdev->feature != new_fsl_chan->feature); | 824 | WARN_ON(fdev->feature != new_fsl_chan->feature); |
824 | 825 | ||
825 | new_fsl_chan->dev = &dev->dev; | 826 | new_fsl_chan->dev = &new_fsl_chan->common.dev; |
826 | new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start, | 827 | new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start, |
827 | new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1); | 828 | new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1); |
828 | 829 | ||
829 | new_fsl_chan->id = ((new_fsl_chan->reg.start - 0x100) & 0xfff) >> 7; | 830 | new_fsl_chan->id = ((new_fsl_chan->reg.start - 0x100) & 0xfff) >> 7; |
830 | if (new_fsl_chan->id > FSL_DMA_MAX_CHANS_PER_DEVICE) { | 831 | if (new_fsl_chan->id > FSL_DMA_MAX_CHANS_PER_DEVICE) { |
831 | dev_err(&dev->dev, "There is no %d channel!\n", | 832 | dev_err(fdev->dev, "There is no %d channel!\n", |
832 | new_fsl_chan->id); | 833 | new_fsl_chan->id); |
833 | err = -EINVAL; | 834 | err = -EINVAL; |
834 | goto err_no_chan; | 835 | goto err_no_chan; |
@@ -862,20 +863,20 @@ static int __devinit of_fsl_dma_chan_probe(struct of_device *dev, | |||
862 | &fdev->common.channels); | 863 | &fdev->common.channels); |
863 | fdev->common.chancnt++; | 864 | fdev->common.chancnt++; |
864 | 865 | ||
865 | new_fsl_chan->irq = irq_of_parse_and_map(dev->node, 0); | 866 | new_fsl_chan->irq = irq_of_parse_and_map(node, 0); |
866 | if (new_fsl_chan->irq != NO_IRQ) { | 867 | if (new_fsl_chan->irq != NO_IRQ) { |
867 | err = request_irq(new_fsl_chan->irq, | 868 | err = request_irq(new_fsl_chan->irq, |
868 | &fsl_dma_chan_do_interrupt, IRQF_SHARED, | 869 | &fsl_dma_chan_do_interrupt, IRQF_SHARED, |
869 | "fsldma-channel", new_fsl_chan); | 870 | "fsldma-channel", new_fsl_chan); |
870 | if (err) { | 871 | if (err) { |
871 | dev_err(&dev->dev, "DMA channel %s request_irq error " | 872 | dev_err(fdev->dev, "DMA channel %s request_irq error " |
872 | "with return %d\n", dev->node->full_name, err); | 873 | "with return %d\n", node->full_name, err); |
873 | goto err_no_irq; | 874 | goto err_no_irq; |
874 | } | 875 | } |
875 | } | 876 | } |
876 | 877 | ||
877 | dev_info(&dev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id, | 878 | dev_info(fdev->dev, "#%d (%s), irq %d\n", new_fsl_chan->id, |
878 | match->compatible, new_fsl_chan->irq); | 879 | compatible, new_fsl_chan->irq); |
879 | 880 | ||
880 | return 0; | 881 | return 0; |
881 | 882 | ||
@@ -888,38 +889,20 @@ err_no_reg: | |||
888 | return err; | 889 | return err; |
889 | } | 890 | } |
890 | 891 | ||
891 | const u32 mpc8540_dma_ip_feature = FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN; | 892 | static void fsl_dma_chan_remove(struct fsl_dma_chan *fchan) |
892 | const u32 mpc8349_dma_ip_feature = FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN; | ||
893 | |||
894 | static struct of_device_id of_fsl_dma_chan_ids[] = { | ||
895 | { | ||
896 | .compatible = "fsl,eloplus-dma-channel", | ||
897 | .data = (void *)&mpc8540_dma_ip_feature, | ||
898 | }, | ||
899 | { | ||
900 | .compatible = "fsl,elo-dma-channel", | ||
901 | .data = (void *)&mpc8349_dma_ip_feature, | ||
902 | }, | ||
903 | {} | ||
904 | }; | ||
905 | |||
906 | static struct of_platform_driver of_fsl_dma_chan_driver = { | ||
907 | .name = "of-fsl-dma-channel", | ||
908 | .match_table = of_fsl_dma_chan_ids, | ||
909 | .probe = of_fsl_dma_chan_probe, | ||
910 | }; | ||
911 | |||
912 | static __init int of_fsl_dma_chan_init(void) | ||
913 | { | 893 | { |
914 | return of_register_platform_driver(&of_fsl_dma_chan_driver); | 894 | free_irq(fchan->irq, fchan); |
895 | list_del(&fchan->common.device_node); | ||
896 | iounmap(fchan->reg_base); | ||
897 | kfree(fchan); | ||
915 | } | 898 | } |
916 | 899 | ||
917 | static int __devinit of_fsl_dma_probe(struct of_device *dev, | 900 | static int __devinit of_fsl_dma_probe(struct of_device *dev, |
918 | const struct of_device_id *match) | 901 | const struct of_device_id *match) |
919 | { | 902 | { |
920 | int err; | 903 | int err; |
921 | unsigned int irq; | ||
922 | struct fsl_dma_device *fdev; | 904 | struct fsl_dma_device *fdev; |
905 | struct device_node *child; | ||
923 | 906 | ||
924 | fdev = kzalloc(sizeof(struct fsl_dma_device), GFP_KERNEL); | 907 | fdev = kzalloc(sizeof(struct fsl_dma_device), GFP_KERNEL); |
925 | if (!fdev) { | 908 | if (!fdev) { |
@@ -953,9 +936,9 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev, | |||
953 | fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; | 936 | fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; |
954 | fdev->common.dev = &dev->dev; | 937 | fdev->common.dev = &dev->dev; |
955 | 938 | ||
956 | irq = irq_of_parse_and_map(dev->node, 0); | 939 | fdev->irq = irq_of_parse_and_map(dev->node, 0); |
957 | if (irq != NO_IRQ) { | 940 | if (fdev->irq != NO_IRQ) { |
958 | err = request_irq(irq, &fsl_dma_do_interrupt, IRQF_SHARED, | 941 | err = request_irq(fdev->irq, &fsl_dma_do_interrupt, IRQF_SHARED, |
959 | "fsldma-device", fdev); | 942 | "fsldma-device", fdev); |
960 | if (err) { | 943 | if (err) { |
961 | dev_err(&dev->dev, "DMA device request_irq error " | 944 | dev_err(&dev->dev, "DMA device request_irq error " |
@@ -965,7 +948,21 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev, | |||
965 | } | 948 | } |
966 | 949 | ||
967 | dev_set_drvdata(&(dev->dev), fdev); | 950 | dev_set_drvdata(&(dev->dev), fdev); |
968 | of_platform_bus_probe(dev->node, of_fsl_dma_chan_ids, &dev->dev); | 951 | |
952 | /* We cannot use of_platform_bus_probe() because there is no | ||
953 | * of_platform_bus_remove. Instead, we manually instantiate every DMA | ||
954 | * channel object. | ||
955 | */ | ||
956 | for_each_child_of_node(dev->node, child) { | ||
957 | if (of_device_is_compatible(child, "fsl,eloplus-dma-channel")) | ||
958 | fsl_dma_chan_probe(fdev, child, | ||
959 | FSL_DMA_IP_85XX | FSL_DMA_BIG_ENDIAN, | ||
960 | "fsl,eloplus-dma-channel"); | ||
961 | if (of_device_is_compatible(child, "fsl,elo-dma-channel")) | ||
962 | fsl_dma_chan_probe(fdev, child, | ||
963 | FSL_DMA_IP_83XX | FSL_DMA_LITTLE_ENDIAN, | ||
964 | "fsl,elo-dma-channel"); | ||
965 | } | ||
969 | 966 | ||
970 | dma_async_device_register(&fdev->common); | 967 | dma_async_device_register(&fdev->common); |
971 | return 0; | 968 | return 0; |
@@ -977,6 +974,30 @@ err_no_reg: | |||
977 | return err; | 974 | return err; |
978 | } | 975 | } |
979 | 976 | ||
977 | static int of_fsl_dma_remove(struct of_device *of_dev) | ||
978 | { | ||
979 | struct fsl_dma_device *fdev; | ||
980 | unsigned int i; | ||
981 | |||
982 | fdev = dev_get_drvdata(&of_dev->dev); | ||
983 | |||
984 | dma_async_device_unregister(&fdev->common); | ||
985 | |||
986 | for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) | ||
987 | if (fdev->chan[i]) | ||
988 | fsl_dma_chan_remove(fdev->chan[i]); | ||
989 | |||
990 | if (fdev->irq != NO_IRQ) | ||
991 | free_irq(fdev->irq, fdev); | ||
992 | |||
993 | iounmap(fdev->reg_base); | ||
994 | |||
995 | kfree(fdev); | ||
996 | dev_set_drvdata(&of_dev->dev, NULL); | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
980 | static struct of_device_id of_fsl_dma_ids[] = { | 1001 | static struct of_device_id of_fsl_dma_ids[] = { |
981 | { .compatible = "fsl,eloplus-dma", }, | 1002 | { .compatible = "fsl,eloplus-dma", }, |
982 | { .compatible = "fsl,elo-dma", }, | 1003 | { .compatible = "fsl,elo-dma", }, |
@@ -984,15 +1005,32 @@ static struct of_device_id of_fsl_dma_ids[] = { | |||
984 | }; | 1005 | }; |
985 | 1006 | ||
986 | static struct of_platform_driver of_fsl_dma_driver = { | 1007 | static struct of_platform_driver of_fsl_dma_driver = { |
987 | .name = "of-fsl-dma", | 1008 | .name = "fsl-elo-dma", |
988 | .match_table = of_fsl_dma_ids, | 1009 | .match_table = of_fsl_dma_ids, |
989 | .probe = of_fsl_dma_probe, | 1010 | .probe = of_fsl_dma_probe, |
1011 | .remove = of_fsl_dma_remove, | ||
990 | }; | 1012 | }; |
991 | 1013 | ||
992 | static __init int of_fsl_dma_init(void) | 1014 | static __init int of_fsl_dma_init(void) |
993 | { | 1015 | { |
994 | return of_register_platform_driver(&of_fsl_dma_driver); | 1016 | int ret; |
1017 | |||
1018 | pr_info("Freescale Elo / Elo Plus DMA driver\n"); | ||
1019 | |||
1020 | ret = of_register_platform_driver(&of_fsl_dma_driver); | ||
1021 | if (ret) | ||
1022 | pr_err("fsldma: failed to register platform driver\n"); | ||
1023 | |||
1024 | return ret; | ||
1025 | } | ||
1026 | |||
1027 | static void __exit of_fsl_dma_exit(void) | ||
1028 | { | ||
1029 | of_unregister_platform_driver(&of_fsl_dma_driver); | ||
995 | } | 1030 | } |
996 | 1031 | ||
997 | subsys_initcall(of_fsl_dma_chan_init); | ||
998 | subsys_initcall(of_fsl_dma_init); | 1032 | subsys_initcall(of_fsl_dma_init); |
1033 | module_exit(of_fsl_dma_exit); | ||
1034 | |||
1035 | MODULE_DESCRIPTION("Freescale Elo / Elo Plus DMA driver"); | ||
1036 | MODULE_LICENSE("GPL"); | ||