aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/stm32/stm32-dcmi.c
diff options
context:
space:
mode:
authorHugues Fruchet <hugues.fruchet@st.com>2018-06-13 05:59:39 -0400
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-06-28 07:49:56 -0400
commit152e0bf60219ba589254c7aff4c095943c36cf68 (patch)
tree8204a5f38cd33ba54a181e18b19ffd2a48080609 /drivers/media/platform/stm32/stm32-dcmi.c
parentf11552d030e8e5a0a945b1920e31eaf48fe3fad4 (diff)
media: stm32-dcmi: add power saving support
Implements runtime & system sleep power management ops. Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Diffstat (limited to 'drivers/media/platform/stm32/stm32-dcmi.c')
-rw-r--r--drivers/media/platform/stm32/stm32-dcmi.c81
1 files changed, 65 insertions, 16 deletions
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index 4f65f14fbbc1..721564176d8c 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -22,7 +22,9 @@
22#include <linux/of.h> 22#include <linux/of.h>
23#include <linux/of_device.h> 23#include <linux/of_device.h>
24#include <linux/of_graph.h> 24#include <linux/of_graph.h>
25#include <linux/pinctrl/consumer.h>
25#include <linux/platform_device.h> 26#include <linux/platform_device.h>
27#include <linux/pm_runtime.h>
26#include <linux/reset.h> 28#include <linux/reset.h>
27#include <linux/videodev2.h> 29#include <linux/videodev2.h>
28 30
@@ -567,9 +569,9 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
567 u32 val = 0; 569 u32 val = 0;
568 int ret; 570 int ret;
569 571
570 ret = clk_enable(dcmi->mclk); 572 ret = pm_runtime_get_sync(dcmi->dev);
571 if (ret) { 573 if (ret) {
572 dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock\n", 574 dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync\n",
573 __func__); 575 __func__);
574 goto err_release_buffers; 576 goto err_release_buffers;
575 } 577 }
@@ -579,7 +581,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
579 if (ret && ret != -ENOIOCTLCMD) { 581 if (ret && ret != -ENOIOCTLCMD) {
580 dev_err(dcmi->dev, "%s: Failed to start streaming, subdev streamon error", 582 dev_err(dcmi->dev, "%s: Failed to start streaming, subdev streamon error",
581 __func__); 583 __func__);
582 goto err_disable_clock; 584 goto err_pm_put;
583 } 585 }
584 586
585 spin_lock_irq(&dcmi->irqlock); 587 spin_lock_irq(&dcmi->irqlock);
@@ -664,8 +666,8 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
664err_subdev_streamoff: 666err_subdev_streamoff:
665 v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); 667 v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0);
666 668
667err_disable_clock: 669err_pm_put:
668 clk_disable(dcmi->mclk); 670 pm_runtime_put(dcmi->dev);
669 671
670err_release_buffers: 672err_release_buffers:
671 spin_lock_irq(&dcmi->irqlock); 673 spin_lock_irq(&dcmi->irqlock);
@@ -717,7 +719,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
717 /* Stop all pending DMA operations */ 719 /* Stop all pending DMA operations */
718 dmaengine_terminate_all(dcmi->dma_chan); 720 dmaengine_terminate_all(dcmi->dma_chan);
719 721
720 clk_disable(dcmi->mclk); 722 pm_runtime_put(dcmi->dev);
721 723
722 if (dcmi->errors_count) 724 if (dcmi->errors_count)
723 dev_warn(dcmi->dev, "Some errors found while streaming: errors=%d (overrun=%d), buffers=%d\n", 725 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)
1707 return -EPROBE_DEFER; 1709 return -EPROBE_DEFER;
1708 } 1710 }
1709 1711
1710 ret = clk_prepare(mclk);
1711 if (ret) {
1712 dev_err(&pdev->dev, "Unable to prepare mclk %p\n", mclk);
1713 goto err_dma_release;
1714 }
1715
1716 spin_lock_init(&dcmi->irqlock); 1712 spin_lock_init(&dcmi->irqlock);
1717 mutex_init(&dcmi->lock); 1713 mutex_init(&dcmi->lock);
1718 init_completion(&dcmi->complete); 1714 init_completion(&dcmi->complete);
@@ -1728,7 +1724,7 @@ static int dcmi_probe(struct platform_device *pdev)
1728 /* Initialize the top-level structure */ 1724 /* Initialize the top-level structure */
1729 ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev); 1725 ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev);
1730 if (ret) 1726 if (ret)
1731 goto err_clk_unprepare; 1727 goto err_dma_release;
1732 1728
1733 dcmi->vdev = video_device_alloc(); 1729 dcmi->vdev = video_device_alloc();
1734 if (!dcmi->vdev) { 1730 if (!dcmi->vdev) {
@@ -1788,14 +1784,15 @@ static int dcmi_probe(struct platform_device *pdev)
1788 dev_info(&pdev->dev, "Probe done\n"); 1784 dev_info(&pdev->dev, "Probe done\n");
1789 1785
1790 platform_set_drvdata(pdev, dcmi); 1786 platform_set_drvdata(pdev, dcmi);
1787
1788 pm_runtime_enable(&pdev->dev);
1789
1791 return 0; 1790 return 0;
1792 1791
1793err_device_release: 1792err_device_release:
1794 video_device_release(dcmi->vdev); 1793 video_device_release(dcmi->vdev);
1795err_device_unregister: 1794err_device_unregister:
1796 v4l2_device_unregister(&dcmi->v4l2_dev); 1795 v4l2_device_unregister(&dcmi->v4l2_dev);
1797err_clk_unprepare:
1798 clk_unprepare(dcmi->mclk);
1799err_dma_release: 1796err_dma_release:
1800 dma_release_channel(dcmi->dma_chan); 1797 dma_release_channel(dcmi->dma_chan);
1801 1798
@@ -1806,20 +1803,72 @@ static int dcmi_remove(struct platform_device *pdev)
1806{ 1803{
1807 struct stm32_dcmi *dcmi = platform_get_drvdata(pdev); 1804 struct stm32_dcmi *dcmi = platform_get_drvdata(pdev);
1808 1805
1806 pm_runtime_disable(&pdev->dev);
1807
1809 v4l2_async_notifier_unregister(&dcmi->notifier); 1808 v4l2_async_notifier_unregister(&dcmi->notifier);
1810 v4l2_device_unregister(&dcmi->v4l2_dev); 1809 v4l2_device_unregister(&dcmi->v4l2_dev);
1811 clk_unprepare(dcmi->mclk); 1810
1812 dma_release_channel(dcmi->dma_chan); 1811 dma_release_channel(dcmi->dma_chan);
1813 1812
1814 return 0; 1813 return 0;
1815} 1814}
1816 1815
1816static __maybe_unused int dcmi_runtime_suspend(struct device *dev)
1817{
1818 struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
1819
1820 clk_disable_unprepare(dcmi->mclk);
1821
1822 return 0;
1823}
1824
1825static __maybe_unused int dcmi_runtime_resume(struct device *dev)
1826{
1827 struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
1828 int ret;
1829
1830 ret = clk_prepare_enable(dcmi->mclk);
1831 if (ret)
1832 dev_err(dev, "%s: Failed to prepare_enable clock\n", __func__);
1833
1834 return ret;
1835}
1836
1837static __maybe_unused int dcmi_suspend(struct device *dev)
1838{
1839 /* disable clock */
1840 pm_runtime_force_suspend(dev);
1841
1842 /* change pinctrl state */
1843 pinctrl_pm_select_sleep_state(dev);
1844
1845 return 0;
1846}
1847
1848static __maybe_unused int dcmi_resume(struct device *dev)
1849{
1850 /* restore pinctl default state */
1851 pinctrl_pm_select_default_state(dev);
1852
1853 /* clock enable */
1854 pm_runtime_force_resume(dev);
1855
1856 return 0;
1857}
1858
1859static const struct dev_pm_ops dcmi_pm_ops = {
1860 SET_SYSTEM_SLEEP_PM_OPS(dcmi_suspend, dcmi_resume)
1861 SET_RUNTIME_PM_OPS(dcmi_runtime_suspend,
1862 dcmi_runtime_resume, NULL)
1863};
1864
1817static struct platform_driver stm32_dcmi_driver = { 1865static struct platform_driver stm32_dcmi_driver = {
1818 .probe = dcmi_probe, 1866 .probe = dcmi_probe,
1819 .remove = dcmi_remove, 1867 .remove = dcmi_remove,
1820 .driver = { 1868 .driver = {
1821 .name = DRV_NAME, 1869 .name = DRV_NAME,
1822 .of_match_table = of_match_ptr(stm32_dcmi_of_match), 1870 .of_match_table = of_match_ptr(stm32_dcmi_of_match),
1871 .pm = &dcmi_pm_ops,
1823 }, 1872 },
1824}; 1873};
1825 1874