[media] s5p-fimc: Add runtime PM support in the camera capture driver
authorSylwester Nawrocki <s.nawrocki@samsung.com>
Wed, 24 Aug 2011 23:45:34 +0000 (20:45 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 6 Sep 2011 20:50:31 +0000 (17:50 -0300)
Add support for whole pipeline suspend/resume. Sensors must support
suspend/resume through s_power subdev operation.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-fimc/fimc-core.h

index 469384623952b13d3d83ab0e1e966aea905e318b..d6219c5aeffc274dd1358e1e35152142a45af13a 100644 (file)
@@ -69,41 +69,45 @@ static int fimc_init_capture(struct fimc_dev *fimc)
        return ret;
 }
 
-static int fimc_capture_state_cleanup(struct fimc_dev *fimc)
+static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
 {
        struct fimc_vid_cap *cap = &fimc->vid_cap;
        struct fimc_vid_buffer *buf;
        unsigned long flags;
+       bool streaming;
 
        spin_lock_irqsave(&fimc->slock, flags);
-       fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
-                        1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM |
-                        1 << ST_CAPT_ISP_STREAM);
+       streaming = fimc->state & (1 << ST_CAPT_ISP_STREAM);
 
-       fimc->vid_cap.active_buf_cnt = 0;
+       fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT |
+                        1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM);
+       if (!suspend)
+               fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED);
 
-       /* Release buffers that were enqueued in the driver by videobuf2. */
-       while (!list_empty(&cap->pending_buf_q)) {
+       /* Release unused buffers */
+       while (!suspend && !list_empty(&cap->pending_buf_q)) {
                buf = fimc_pending_queue_pop(cap);
                vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
-
+       /* If suspending put unused buffers onto pending queue */
        while (!list_empty(&cap->active_buf_q)) {
                buf = fimc_active_queue_pop(cap);
-               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+               if (suspend)
+                       fimc_pending_queue_add(cap, buf);
+               else
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
        }
-
+       set_bit(ST_CAPT_SUSPENDED, &fimc->state);
        spin_unlock_irqrestore(&fimc->slock, flags);
 
-       if (test_bit(ST_CAPT_ISP_STREAM, &fimc->state))
+       if (streaming)
                return fimc_pipeline_s_stream(fimc, 0);
        else
                return 0;
 }
 
-static int fimc_stop_capture(struct fimc_dev *fimc)
+static int fimc_stop_capture(struct fimc_dev *fimc, bool suspend)
 {
-       struct fimc_vid_cap *cap = &fimc->vid_cap;
        unsigned long flags;
 
        if (!fimc_capture_active(fimc))
@@ -116,9 +120,9 @@ static int fimc_stop_capture(struct fimc_dev *fimc)
 
        wait_event_timeout(fimc->irq_queue,
                           !test_bit(ST_CAPT_SHUT, &fimc->state),
-                          FIMC_SHUTDOWN_TIMEOUT);
+                          (2*HZ/10)); /* 200 ms */
 
-       return fimc_capture_state_cleanup(fimc);
+       return fimc_capture_state_cleanup(fimc, suspend);
 }
 
 /**
@@ -181,7 +185,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
 
        return 0;
 error:
-       fimc_capture_state_cleanup(fimc);
+       fimc_capture_state_cleanup(fimc, false);
        return ret;
 }
 
@@ -193,17 +197,46 @@ static int stop_streaming(struct vb2_queue *q)
        if (!fimc_capture_active(fimc))
                return -EINVAL;
 
-       return fimc_stop_capture(fimc);
+       return fimc_stop_capture(fimc, false);
 }
 
 int fimc_capture_suspend(struct fimc_dev *fimc)
 {
-       return -EBUSY;
+       bool suspend = fimc_capture_busy(fimc);
+
+       int ret = fimc_stop_capture(fimc, suspend);
+       if (ret)
+               return ret;
+       return fimc_pipeline_shutdown(fimc);
 }
 
+static void buffer_queue(struct vb2_buffer *vb);
+
 int fimc_capture_resume(struct fimc_dev *fimc)
 {
+       struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+       struct fimc_vid_buffer *buf;
+       int i;
+
+       if (!test_and_clear_bit(ST_CAPT_SUSPENDED, &fimc->state))
+               return 0;
+
+       INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
+       vid_cap->buf_index = 0;
+       fimc_pipeline_initialize(fimc, &fimc->vid_cap.vfd->entity,
+                                false);
+       fimc_init_capture(fimc);
+
+       clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
+
+       for (i = 0; i < vid_cap->reqbufs_count; i++) {
+               if (list_empty(&vid_cap->pending_buf_q))
+                       break;
+               buf = fimc_pending_queue_pop(vid_cap);
+               buffer_queue(&buf->vb);
+       }
        return 0;
+
 }
 
 static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane)
@@ -271,8 +304,9 @@ static void buffer_queue(struct vb2_buffer *vb)
        spin_lock_irqsave(&fimc->slock, flags);
        fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr);
 
-       if (!test_bit(ST_CAPT_STREAM, &fimc->state)
-            && vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) {
+       if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) &&
+           !test_bit(ST_CAPT_STREAM, &fimc->state) &&
+           vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) {
                /* Setup the buffer directly for processing. */
                int buf_id = (vid_cap->reqbufs_count == 1) ? -1 :
                                vid_cap->buf_index;
@@ -366,6 +400,7 @@ static int fimc_capture_open(struct file *file)
        if (fimc_m2m_active(fimc))
                return -EBUSY;
 
+       set_bit(ST_CAPT_BUSY, &fimc->state);
        pm_runtime_get_sync(&fimc->pdev->dev);
 
        if (++fimc->vid_cap.refcnt == 1) {
@@ -377,6 +412,7 @@ static int fimc_capture_open(struct file *file)
                        pm_runtime_put_sync(&fimc->pdev->dev);
                        fimc->vid_cap.refcnt--;
                        v4l2_fh_release(file);
+                       clear_bit(ST_CAPT_BUSY, &fimc->state);
                        return ret;
                }
                ret = fimc_capture_ctrls_create(fimc);
@@ -394,14 +430,18 @@ static int fimc_capture_close(struct file *file)
        dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
 
        if (--fimc->vid_cap.refcnt == 0) {
-               fimc_stop_capture(fimc);
+               clear_bit(ST_CAPT_BUSY, &fimc->state);
+               fimc_stop_capture(fimc, false);
                fimc_pipeline_shutdown(fimc);
-               fimc_ctrls_delete(fimc->vid_cap.ctx);
-               vb2_queue_release(&fimc->vid_cap.vbq);
+               clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
        }
 
        pm_runtime_put(&fimc->pdev->dev);
 
+       if (fimc->vid_cap.refcnt == 0) {
+               vb2_queue_release(&fimc->vid_cap.vbq);
+               fimc_ctrls_delete(fimc->vid_cap.ctx);
+       }
        return v4l2_fh_release(file);
 }
 
index 33c7069857638ed887e3480935d64509f328e13d..a51bf309f4dccd104c5b00f33ed46c124afbdf56 100644 (file)
@@ -334,6 +334,11 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final)
        struct timeval *tv;
        struct timespec ts;
 
+       if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
+               wake_up(&fimc->irq_queue);
+               return;
+       }
+
        if (!list_empty(&cap->active_buf_q) &&
            test_bit(ST_CAPT_RUN, &fimc->state) && final) {
                ktime_get_real_ts(&ts);
@@ -348,11 +353,6 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final)
                vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
        }
 
-       if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
-               wake_up(&fimc->irq_queue);
-               return;
-       }
-
        if (!list_empty(&cap->pending_buf_q)) {
 
                v_buf = fimc_pending_queue_pop(cap);
index 82ac59776df7cc2932c1c9e0634ccbeb1ba72ad4..a6936dad5b1025b196ef6c1acd5e40131a44d7c3 100644 (file)
@@ -63,6 +63,7 @@ enum fimc_dev_flags {
        ST_CAPT_RUN,
        ST_CAPT_STREAM,
        ST_CAPT_ISP_STREAM,
+       ST_CAPT_SUSPENDED,
        ST_CAPT_SHUT,
        ST_CAPT_BUSY,
        ST_CAPT_APPLY_CFG,