aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/sirf-dma.c
diff options
context:
space:
mode:
authorBarry Song <21cnbao@gmail.com>2013-07-30 05:44:34 -0400
committerVinod Koul <vinod.koul@intel.com>2013-08-13 07:31:01 -0400
commit2a76689bcaecf35391e6ddc8a00c09c79d6d5857 (patch)
tree8723262ec9fdcc44d057636bd461e8e998f19e72 /drivers/dma/sirf-dma.c
parentd4adcc0160404c3237fe6ffa09dd2dd039dd3975 (diff)
dmaengine: sirf: add PM entries for sleep and runtime
this patch adds PM ops entries in sirf-dma drivers, so that this driver can support suspend/resume, hibernation and runtime PM. while suspending, sirf-dma will lose all registers, so we save them at suspend and restore in resume for active channels. Signed-off-by: Barry Song <Baohua.Song@csr.com> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/sirf-dma.c')
-rw-r--r--drivers/dma/sirf-dma.c132
1 files changed, 129 insertions, 3 deletions
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index 973ecd05dffd..6aec3ad814d3 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -9,6 +9,7 @@
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/dmaengine.h> 10#include <linux/dmaengine.h>
11#include <linux/dma-mapping.h> 11#include <linux/dma-mapping.h>
12#include <linux/pm_runtime.h>
12#include <linux/interrupt.h> 13#include <linux/interrupt.h>
13#include <linux/io.h> 14#include <linux/io.h>
14#include <linux/slab.h> 15#include <linux/slab.h>
@@ -73,6 +74,11 @@ struct sirfsoc_dma_chan {
73 int mode; 74 int mode;
74}; 75};
75 76
77struct sirfsoc_dma_regs {
78 u32 ctrl[SIRFSOC_DMA_CHANNELS];
79 u32 interrupt_en;
80};
81
76struct sirfsoc_dma { 82struct sirfsoc_dma {
77 struct dma_device dma; 83 struct dma_device dma;
78 struct tasklet_struct tasklet; 84 struct tasklet_struct tasklet;
@@ -81,10 +87,13 @@ struct sirfsoc_dma {
81 int irq; 87 int irq;
82 struct clk *clk; 88 struct clk *clk;
83 bool is_marco; 89 bool is_marco;
90 struct sirfsoc_dma_regs regs_save;
84}; 91};
85 92
86#define DRV_NAME "sirfsoc_dma" 93#define DRV_NAME "sirfsoc_dma"
87 94
95static int sirfsoc_dma_runtime_suspend(struct device *dev);
96
88/* Convert struct dma_chan to struct sirfsoc_dma_chan */ 97/* Convert struct dma_chan to struct sirfsoc_dma_chan */
89static inline 98static inline
90struct sirfsoc_dma_chan *dma_chan_to_sirfsoc_dma_chan(struct dma_chan *c) 99struct sirfsoc_dma_chan *dma_chan_to_sirfsoc_dma_chan(struct dma_chan *c)
@@ -393,6 +402,8 @@ static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan)
393 LIST_HEAD(descs); 402 LIST_HEAD(descs);
394 int i; 403 int i;
395 404
405 pm_runtime_get_sync(sdma->dma.dev);
406
396 /* Alloc descriptors for this channel */ 407 /* Alloc descriptors for this channel */
397 for (i = 0; i < SIRFSOC_DMA_DESCRIPTORS; i++) { 408 for (i = 0; i < SIRFSOC_DMA_DESCRIPTORS; i++) {
398 sdesc = kzalloc(sizeof(*sdesc), GFP_KERNEL); 409 sdesc = kzalloc(sizeof(*sdesc), GFP_KERNEL);
@@ -425,6 +436,7 @@ static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan)
425static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan) 436static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan)
426{ 437{
427 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); 438 struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
439 struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
428 struct sirfsoc_dma_desc *sdesc, *tmp; 440 struct sirfsoc_dma_desc *sdesc, *tmp;
429 unsigned long flags; 441 unsigned long flags;
430 LIST_HEAD(descs); 442 LIST_HEAD(descs);
@@ -445,6 +457,8 @@ static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan)
445 /* Free descriptors */ 457 /* Free descriptors */
446 list_for_each_entry_safe(sdesc, tmp, &descs, node) 458 list_for_each_entry_safe(sdesc, tmp, &descs, node)
447 kfree(sdesc); 459 kfree(sdesc);
460
461 pm_runtime_put(sdma->dma.dev);
448} 462}
449 463
450/* Send pending descriptor to hardware */ 464/* Send pending descriptor to hardware */
@@ -723,14 +737,14 @@ static int sirfsoc_dma_probe(struct platform_device *op)
723 737
724 tasklet_init(&sdma->tasklet, sirfsoc_dma_tasklet, (unsigned long)sdma); 738 tasklet_init(&sdma->tasklet, sirfsoc_dma_tasklet, (unsigned long)sdma);
725 739
726 clk_prepare_enable(sdma->clk);
727
728 /* Register DMA engine */ 740 /* Register DMA engine */
729 dev_set_drvdata(dev, sdma); 741 dev_set_drvdata(dev, sdma);
742
730 ret = dma_async_device_register(dma); 743 ret = dma_async_device_register(dma);
731 if (ret) 744 if (ret)
732 goto free_irq; 745 goto free_irq;
733 746
747 pm_runtime_enable(&op->dev);
734 dev_info(dev, "initialized SIRFSOC DMAC driver\n"); 748 dev_info(dev, "initialized SIRFSOC DMAC driver\n");
735 749
736 return 0; 750 return 0;
@@ -747,13 +761,124 @@ static int sirfsoc_dma_remove(struct platform_device *op)
747 struct device *dev = &op->dev; 761 struct device *dev = &op->dev;
748 struct sirfsoc_dma *sdma = dev_get_drvdata(dev); 762 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
749 763
750 clk_disable_unprepare(sdma->clk);
751 dma_async_device_unregister(&sdma->dma); 764 dma_async_device_unregister(&sdma->dma);
752 free_irq(sdma->irq, sdma); 765 free_irq(sdma->irq, sdma);
753 irq_dispose_mapping(sdma->irq); 766 irq_dispose_mapping(sdma->irq);
767 pm_runtime_disable(&op->dev);
768 if (!pm_runtime_status_suspended(&op->dev))
769 sirfsoc_dma_runtime_suspend(&op->dev);
770
771 return 0;
772}
773
774static int sirfsoc_dma_runtime_suspend(struct device *dev)
775{
776 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
777
778 clk_disable_unprepare(sdma->clk);
779 return 0;
780}
781
782static int sirfsoc_dma_runtime_resume(struct device *dev)
783{
784 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
785 int ret;
786
787 ret = clk_prepare_enable(sdma->clk);
788 if (ret < 0) {
789 dev_err(dev, "clk_enable failed: %d\n", ret);
790 return ret;
791 }
792 return 0;
793}
794
795static int sirfsoc_dma_pm_suspend(struct device *dev)
796{
797 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
798 struct sirfsoc_dma_regs *save = &sdma->regs_save;
799 struct sirfsoc_dma_desc *sdesc;
800 struct sirfsoc_dma_chan *schan;
801 int ch;
802 int ret;
803
804 /*
805 * if we were runtime-suspended before, resume to enable clock
806 * before accessing register
807 */
808 if (pm_runtime_status_suspended(dev)) {
809 ret = sirfsoc_dma_runtime_resume(dev);
810 if (ret < 0)
811 return ret;
812 }
813
814 /*
815 * DMA controller will lose all registers while suspending
816 * so we need to save registers for active channels
817 */
818 for (ch = 0; ch < SIRFSOC_DMA_CHANNELS; ch++) {
819 schan = &sdma->channels[ch];
820 if (list_empty(&schan->active))
821 continue;
822 sdesc = list_first_entry(&schan->active,
823 struct sirfsoc_dma_desc,
824 node);
825 save->ctrl[ch] = readl_relaxed(sdma->base +
826 ch * 0x10 + SIRFSOC_DMA_CH_CTRL);
827 }
828 save->interrupt_en = readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN);
829
830 /* Disable clock */
831 sirfsoc_dma_runtime_suspend(dev);
832
833 return 0;
834}
835
836static int sirfsoc_dma_pm_resume(struct device *dev)
837{
838 struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
839 struct sirfsoc_dma_regs *save = &sdma->regs_save;
840 struct sirfsoc_dma_desc *sdesc;
841 struct sirfsoc_dma_chan *schan;
842 int ch;
843 int ret;
844
845 /* Enable clock before accessing register */
846 ret = sirfsoc_dma_runtime_resume(dev);
847 if (ret < 0)
848 return ret;
849
850 writel_relaxed(save->interrupt_en, sdma->base + SIRFSOC_DMA_INT_EN);
851 for (ch = 0; ch < SIRFSOC_DMA_CHANNELS; ch++) {
852 schan = &sdma->channels[ch];
853 if (list_empty(&schan->active))
854 continue;
855 sdesc = list_first_entry(&schan->active,
856 struct sirfsoc_dma_desc,
857 node);
858 writel_relaxed(sdesc->width,
859 sdma->base + SIRFSOC_DMA_WIDTH_0 + ch * 4);
860 writel_relaxed(sdesc->xlen,
861 sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_XLEN);
862 writel_relaxed(sdesc->ylen,
863 sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_YLEN);
864 writel_relaxed(save->ctrl[ch],
865 sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_CTRL);
866 writel_relaxed(sdesc->addr >> 2,
867 sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_ADDR);
868 }
869
870 /* if we were runtime-suspended before, suspend again */
871 if (pm_runtime_status_suspended(dev))
872 sirfsoc_dma_runtime_suspend(dev);
873
754 return 0; 874 return 0;
755} 875}
756 876
877static const struct dev_pm_ops sirfsoc_dma_pm_ops = {
878 SET_RUNTIME_PM_OPS(sirfsoc_dma_runtime_suspend, sirfsoc_dma_runtime_resume, NULL)
879 SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_dma_pm_suspend, sirfsoc_dma_pm_resume)
880};
881
757static struct of_device_id sirfsoc_dma_match[] = { 882static struct of_device_id sirfsoc_dma_match[] = {
758 { .compatible = "sirf,prima2-dmac", }, 883 { .compatible = "sirf,prima2-dmac", },
759 { .compatible = "sirf,marco-dmac", }, 884 { .compatible = "sirf,marco-dmac", },
@@ -766,6 +891,7 @@ static struct platform_driver sirfsoc_dma_driver = {
766 .driver = { 891 .driver = {
767 .name = DRV_NAME, 892 .name = DRV_NAME,
768 .owner = THIS_MODULE, 893 .owner = THIS_MODULE,
894 .pm = &sirfsoc_dma_pm_ops,
769 .of_match_table = sirfsoc_dma_match, 895 .of_match_table = sirfsoc_dma_match,
770 }, 896 },
771}; 897};