aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorHongbo Zhang <hongbo.zhang@freescale.com>2014-05-21 04:03:02 -0400
committerVinod Koul <vinod.koul@intel.com>2014-07-14 12:02:18 -0400
commit14c6a3333c8e885604fc98768d8b9a32e08110ac (patch)
tree5dae60ced4af6ade4439b656730d05e09c8ae393 /drivers/dma
parent2baff5700b0832632f05c2ae93362fe3320cc735 (diff)
dmaengine: Freescale: add suspend resume functions for DMA driver
This patch adds suspend and resume functions for Freescale DMA driver. Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/fsldma.c77
-rw-r--r--drivers/dma/fsldma.h15
2 files changed, 92 insertions, 0 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index b291e6c65053..465f16dd78e5 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -400,6 +400,14 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
400 400
401 spin_lock_bh(&chan->desc_lock); 401 spin_lock_bh(&chan->desc_lock);
402 402
403#ifdef CONFIG_PM
404 if (unlikely(chan->pm_state != RUNNING)) {
405 chan_dbg(chan, "cannot submit due to suspend\n");
406 spin_unlock_bh(&chan->desc_lock);
407 return -1;
408 }
409#endif
410
403 /* 411 /*
404 * assign cookies to all of the software descriptors 412 * assign cookies to all of the software descriptors
405 * that make up this transaction 413 * that make up this transaction
@@ -1221,6 +1229,9 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
1221 INIT_LIST_HEAD(&chan->ld_pending); 1229 INIT_LIST_HEAD(&chan->ld_pending);
1222 INIT_LIST_HEAD(&chan->ld_running); 1230 INIT_LIST_HEAD(&chan->ld_running);
1223 chan->idle = true; 1231 chan->idle = true;
1232#ifdef CONFIG_PM
1233 chan->pm_state = RUNNING;
1234#endif
1224 1235
1225 chan->common.device = &fdev->common; 1236 chan->common.device = &fdev->common;
1226 dma_cookie_init(&chan->common); 1237 dma_cookie_init(&chan->common);
@@ -1360,6 +1371,69 @@ static int fsldma_of_remove(struct platform_device *op)
1360 return 0; 1371 return 0;
1361} 1372}
1362 1373
1374#ifdef CONFIG_PM
1375static int fsldma_suspend_late(struct device *dev)
1376{
1377 struct platform_device *pdev = to_platform_device(dev);
1378 struct fsldma_device *fdev = platform_get_drvdata(pdev);
1379 struct fsldma_chan *chan;
1380 int i;
1381
1382 for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
1383 chan = fdev->chan[i];
1384 if (!chan)
1385 continue;
1386
1387 spin_lock_bh(&chan->desc_lock);
1388 if (unlikely(!chan->idle))
1389 goto out;
1390 chan->regs_save.mr = get_mr(chan);
1391 chan->pm_state = SUSPENDED;
1392 spin_unlock_bh(&chan->desc_lock);
1393 }
1394 return 0;
1395
1396out:
1397 for (; i >= 0; i--) {
1398 chan = fdev->chan[i];
1399 if (!chan)
1400 continue;
1401 chan->pm_state = RUNNING;
1402 spin_unlock_bh(&chan->desc_lock);
1403 }
1404 return -EBUSY;
1405}
1406
1407static int fsldma_resume_early(struct device *dev)
1408{
1409 struct platform_device *pdev = to_platform_device(dev);
1410 struct fsldma_device *fdev = platform_get_drvdata(pdev);
1411 struct fsldma_chan *chan;
1412 u32 mode;
1413 int i;
1414
1415 for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
1416 chan = fdev->chan[i];
1417 if (!chan)
1418 continue;
1419
1420 spin_lock_bh(&chan->desc_lock);
1421 mode = chan->regs_save.mr
1422 & ~FSL_DMA_MR_CS & ~FSL_DMA_MR_CC & ~FSL_DMA_MR_CA;
1423 set_mr(chan, mode);
1424 chan->pm_state = RUNNING;
1425 spin_unlock_bh(&chan->desc_lock);
1426 }
1427
1428 return 0;
1429}
1430
1431static const struct dev_pm_ops fsldma_pm_ops = {
1432 .suspend_late = fsldma_suspend_late,
1433 .resume_early = fsldma_resume_early,
1434};
1435#endif
1436
1363static const struct of_device_id fsldma_of_ids[] = { 1437static const struct of_device_id fsldma_of_ids[] = {
1364 { .compatible = "fsl,elo3-dma", }, 1438 { .compatible = "fsl,elo3-dma", },
1365 { .compatible = "fsl,eloplus-dma", }, 1439 { .compatible = "fsl,eloplus-dma", },
@@ -1372,6 +1446,9 @@ static struct platform_driver fsldma_of_driver = {
1372 .name = "fsl-elo-dma", 1446 .name = "fsl-elo-dma",
1373 .owner = THIS_MODULE, 1447 .owner = THIS_MODULE,
1374 .of_match_table = fsldma_of_ids, 1448 .of_match_table = fsldma_of_ids,
1449#ifdef CONFIG_PM
1450 .pm = &fsldma_pm_ops,
1451#endif
1375 }, 1452 },
1376 .probe = fsldma_of_probe, 1453 .probe = fsldma_of_probe,
1377 .remove = fsldma_of_remove, 1454 .remove = fsldma_of_remove,
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index d56e83599825..f2e0c4dcf901 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -134,6 +134,17 @@ struct fsldma_device {
134#define FSL_DMA_CHAN_PAUSE_EXT 0x00001000 134#define FSL_DMA_CHAN_PAUSE_EXT 0x00001000
135#define FSL_DMA_CHAN_START_EXT 0x00002000 135#define FSL_DMA_CHAN_START_EXT 0x00002000
136 136
137#ifdef CONFIG_PM
138struct fsldma_chan_regs_save {
139 u32 mr;
140};
141
142enum fsldma_pm_state {
143 RUNNING = 0,
144 SUSPENDED,
145};
146#endif
147
137struct fsldma_chan { 148struct fsldma_chan {
138 char name[8]; /* Channel name */ 149 char name[8]; /* Channel name */
139 struct fsldma_chan_regs __iomem *regs; 150 struct fsldma_chan_regs __iomem *regs;
@@ -148,6 +159,10 @@ struct fsldma_chan {
148 struct tasklet_struct tasklet; 159 struct tasklet_struct tasklet;
149 u32 feature; 160 u32 feature;
150 bool idle; /* DMA controller is idle */ 161 bool idle; /* DMA controller is idle */
162#ifdef CONFIG_PM
163 struct fsldma_chan_regs_save regs_save;
164 enum fsldma_pm_state pm_state;
165#endif
151 166
152 void (*toggle_ext_pause)(struct fsldma_chan *fsl_chan, int enable); 167 void (*toggle_ext_pause)(struct fsldma_chan *fsl_chan, int enable);
153 void (*toggle_ext_start)(struct fsldma_chan *fsl_chan, int enable); 168 void (*toggle_ext_start)(struct fsldma_chan *fsl_chan, int enable);