diff options
author | Daniel Mack <zonque@gmail.com> | 2013-08-10 12:52:19 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2013-08-14 04:25:15 -0400 |
commit | a9a7cf08bd080289bbf01ceed9369220f0715684 (patch) | |
tree | 5ee01d6efb976c7aa758aa716a82ab43d657db5e /drivers/dma/mmp_pdma.c | |
parent | 13b3006b8ebd60926a60fc378ff6fe8affa9a194 (diff) |
dma: mmp_pdma: make the controller a DMA provider
This patch makes the mmp_pdma controller able to provide DMA resources
in DT environments by providing an dma xlate function.
of_dma_simple_xlate() isn't used here, because if fails to handle
multiple different DMA engines or several instances of the same
controller. Instead, a private implementation is provided that makes use
of the newly introduced dma_get_slave_channel() call.
Signed-off-by: Daniel Mack <zonque@gmail.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/mmp_pdma.c')
-rw-r--r-- | drivers/dma/mmp_pdma.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index dd024d4759e7..76884c48ea85 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/platform_data/mmp_dma.h> | 18 | #include <linux/platform_data/mmp_dma.h> |
19 | #include <linux/dmapool.h> | 19 | #include <linux/dmapool.h> |
20 | #include <linux/of_device.h> | 20 | #include <linux/of_device.h> |
21 | #include <linux/of_dma.h> | ||
21 | #include <linux/of.h> | 22 | #include <linux/of.h> |
22 | #include <linux/dma/mmp-pdma.h> | 23 | #include <linux/dma/mmp-pdma.h> |
23 | 24 | ||
@@ -777,6 +778,39 @@ static struct of_device_id mmp_pdma_dt_ids[] = { | |||
777 | }; | 778 | }; |
778 | MODULE_DEVICE_TABLE(of, mmp_pdma_dt_ids); | 779 | MODULE_DEVICE_TABLE(of, mmp_pdma_dt_ids); |
779 | 780 | ||
781 | static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec, | ||
782 | struct of_dma *ofdma) | ||
783 | { | ||
784 | struct mmp_pdma_device *d = ofdma->of_dma_data; | ||
785 | struct dma_chan *chan, *candidate; | ||
786 | |||
787 | retry: | ||
788 | candidate = NULL; | ||
789 | |||
790 | /* walk the list of channels registered with the current instance and | ||
791 | * find one that is currently unused */ | ||
792 | list_for_each_entry(chan, &d->device.channels, device_node) | ||
793 | if (chan->client_count == 0) { | ||
794 | candidate = chan; | ||
795 | break; | ||
796 | } | ||
797 | |||
798 | if (!candidate) | ||
799 | return NULL; | ||
800 | |||
801 | /* dma_get_slave_channel will return NULL if we lost a race between | ||
802 | * the lookup and the reservation */ | ||
803 | chan = dma_get_slave_channel(candidate); | ||
804 | |||
805 | if (chan) { | ||
806 | struct mmp_pdma_chan *c = to_mmp_pdma_chan(chan); | ||
807 | c->drcmr = dma_spec->args[0]; | ||
808 | return chan; | ||
809 | } | ||
810 | |||
811 | goto retry; | ||
812 | } | ||
813 | |||
780 | static int mmp_pdma_probe(struct platform_device *op) | 814 | static int mmp_pdma_probe(struct platform_device *op) |
781 | { | 815 | { |
782 | struct mmp_pdma_device *pdev; | 816 | struct mmp_pdma_device *pdev; |
@@ -863,6 +897,16 @@ static int mmp_pdma_probe(struct platform_device *op) | |||
863 | return ret; | 897 | return ret; |
864 | } | 898 | } |
865 | 899 | ||
900 | if (op->dev.of_node) { | ||
901 | /* Device-tree DMA controller registration */ | ||
902 | ret = of_dma_controller_register(op->dev.of_node, | ||
903 | mmp_pdma_dma_xlate, pdev); | ||
904 | if (ret < 0) { | ||
905 | dev_err(&op->dev, "of_dma_controller_register failed\n"); | ||
906 | return ret; | ||
907 | } | ||
908 | } | ||
909 | |||
866 | dev_info(pdev->device.dev, "initialized\n"); | 910 | dev_info(pdev->device.dev, "initialized\n"); |
867 | return 0; | 911 | return 0; |
868 | } | 912 | } |