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);
|
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
|
* assign cookies to all of the software descriptors
|
||||||
* that make up this transaction
|
* 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_pending);
|
||||||
INIT_LIST_HEAD(&chan->ld_running);
|
INIT_LIST_HEAD(&chan->ld_running);
|
||||||
chan->idle = true;
|
chan->idle = true;
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
chan->pm_state = RUNNING;
|
||||||
|
#endif
|
||||||
|
|
||||||
chan->common.device = &fdev->common;
|
chan->common.device = &fdev->common;
|
||||||
dma_cookie_init(&chan->common);
|
dma_cookie_init(&chan->common);
|
||||||
@ -1360,6 +1371,69 @@ static int fsldma_of_remove(struct platform_device *op)
|
|||||||
return 0;
|
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[] = {
|
static const struct of_device_id fsldma_of_ids[] = {
|
||||||
{ .compatible = "fsl,elo3-dma", },
|
{ .compatible = "fsl,elo3-dma", },
|
||||||
{ .compatible = "fsl,eloplus-dma", },
|
{ .compatible = "fsl,eloplus-dma", },
|
||||||
@ -1372,6 +1446,9 @@ static struct platform_driver fsldma_of_driver = {
|
|||||||
.name = "fsl-elo-dma",
|
.name = "fsl-elo-dma",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.of_match_table = fsldma_of_ids,
|
.of_match_table = fsldma_of_ids,
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.pm = &fsldma_pm_ops,
|
||||||
|
#endif
|
||||||
},
|
},
|
||||||
.probe = fsldma_of_probe,
|
.probe = fsldma_of_probe,
|
||||||
.remove = fsldma_of_remove,
|
.remove = fsldma_of_remove,
|
||||||
|
@ -134,6 +134,17 @@ struct fsldma_device {
|
|||||||
#define FSL_DMA_CHAN_PAUSE_EXT 0x00001000
|
#define FSL_DMA_CHAN_PAUSE_EXT 0x00001000
|
||||||
#define FSL_DMA_CHAN_START_EXT 0x00002000
|
#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 {
|
struct fsldma_chan {
|
||||||
char name[8]; /* Channel name */
|
char name[8]; /* Channel name */
|
||||||
struct fsldma_chan_regs __iomem *regs;
|
struct fsldma_chan_regs __iomem *regs;
|
||||||
@ -148,6 +159,10 @@ struct fsldma_chan {
|
|||||||
struct tasklet_struct tasklet;
|
struct tasklet_struct tasklet;
|
||||||
u32 feature;
|
u32 feature;
|
||||||
bool idle; /* DMA controller is idle */
|
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_pause)(struct fsldma_chan *fsl_chan, int enable);
|
||||||
void (*toggle_ext_start)(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