diff options
author | Vinod Koul <vinod.koul@intel.com> | 2017-11-14 00:02:49 -0500 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2017-11-14 00:02:49 -0500 |
commit | 340b11b9f1b1a90d460ae4bcf1be448d6c032ef7 (patch) | |
tree | c3308e1b75b38d10313f4f7456fc607b9c6bda38 | |
parent | e143132a04b10c36df9c0ffa5a33efc527d5e270 (diff) | |
parent | 56d355e6f586539e5f87280376eed09fb8801f42 (diff) |
Merge branch 'topic/img' into for-linus
-rw-r--r-- | drivers/dma/img-mdc-dma.c | 98 |
1 files changed, 80 insertions, 18 deletions
diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c index 54db1411ce73..0391f930aecc 100644 --- a/drivers/dma/img-mdc-dma.c +++ b/drivers/dma/img-mdc-dma.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/of_device.h> | 23 | #include <linux/of_device.h> |
24 | #include <linux/of_dma.h> | 24 | #include <linux/of_dma.h> |
25 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/pm_runtime.h> | ||
26 | #include <linux/regmap.h> | 27 | #include <linux/regmap.h> |
27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
28 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
@@ -730,14 +731,23 @@ static int mdc_slave_config(struct dma_chan *chan, | |||
730 | return 0; | 731 | return 0; |
731 | } | 732 | } |
732 | 733 | ||
734 | static int mdc_alloc_chan_resources(struct dma_chan *chan) | ||
735 | { | ||
736 | struct mdc_chan *mchan = to_mdc_chan(chan); | ||
737 | struct device *dev = mdma2dev(mchan->mdma); | ||
738 | |||
739 | return pm_runtime_get_sync(dev); | ||
740 | } | ||
741 | |||
733 | static void mdc_free_chan_resources(struct dma_chan *chan) | 742 | static void mdc_free_chan_resources(struct dma_chan *chan) |
734 | { | 743 | { |
735 | struct mdc_chan *mchan = to_mdc_chan(chan); | 744 | struct mdc_chan *mchan = to_mdc_chan(chan); |
736 | struct mdc_dma *mdma = mchan->mdma; | 745 | struct mdc_dma *mdma = mchan->mdma; |
746 | struct device *dev = mdma2dev(mdma); | ||
737 | 747 | ||
738 | mdc_terminate_all(chan); | 748 | mdc_terminate_all(chan); |
739 | |||
740 | mdma->soc->disable_chan(mchan); | 749 | mdma->soc->disable_chan(mchan); |
750 | pm_runtime_put(dev); | ||
741 | } | 751 | } |
742 | 752 | ||
743 | static irqreturn_t mdc_chan_irq(int irq, void *dev_id) | 753 | static irqreturn_t mdc_chan_irq(int irq, void *dev_id) |
@@ -854,6 +864,22 @@ static const struct of_device_id mdc_dma_of_match[] = { | |||
854 | }; | 864 | }; |
855 | MODULE_DEVICE_TABLE(of, mdc_dma_of_match); | 865 | MODULE_DEVICE_TABLE(of, mdc_dma_of_match); |
856 | 866 | ||
867 | static int img_mdc_runtime_suspend(struct device *dev) | ||
868 | { | ||
869 | struct mdc_dma *mdma = dev_get_drvdata(dev); | ||
870 | |||
871 | clk_disable_unprepare(mdma->clk); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int img_mdc_runtime_resume(struct device *dev) | ||
877 | { | ||
878 | struct mdc_dma *mdma = dev_get_drvdata(dev); | ||
879 | |||
880 | return clk_prepare_enable(mdma->clk); | ||
881 | } | ||
882 | |||
857 | static int mdc_dma_probe(struct platform_device *pdev) | 883 | static int mdc_dma_probe(struct platform_device *pdev) |
858 | { | 884 | { |
859 | struct mdc_dma *mdma; | 885 | struct mdc_dma *mdma; |
@@ -883,10 +909,6 @@ static int mdc_dma_probe(struct platform_device *pdev) | |||
883 | if (IS_ERR(mdma->clk)) | 909 | if (IS_ERR(mdma->clk)) |
884 | return PTR_ERR(mdma->clk); | 910 | return PTR_ERR(mdma->clk); |
885 | 911 | ||
886 | ret = clk_prepare_enable(mdma->clk); | ||
887 | if (ret) | ||
888 | return ret; | ||
889 | |||
890 | dma_cap_zero(mdma->dma_dev.cap_mask); | 912 | dma_cap_zero(mdma->dma_dev.cap_mask); |
891 | dma_cap_set(DMA_SLAVE, mdma->dma_dev.cap_mask); | 913 | dma_cap_set(DMA_SLAVE, mdma->dma_dev.cap_mask); |
892 | dma_cap_set(DMA_PRIVATE, mdma->dma_dev.cap_mask); | 914 | dma_cap_set(DMA_PRIVATE, mdma->dma_dev.cap_mask); |
@@ -919,12 +941,13 @@ static int mdc_dma_probe(struct platform_device *pdev) | |||
919 | "img,max-burst-multiplier", | 941 | "img,max-burst-multiplier", |
920 | &mdma->max_burst_mult); | 942 | &mdma->max_burst_mult); |
921 | if (ret) | 943 | if (ret) |
922 | goto disable_clk; | 944 | return ret; |
923 | 945 | ||
924 | mdma->dma_dev.dev = &pdev->dev; | 946 | mdma->dma_dev.dev = &pdev->dev; |
925 | mdma->dma_dev.device_prep_slave_sg = mdc_prep_slave_sg; | 947 | mdma->dma_dev.device_prep_slave_sg = mdc_prep_slave_sg; |
926 | mdma->dma_dev.device_prep_dma_cyclic = mdc_prep_dma_cyclic; | 948 | mdma->dma_dev.device_prep_dma_cyclic = mdc_prep_dma_cyclic; |
927 | mdma->dma_dev.device_prep_dma_memcpy = mdc_prep_dma_memcpy; | 949 | mdma->dma_dev.device_prep_dma_memcpy = mdc_prep_dma_memcpy; |
950 | mdma->dma_dev.device_alloc_chan_resources = mdc_alloc_chan_resources; | ||
928 | mdma->dma_dev.device_free_chan_resources = mdc_free_chan_resources; | 951 | mdma->dma_dev.device_free_chan_resources = mdc_free_chan_resources; |
929 | mdma->dma_dev.device_tx_status = mdc_tx_status; | 952 | mdma->dma_dev.device_tx_status = mdc_tx_status; |
930 | mdma->dma_dev.device_issue_pending = mdc_issue_pending; | 953 | mdma->dma_dev.device_issue_pending = mdc_issue_pending; |
@@ -945,15 +968,14 @@ static int mdc_dma_probe(struct platform_device *pdev) | |||
945 | mchan->mdma = mdma; | 968 | mchan->mdma = mdma; |
946 | mchan->chan_nr = i; | 969 | mchan->chan_nr = i; |
947 | mchan->irq = platform_get_irq(pdev, i); | 970 | mchan->irq = platform_get_irq(pdev, i); |
948 | if (mchan->irq < 0) { | 971 | if (mchan->irq < 0) |
949 | ret = mchan->irq; | 972 | return mchan->irq; |
950 | goto disable_clk; | 973 | |
951 | } | ||
952 | ret = devm_request_irq(&pdev->dev, mchan->irq, mdc_chan_irq, | 974 | ret = devm_request_irq(&pdev->dev, mchan->irq, mdc_chan_irq, |
953 | IRQ_TYPE_LEVEL_HIGH, | 975 | IRQ_TYPE_LEVEL_HIGH, |
954 | dev_name(&pdev->dev), mchan); | 976 | dev_name(&pdev->dev), mchan); |
955 | if (ret < 0) | 977 | if (ret < 0) |
956 | goto disable_clk; | 978 | return ret; |
957 | 979 | ||
958 | mchan->vc.desc_free = mdc_desc_free; | 980 | mchan->vc.desc_free = mdc_desc_free; |
959 | vchan_init(&mchan->vc, &mdma->dma_dev); | 981 | vchan_init(&mchan->vc, &mdma->dma_dev); |
@@ -962,14 +984,19 @@ static int mdc_dma_probe(struct platform_device *pdev) | |||
962 | mdma->desc_pool = dmam_pool_create(dev_name(&pdev->dev), &pdev->dev, | 984 | mdma->desc_pool = dmam_pool_create(dev_name(&pdev->dev), &pdev->dev, |
963 | sizeof(struct mdc_hw_list_desc), | 985 | sizeof(struct mdc_hw_list_desc), |
964 | 4, 0); | 986 | 4, 0); |
965 | if (!mdma->desc_pool) { | 987 | if (!mdma->desc_pool) |
966 | ret = -ENOMEM; | 988 | return -ENOMEM; |
967 | goto disable_clk; | 989 | |
990 | pm_runtime_enable(&pdev->dev); | ||
991 | if (!pm_runtime_enabled(&pdev->dev)) { | ||
992 | ret = img_mdc_runtime_resume(&pdev->dev); | ||
993 | if (ret) | ||
994 | return ret; | ||
968 | } | 995 | } |
969 | 996 | ||
970 | ret = dma_async_device_register(&mdma->dma_dev); | 997 | ret = dma_async_device_register(&mdma->dma_dev); |
971 | if (ret) | 998 | if (ret) |
972 | goto disable_clk; | 999 | goto suspend; |
973 | 1000 | ||
974 | ret = of_dma_controller_register(pdev->dev.of_node, mdc_of_xlate, mdma); | 1001 | ret = of_dma_controller_register(pdev->dev.of_node, mdc_of_xlate, mdma); |
975 | if (ret) | 1002 | if (ret) |
@@ -982,8 +1009,10 @@ static int mdc_dma_probe(struct platform_device *pdev) | |||
982 | 1009 | ||
983 | unregister: | 1010 | unregister: |
984 | dma_async_device_unregister(&mdma->dma_dev); | 1011 | dma_async_device_unregister(&mdma->dma_dev); |
985 | disable_clk: | 1012 | suspend: |
986 | clk_disable_unprepare(mdma->clk); | 1013 | if (!pm_runtime_enabled(&pdev->dev)) |
1014 | img_mdc_runtime_suspend(&pdev->dev); | ||
1015 | pm_runtime_disable(&pdev->dev); | ||
987 | return ret; | 1016 | return ret; |
988 | } | 1017 | } |
989 | 1018 | ||
@@ -1004,14 +1033,47 @@ static int mdc_dma_remove(struct platform_device *pdev) | |||
1004 | tasklet_kill(&mchan->vc.task); | 1033 | tasklet_kill(&mchan->vc.task); |
1005 | } | 1034 | } |
1006 | 1035 | ||
1007 | clk_disable_unprepare(mdma->clk); | 1036 | pm_runtime_disable(&pdev->dev); |
1037 | if (!pm_runtime_status_suspended(&pdev->dev)) | ||
1038 | img_mdc_runtime_suspend(&pdev->dev); | ||
1008 | 1039 | ||
1009 | return 0; | 1040 | return 0; |
1010 | } | 1041 | } |
1011 | 1042 | ||
1043 | #ifdef CONFIG_PM_SLEEP | ||
1044 | static int img_mdc_suspend_late(struct device *dev) | ||
1045 | { | ||
1046 | struct mdc_dma *mdma = dev_get_drvdata(dev); | ||
1047 | int i; | ||
1048 | |||
1049 | /* Check that all channels are idle */ | ||
1050 | for (i = 0; i < mdma->nr_channels; i++) { | ||
1051 | struct mdc_chan *mchan = &mdma->channels[i]; | ||
1052 | |||
1053 | if (unlikely(mchan->desc)) | ||
1054 | return -EBUSY; | ||
1055 | } | ||
1056 | |||
1057 | return pm_runtime_force_suspend(dev); | ||
1058 | } | ||
1059 | |||
1060 | static int img_mdc_resume_early(struct device *dev) | ||
1061 | { | ||
1062 | return pm_runtime_force_resume(dev); | ||
1063 | } | ||
1064 | #endif /* CONFIG_PM_SLEEP */ | ||
1065 | |||
1066 | static const struct dev_pm_ops img_mdc_pm_ops = { | ||
1067 | SET_RUNTIME_PM_OPS(img_mdc_runtime_suspend, | ||
1068 | img_mdc_runtime_resume, NULL) | ||
1069 | SET_LATE_SYSTEM_SLEEP_PM_OPS(img_mdc_suspend_late, | ||
1070 | img_mdc_resume_early) | ||
1071 | }; | ||
1072 | |||
1012 | static struct platform_driver mdc_dma_driver = { | 1073 | static struct platform_driver mdc_dma_driver = { |
1013 | .driver = { | 1074 | .driver = { |
1014 | .name = "img-mdc-dma", | 1075 | .name = "img-mdc-dma", |
1076 | .pm = &img_mdc_pm_ops, | ||
1015 | .of_match_table = of_match_ptr(mdc_dma_of_match), | 1077 | .of_match_table = of_match_ptr(mdc_dma_of_match), |
1016 | }, | 1078 | }, |
1017 | .probe = mdc_dma_probe, | 1079 | .probe = mdc_dma_probe, |