diff options
author | Hongbo Zhang <hongbo.zhang@freescale.com> | 2014-05-21 04:03:02 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2014-07-14 12:02:18 -0400 |
commit | 14c6a3333c8e885604fc98768d8b9a32e08110ac (patch) | |
tree | 5dae60ced4af6ade4439b656730d05e09c8ae393 /drivers/dma | |
parent | 2baff5700b0832632f05c2ae93362fe3320cc735 (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.c | 77 | ||||
-rw-r--r-- | drivers/dma/fsldma.h | 15 |
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 | ||
1375 | static 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 | |||
1396 | out: | ||
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 | |||
1407 | static 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 | |||
1431 | static const struct dev_pm_ops fsldma_pm_ops = { | ||
1432 | .suspend_late = fsldma_suspend_late, | ||
1433 | .resume_early = fsldma_resume_early, | ||
1434 | }; | ||
1435 | #endif | ||
1436 | |||
1363 | static const struct of_device_id fsldma_of_ids[] = { | 1437 | static 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 | ||
138 | struct fsldma_chan_regs_save { | ||
139 | u32 mr; | ||
140 | }; | ||
141 | |||
142 | enum fsldma_pm_state { | ||
143 | RUNNING = 0, | ||
144 | SUSPENDED, | ||
145 | }; | ||
146 | #endif | ||
147 | |||
137 | struct fsldma_chan { | 148 | struct 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); |