|
@@ -400,6 +400,14 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
|
|
|
|
|
|
spin_lock_bh(&chan->desc_lock);
|
|
|
|
|
|
+#ifdef CONFIG_PM
|
|
|
+ if (unlikely(chan->pm_state != RUNNING)) {
|
|
|
+ chan_dbg(chan, "cannot submit due to suspend\n");
|
|
|
+ spin_unlock_bh(&chan->desc_lock);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
/*
|
|
|
* assign cookies to all of the software descriptors
|
|
|
* that make up this transaction
|
|
@@ -1221,6 +1229,9 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
|
|
|
INIT_LIST_HEAD(&chan->ld_pending);
|
|
|
INIT_LIST_HEAD(&chan->ld_running);
|
|
|
chan->idle = true;
|
|
|
+#ifdef CONFIG_PM
|
|
|
+ chan->pm_state = RUNNING;
|
|
|
+#endif
|
|
|
|
|
|
chan->common.device = &fdev->common;
|
|
|
dma_cookie_init(&chan->common);
|
|
@@ -1360,6 +1371,69 @@ static int fsldma_of_remove(struct platform_device *op)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_PM
|
|
|
+static int fsldma_suspend_late(struct device *dev)
|
|
|
+{
|
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
|
+ struct fsldma_device *fdev = platform_get_drvdata(pdev);
|
|
|
+ struct fsldma_chan *chan;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
|
|
|
+ chan = fdev->chan[i];
|
|
|
+ if (!chan)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ spin_lock_bh(&chan->desc_lock);
|
|
|
+ if (unlikely(!chan->idle))
|
|
|
+ goto out;
|
|
|
+ chan->regs_save.mr = get_mr(chan);
|
|
|
+ chan->pm_state = SUSPENDED;
|
|
|
+ spin_unlock_bh(&chan->desc_lock);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out:
|
|
|
+ for (; i >= 0; i--) {
|
|
|
+ chan = fdev->chan[i];
|
|
|
+ if (!chan)
|
|
|
+ continue;
|
|
|
+ chan->pm_state = RUNNING;
|
|
|
+ spin_unlock_bh(&chan->desc_lock);
|
|
|
+ }
|
|
|
+ return -EBUSY;
|
|
|
+}
|
|
|
+
|
|
|
+static int fsldma_resume_early(struct device *dev)
|
|
|
+{
|
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
|
+ struct fsldma_device *fdev = platform_get_drvdata(pdev);
|
|
|
+ struct fsldma_chan *chan;
|
|
|
+ u32 mode;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
|
|
|
+ chan = fdev->chan[i];
|
|
|
+ if (!chan)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ spin_lock_bh(&chan->desc_lock);
|
|
|
+ mode = chan->regs_save.mr
|
|
|
+ & ~FSL_DMA_MR_CS & ~FSL_DMA_MR_CC & ~FSL_DMA_MR_CA;
|
|
|
+ set_mr(chan, mode);
|
|
|
+ chan->pm_state = RUNNING;
|
|
|
+ spin_unlock_bh(&chan->desc_lock);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct dev_pm_ops fsldma_pm_ops = {
|
|
|
+ .suspend_late = fsldma_suspend_late,
|
|
|
+ .resume_early = fsldma_resume_early,
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
static const struct of_device_id fsldma_of_ids[] = {
|
|
|
{ .compatible = "fsl,elo3-dma", },
|
|
|
{ .compatible = "fsl,eloplus-dma", },
|
|
@@ -1372,6 +1446,9 @@ static struct platform_driver fsldma_of_driver = {
|
|
|
.name = "fsl-elo-dma",
|
|
|
.owner = THIS_MODULE,
|
|
|
.of_match_table = fsldma_of_ids,
|
|
|
+#ifdef CONFIG_PM
|
|
|
+ .pm = &fsldma_pm_ops,
|
|
|
+#endif
|
|
|
},
|
|
|
.probe = fsldma_of_probe,
|
|
|
.remove = fsldma_of_remove,
|