1
0
Fork 0

MLK-16769-4: dma: mxs-dma: enable runtime PM for mxs-dma

enable runtime pm for mxs-dma

 BuildInfo:
  - SCFW 60e110f9, IMX-MKIMAGE e131af10, ATF
  - U-Boot 2017.03-imx_4.9.51_8qm_beta1_8qxp_alpha+gfcc9bdc

Signed-off-by: Han Xu <han.xu@nxp.com>
pull/10/head
Han Xu 2017-10-30 14:50:33 -05:00 committed by Jason Liu
parent a5b5c43a8a
commit 89e6459a3e
1 changed files with 69 additions and 12 deletions

View File

@ -29,6 +29,7 @@
#include <linux/of_dma.h>
#include <linux/list.h>
#include <asm/irq.h>
#include <linux/pm_runtime.h>
#include "dmaengine.h"
@ -41,6 +42,8 @@
#define dma_is_apbh(mxs_dma) ((mxs_dma)->type == MXS_DMA_APBH)
#define apbh_is_old(mxs_dma) ((mxs_dma)->dev_id == IMX23_DMA)
#define MXS_DMA_RPM_TIMEOUT 50 /* ms */
#define HW_APBHX_CTRL0 0x000
#define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29)
#define BM_APBH_CTRL0_APB_BURST_EN (1 << 28)
@ -434,6 +437,7 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
{
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
struct device *dev = &mxs_dma->pdev->dev;
int ret;
mxs_chan->ccw = dma_zalloc_coherent(mxs_dma->dma_device.dev,
@ -449,9 +453,11 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
if (ret)
goto err_irq;
ret = clk_prepare_enable(mxs_dma->clk);
if (ret)
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "Failed to enable clock\n");
goto err_clk;
}
mxs_dma_reset_chan(chan);
@ -463,7 +469,6 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
return 0;
clk_disable_unprepare(mxs_dma->clk);
err_clk:
free_irq(mxs_chan->chan_irq, mxs_dma);
err_irq:
@ -477,6 +482,7 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
{
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
struct device *dev = &mxs_dma->pdev->dev;
mxs_dma_disable_chan(chan);
@ -485,7 +491,9 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
dma_free_coherent(mxs_dma->dma_device.dev, CCW_BLOCK_SIZE,
mxs_chan->ccw, mxs_chan->ccw_phys);
clk_disable_unprepare(mxs_dma->clk);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}
/*
@ -707,14 +715,32 @@ static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
return mxs_chan->status;
}
static int mxs_dma_init_rpm(struct mxs_dma_engine *mxs_dma)
{
struct device *dev = &mxs_dma->pdev->dev;
pm_runtime_enable(dev);
pm_runtime_set_autosuspend_delay(dev, MXS_DMA_RPM_TIMEOUT);
pm_runtime_use_autosuspend(dev);
return 0;
}
static int mxs_dma_init(struct mxs_dma_engine *mxs_dma)
{
int ret;
struct device *dev = &mxs_dma->pdev->dev;
ret = clk_prepare_enable(mxs_dma->clk);
ret = mxs_dma_init_rpm(mxs_dma);
if (ret)
return ret;
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "Failed to enable clock\n");
return ret;
}
ret = stmp_reset_block(mxs_dma->base);
if (ret)
goto err_clk;
@ -732,7 +758,8 @@ static int mxs_dma_init(struct mxs_dma_engine *mxs_dma)
mxs_dma->base + HW_APBHX_CTRL1 + STMP_OFFSET_REG_SET);
err_clk:
clk_disable_unprepare(mxs_dma->clk);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return ret;
}
@ -847,11 +874,13 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
&mxs_dma->dma_device.channels);
}
platform_set_drvdata(pdev, mxs_dma);
mxs_dma->pdev = pdev;
ret = mxs_dma_init(mxs_dma);
if (ret)
return ret;
mxs_dma->pdev = pdev;
mxs_dma->dma_device.dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, mxs_dma);
@ -893,11 +922,11 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
static int mxs_dma_pm_suspend(struct device *dev)
{
/*
* We do not save any registers here, since the gpmi will release its
* DMA channel.
*/
return 0;
int ret;
ret = pm_runtime_force_suspend(dev);
return ret;
}
static int mxs_dma_pm_resume(struct device *dev)
@ -905,13 +934,41 @@ static int mxs_dma_pm_resume(struct device *dev)
struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
ret = mxs_dma_init(mxs_dma);
if (ret)
return ret;
return 0;
}
int mxs_dma_runtime_suspend(struct device *dev)
{
struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev);
clk_disable_unprepare(mxs_dma->clk);
return 0;
}
int mxs_dma_runtime_resume(struct device *dev)
{
struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(mxs_dma->clk);
if (ret) {
dev_err(&mxs_dma->pdev->dev, "failed to enable the clock\n");
return ret;
}
return 0;
}
static const struct dev_pm_ops mxs_dma_pm_ops = {
SET_RUNTIME_PM_OPS(mxs_dma_runtime_suspend, mxs_dma_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(mxs_dma_pm_suspend, mxs_dma_pm_resume)
};