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>
This commit is contained in:
Hongbo Zhang 2014-05-21 16:03:02 +08:00 committed by Vinod Koul
parent 2baff5700b
commit 14c6a3333c
2 changed files with 92 additions and 0 deletions

View File

@ -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,

View File

@ -134,6 +134,17 @@ struct fsldma_device {
#define FSL_DMA_CHAN_PAUSE_EXT 0x00001000
#define FSL_DMA_CHAN_START_EXT 0x00002000
#ifdef CONFIG_PM
struct fsldma_chan_regs_save {
u32 mr;
};
enum fsldma_pm_state {
RUNNING = 0,
SUSPENDED,
};
#endif
struct fsldma_chan {
char name[8]; /* Channel name */
struct fsldma_chan_regs __iomem *regs;
@ -148,6 +159,10 @@ struct fsldma_chan {
struct tasklet_struct tasklet;
u32 feature;
bool idle; /* DMA controller is idle */
#ifdef CONFIG_PM
struct fsldma_chan_regs_save regs_save;
enum fsldma_pm_state pm_state;
#endif
void (*toggle_ext_pause)(struct fsldma_chan *fsl_chan, int enable);
void (*toggle_ext_start)(struct fsldma_chan *fsl_chan, int enable);