summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorJingchang Lu <jingchang.lu@freescale.com>2014-09-18 02:11:36 (GMT)
committerMatthew Weigel <Matthew.Weigel@freescale.com>2014-12-11 18:38:56 (GMT)
commit5c14af7b5f2c61e55044c7e28ebc50bb99548632 (patch)
tree970e06626c8345a6205a2ab823f9bb2251942f32 /drivers/dma
parentd686c7b10a2ff6a389c62db631c9a2efe6d205a9 (diff)
downloadlinux-fsl-qoriq-5c14af7b5f2c61e55044c7e28ebc50bb99548632.tar.xz
dmaengine: fsl-edma: add PM suspend/resume support
This adds eDMA power management suspend/resume support. Signed-off-by: Jingchang Lu <jingchang.lu@freescale.com> --- This patch depends on patch "dmaengine: fsl-edma: fixup reg offset and hw S/G support in big-endian model", and the upstream will be done after that patch upstreamed. Change-Id: I596bf0934ea1ee4292f2cc64f9db8996becca14c Reviewed-on: http://git.am.freescale.net:8181/21930 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Huan Wang <alison.wang@freescale.com> Reviewed-by: Zhengxiong Jin <Jason.Jin@freescale.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/fsl-edma.c45
1 files changed, 43 insertions, 2 deletions
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 1cc536b..eadb155 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -147,6 +147,7 @@ struct fsl_edma_slave_config {
struct fsl_edma_chan {
struct virt_dma_chan vchan;
enum dma_status status;
+ u32 slave_id;
struct fsl_edma_engine *edma;
struct fsl_edma_desc *edesc;
struct fsl_edma_slave_config fsc;
@@ -774,6 +775,7 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
{
struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
struct dma_chan *chan, *_chan;
+ struct fsl_edma_chan *fsl_chan;
unsigned long chans_per_mux = fsl_edma->n_chans / DMAMUX_NR;
if (dma_spec->args_count != 2)
@@ -787,8 +789,10 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
chan = dma_get_slave_channel(chan);
if (chan) {
chan->device->privatecnt++;
- fsl_edma_chan_mux(to_fsl_edma_chan(chan),
- dma_spec->args[1], true);
+ fsl_chan = to_fsl_edma_chan(chan);
+ fsl_chan->slave_id = dma_spec->args[1];
+ fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id,
+ true);
mutex_unlock(&fsl_edma->fsl_edma_mutex);
return chan;
}
@@ -817,6 +821,7 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan)
spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
fsl_edma_disable_request(fsl_chan);
fsl_edma_chan_mux(fsl_chan, 0, false);
+ fsl_chan->slave_id = 0;
fsl_chan->edesc = NULL;
vchan_get_all_descriptors(&fsl_chan->vchan, &head);
spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
@@ -1005,6 +1010,41 @@ static int fsl_edma_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int fsl_edma_suspend(struct device *dev)
+{
+ struct fsl_edma_engine *fsl_edma = dev_get_drvdata(dev);
+ struct fsl_edma_chan *fsl_chan;
+ int i;
+
+ for (i = 0; i < fsl_edma->n_chans; i++) {
+ fsl_chan = &fsl_edma->chans[i];
+ fsl_edma_chan_mux(fsl_chan, 0, false);
+ }
+
+ return 0;
+}
+
+static int fsl_edma_resume(struct device *dev)
+{
+ struct fsl_edma_engine *fsl_edma = dev_get_drvdata(dev);
+ struct fsl_edma_chan *fsl_chan;
+ int i;
+
+ for (i = 0; i < fsl_edma->n_chans; i++) {
+ fsl_chan = &fsl_edma->chans[i];
+ edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
+ fsl_edma_chan_mux(fsl_chan, fsl_chan->slave_id, true);
+ }
+
+ edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA,
+ fsl_edma->membase + EDMA_CR);
+
+ return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(fsl_edma_pm_ops, fsl_edma_suspend, fsl_edma_resume);
+
static const struct of_device_id fsl_edma_dt_ids[] = {
{ .compatible = "fsl,vf610-edma", },
{ /* sentinel */ }
@@ -1016,6 +1056,7 @@ static struct platform_driver fsl_edma_driver = {
.name = "fsl-edma",
.owner = THIS_MODULE,
.of_match_table = fsl_edma_dt_ids,
+ .pm = &fsl_edma_pm_ops,
},
.probe = fsl_edma_probe,
.remove = fsl_edma_remove,