diff options
Diffstat (limited to 'drivers/gpu/ipu-v3/ipu-prg.c')
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prg.c | 71 |
1 files changed, 50 insertions, 21 deletions
diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c index 0013ca9f72c8..fd98f48e8a08 100644 --- a/drivers/gpu/ipu-v3/ipu-prg.c +++ b/drivers/gpu/ipu-v3/ipu-prg.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <video/imx-ipu-v3.h> @@ -139,21 +140,11 @@ EXPORT_SYMBOL_GPL(ipu_prg_format_supported); int ipu_prg_enable(struct ipu_soc *ipu) { struct ipu_prg *prg = ipu->prg_priv; - int ret; if (!prg) return 0; - ret = clk_prepare_enable(prg->clk_axi); - if (ret) - goto fail_disable_ipg; - - return 0; - -fail_disable_ipg: - clk_disable_unprepare(prg->clk_ipg); - - return ret; + return pm_runtime_get_sync(prg->dev); } EXPORT_SYMBOL_GPL(ipu_prg_enable); @@ -164,7 +155,7 @@ void ipu_prg_disable(struct ipu_soc *ipu) if (!prg) return; - clk_disable_unprepare(prg->clk_axi); + pm_runtime_put(prg->dev); } EXPORT_SYMBOL_GPL(ipu_prg_disable); @@ -255,7 +246,7 @@ void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan) if (!chan->enabled || prg_chan < 0) return; - clk_prepare_enable(prg->clk_ipg); + pm_runtime_get_sync(prg->dev); val = readl(prg->regs + IPU_PRG_CTL); val |= IPU_PRG_CTL_BYPASS(prg_chan); @@ -264,7 +255,7 @@ void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan) val = IPU_PRG_REG_UPDATE_REG_UPDATE; writel(val, prg->regs + IPU_PRG_REG_UPDATE); - clk_disable_unprepare(prg->clk_ipg); + pm_runtime_put(prg->dev); ipu_prg_put_pre(prg, prg_chan); @@ -299,11 +290,7 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, width, height, stride, format, *eba); - ret = clk_prepare_enable(prg->clk_ipg); - if (ret) { - ipu_prg_put_pre(prg, prg_chan); - return ret; - } + pm_runtime_get_sync(prg->dev); val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK; writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan)); @@ -336,7 +323,7 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)), 5, 1000); - clk_disable_unprepare(prg->clk_ipg); + pm_runtime_put(prg->dev); chan->enabled = true; return 0; @@ -384,6 +371,12 @@ static int ipu_prg_probe(struct platform_device *pdev) if (ret) return ret; + ret = clk_prepare_enable(prg->clk_axi); + if (ret) { + clk_disable_unprepare(prg->clk_ipg); + return ret; + } + /* init to free running mode */ val = readl(prg->regs + IPU_PRG_CTL); val |= IPU_PRG_CTL_SHADOW_EN; @@ -392,7 +385,8 @@ static int ipu_prg_probe(struct platform_device *pdev) /* disable address threshold */ writel(0xffffffff, prg->regs + IPU_PRG_THD); - clk_disable_unprepare(prg->clk_ipg); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); prg->dev = dev; platform_set_drvdata(pdev, prg); @@ -414,6 +408,40 @@ static int ipu_prg_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int prg_suspend(struct device *dev) +{ + struct ipu_prg *prg = dev_get_drvdata(dev); + + clk_disable_unprepare(prg->clk_axi); + clk_disable_unprepare(prg->clk_ipg); + + return 0; +} + +static int prg_resume(struct device *dev) +{ + struct ipu_prg *prg = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(prg->clk_ipg); + if (ret) + return ret; + + ret = clk_prepare_enable(prg->clk_axi); + if (ret) { + clk_disable_unprepare(prg->clk_ipg); + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops prg_pm_ops = { + SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL) +}; + static const struct of_device_id ipu_prg_dt_ids[] = { { .compatible = "fsl,imx6qp-prg", }, { /* sentinel */ }, @@ -424,6 +452,7 @@ struct platform_driver ipu_prg_drv = { .remove = ipu_prg_remove, .driver = { .name = "imx-ipu-prg", + .pm = &prg_pm_ops, .of_match_table = ipu_prg_dt_ids, }, }; |