Commit e9e21083 authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab

[media] s5p-fimc: Add runtime PM support in the mem-to-mem driver

Add runtime PM and system sleep support in the memory-to-memory
driver. It's required to enable the FIMC operation on Exynos4
SoCs. This patch prevents system boot failure when the driver
is compiled in, as it now tries to access its I/O memory without
first enabling the corresponding power domain.

The camera capture device suspend/resume is not fully covered,
the capture device is just powered on/off during the video
node open/close. However this enables it's normal operation
on Exynos4 SoCs.

[mchehab@redhat.com: fix a small checkpatch error]
Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent bd323e28
...@@ -950,7 +950,7 @@ config VIDEO_MX2 ...@@ -950,7 +950,7 @@ config VIDEO_MX2
config VIDEO_SAMSUNG_S5P_FIMC config VIDEO_SAMSUNG_S5P_FIMC
tristate "Samsung S5P and EXYNOS4 camera host interface driver" tristate "Samsung S5P and EXYNOS4 camera host interface driver"
depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P depends on VIDEO_V4L2 && PLAT_S5P && PM_RUNTIME
select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV select V4L2_MEM2MEM_DEV
---help--- ---help---
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clk.h> #include <linux/clk.h>
...@@ -271,6 +272,16 @@ static int stop_streaming(struct vb2_queue *q) ...@@ -271,6 +272,16 @@ static int stop_streaming(struct vb2_queue *q)
return fimc_stop_capture(fimc); return fimc_stop_capture(fimc);
} }
int fimc_capture_suspend(struct fimc_dev *fimc)
{
return -EBUSY;
}
int fimc_capture_resume(struct fimc_dev *fimc)
{
return 0;
}
static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane)
{ {
if (!fr || plane >= fr->fmt->memplanes) if (!fr || plane >= fr->fmt->memplanes)
...@@ -396,9 +407,14 @@ static int fimc_capture_open(struct file *file) ...@@ -396,9 +407,14 @@ static int fimc_capture_open(struct file *file)
if (fimc_m2m_active(fimc)) if (fimc_m2m_active(fimc))
return -EBUSY; return -EBUSY;
ret = pm_runtime_get_sync(&fimc->pdev->dev);
if (ret)
return ret;
if (++fimc->vid_cap.refcnt == 1) { if (++fimc->vid_cap.refcnt == 1) {
ret = fimc_isp_subdev_init(fimc, 0); ret = fimc_isp_subdev_init(fimc, 0);
if (ret) { if (ret) {
pm_runtime_put_sync(&fimc->pdev->dev);
fimc->vid_cap.refcnt--; fimc->vid_cap.refcnt--;
return -EIO; return -EIO;
} }
...@@ -426,6 +442,8 @@ static int fimc_capture_close(struct file *file) ...@@ -426,6 +442,8 @@ static int fimc_capture_close(struct file *file)
fimc_subdev_unregister(fimc); fimc_subdev_unregister(fimc);
} }
pm_runtime_put(&fimc->pdev->dev);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -48,22 +48,26 @@ enum { ...@@ -48,22 +48,26 @@ enum {
}; };
enum fimc_dev_flags { enum fimc_dev_flags {
/* for m2m node */ ST_LPM,
ST_IDLE, /* m2m node */
ST_OUTDMA_RUN, ST_M2M_RUN,
ST_M2M_PEND, ST_M2M_PEND,
/* for capture node */ ST_M2M_SUSPENDING,
ST_M2M_SUSPENDED,
/* capture node */
ST_CAPT_PEND, ST_CAPT_PEND,
ST_CAPT_RUN, ST_CAPT_RUN,
ST_CAPT_STREAM, ST_CAPT_STREAM,
ST_CAPT_SHUT, ST_CAPT_SHUT,
ST_CAPT_BUSY,
}; };
#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state) #define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state)
#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state) #define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state)
#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state) #define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state) #define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
#define fimc_capture_busy(dev) test_bit(ST_CAPT_BUSY, &(dev)->state)
enum fimc_datapath { enum fimc_datapath {
FIMC_CAMERA, FIMC_CAMERA,
...@@ -644,6 +648,8 @@ void fimc_unregister_capture_device(struct fimc_dev *fimc); ...@@ -644,6 +648,8 @@ void fimc_unregister_capture_device(struct fimc_dev *fimc);
int fimc_sensor_sd_init(struct fimc_dev *fimc, int index); int fimc_sensor_sd_init(struct fimc_dev *fimc, int index);
int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
struct fimc_vid_buffer *fimc_vb); struct fimc_vid_buffer *fimc_vb);
int fimc_capture_suspend(struct fimc_dev *fimc);
int fimc_capture_resume(struct fimc_dev *fimc);
/* Locking: the caller holds fimc->slock */ /* Locking: the caller holds fimc->slock */
static inline void fimc_activate_capture(struct fimc_ctx *ctx) static inline void fimc_activate_capture(struct fimc_ctx *ctx)
......
...@@ -30,7 +30,7 @@ void fimc_hw_reset(struct fimc_dev *dev) ...@@ -30,7 +30,7 @@ void fimc_hw_reset(struct fimc_dev *dev)
cfg = readl(dev->regs + S5P_CIGCTRL); cfg = readl(dev->regs + S5P_CIGCTRL);
cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL); cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL);
writel(cfg, dev->regs + S5P_CIGCTRL); writel(cfg, dev->regs + S5P_CIGCTRL);
udelay(1000); udelay(10);
cfg = readl(dev->regs + S5P_CIGCTRL); cfg = readl(dev->regs + S5P_CIGCTRL);
cfg &= ~S5P_CIGCTRL_SWRST; cfg &= ~S5P_CIGCTRL_SWRST;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment