提交 152e0bf6 编写于 作者: H Hugues Fruchet 提交者: Mauro Carvalho Chehab

media: stm32-dcmi: add power saving support

Implements runtime & system sleep power management ops.
Signed-off-by: NHugues Fruchet <hugues.fruchet@st.com>
Signed-off-by: NHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: NMauro Carvalho Chehab <mchehab+samsung@kernel.org>
上级 f11552d0
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -22,7 +22,9 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/videodev2.h>
......@@ -567,9 +569,9 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
u32 val = 0;
int ret;
ret = clk_enable(dcmi->mclk);
ret = pm_runtime_get_sync(dcmi->dev);
if (ret) {
dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock\n",
dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync\n",
__func__);
goto err_release_buffers;
}
......@@ -579,7 +581,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
if (ret && ret != -ENOIOCTLCMD) {
dev_err(dcmi->dev, "%s: Failed to start streaming, subdev streamon error",
__func__);
goto err_disable_clock;
goto err_pm_put;
}
spin_lock_irq(&dcmi->irqlock);
......@@ -664,8 +666,8 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
err_subdev_streamoff:
v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0);
err_disable_clock:
clk_disable(dcmi->mclk);
err_pm_put:
pm_runtime_put(dcmi->dev);
err_release_buffers:
spin_lock_irq(&dcmi->irqlock);
......@@ -717,7 +719,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
/* Stop all pending DMA operations */
dmaengine_terminate_all(dcmi->dma_chan);
clk_disable(dcmi->mclk);
pm_runtime_put(dcmi->dev);
if (dcmi->errors_count)
dev_warn(dcmi->dev, "Some errors found while streaming: errors=%d (overrun=%d), buffers=%d\n",
......@@ -1707,12 +1709,6 @@ static int dcmi_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
ret = clk_prepare(mclk);
if (ret) {
dev_err(&pdev->dev, "Unable to prepare mclk %p\n", mclk);
goto err_dma_release;
}
spin_lock_init(&dcmi->irqlock);
mutex_init(&dcmi->lock);
init_completion(&dcmi->complete);
......@@ -1728,7 +1724,7 @@ static int dcmi_probe(struct platform_device *pdev)
/* Initialize the top-level structure */
ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev);
if (ret)
goto err_clk_unprepare;
goto err_dma_release;
dcmi->vdev = video_device_alloc();
if (!dcmi->vdev) {
......@@ -1788,14 +1784,15 @@ static int dcmi_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "Probe done\n");
platform_set_drvdata(pdev, dcmi);
pm_runtime_enable(&pdev->dev);
return 0;
err_device_release:
video_device_release(dcmi->vdev);
err_device_unregister:
v4l2_device_unregister(&dcmi->v4l2_dev);
err_clk_unprepare:
clk_unprepare(dcmi->mclk);
err_dma_release:
dma_release_channel(dcmi->dma_chan);
......@@ -1806,20 +1803,72 @@ static int dcmi_remove(struct platform_device *pdev)
{
struct stm32_dcmi *dcmi = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
v4l2_async_notifier_unregister(&dcmi->notifier);
v4l2_device_unregister(&dcmi->v4l2_dev);
clk_unprepare(dcmi->mclk);
dma_release_channel(dcmi->dma_chan);
return 0;
}
static __maybe_unused int dcmi_runtime_suspend(struct device *dev)
{
struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
clk_disable_unprepare(dcmi->mclk);
return 0;
}
static __maybe_unused int dcmi_runtime_resume(struct device *dev)
{
struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(dcmi->mclk);
if (ret)
dev_err(dev, "%s: Failed to prepare_enable clock\n", __func__);
return ret;
}
static __maybe_unused int dcmi_suspend(struct device *dev)
{
/* disable clock */
pm_runtime_force_suspend(dev);
/* change pinctrl state */
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static __maybe_unused int dcmi_resume(struct device *dev)
{
/* restore pinctl default state */
pinctrl_pm_select_default_state(dev);
/* clock enable */
pm_runtime_force_resume(dev);
return 0;
}
static const struct dev_pm_ops dcmi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dcmi_suspend, dcmi_resume)
SET_RUNTIME_PM_OPS(dcmi_runtime_suspend,
dcmi_runtime_resume, NULL)
};
static struct platform_driver stm32_dcmi_driver = {
.probe = dcmi_probe,
.remove = dcmi_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(stm32_dcmi_of_match),
.pm = &dcmi_pm_ops,
},
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部