forked from luck/tmp_suning_uos_patched
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:
parent
2baff5700b
commit
14c6a3333c
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user