Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14c6a333 authored by Hongbo Zhang's avatar Hongbo Zhang Committed by Vinod Koul
Browse files

dmaengine: Freescale: add suspend resume functions for DMA driver



This patch adds suspend and resume functions for Freescale DMA driver.

Signed-off-by: default avatarHongbo Zhang <hongbo.zhang@freescale.com>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
parent 2baff570
Loading
Loading
Loading
Loading
+77 −0
Original line number Original line Diff line number Diff line
@@ -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,
+15 −0
Original line number Original line Diff line number Diff line
@@ -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);