|
@@ -522,6 +522,15 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam)
|
|
|
*/
|
|
|
static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
|
|
|
{
|
|
|
+ /*
|
|
|
+ * The list-empty condition can hit us at resume time
|
|
|
+ * if the buffer list was empty when the system was suspended.
|
|
|
+ */
|
|
|
+ if (list_empty(&cam->buffers)) {
|
|
|
+ set_bit(CF_SG_RESTART, &cam->flags);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
|
|
|
mcam_sg_next_buffer(cam);
|
|
|
mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
|
|
@@ -566,6 +575,7 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
|
|
|
} else {
|
|
|
set_bit(CF_SG_RESTART, &cam->flags);
|
|
|
singles++;
|
|
|
+ cam->vb_bufs[0] = NULL;
|
|
|
}
|
|
|
/*
|
|
|
* Now we can give the completed frame back to user space.
|
|
@@ -661,10 +671,10 @@ static int mcam_ctlr_configure(struct mcam_camera *cam)
|
|
|
unsigned long flags;
|
|
|
|
|
|
spin_lock_irqsave(&cam->dev_lock, flags);
|
|
|
+ clear_bit(CF_SG_RESTART, &cam->flags);
|
|
|
cam->dma_setup(cam);
|
|
|
mcam_ctlr_image(cam);
|
|
|
mcam_set_config_needed(cam, 0);
|
|
|
- clear_bit(CF_SG_RESTART, &cam->flags);
|
|
|
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
|
|
return 0;
|
|
|
}
|
|
@@ -873,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam)
|
|
|
mcam_reset_buffers(cam);
|
|
|
mcam_ctlr_irq_enable(cam);
|
|
|
cam->state = S_STREAMING;
|
|
|
- mcam_ctlr_start(cam);
|
|
|
+ if (!test_bit(CF_SG_RESTART, &cam->flags))
|
|
|
+ mcam_ctlr_start(cam);
|
|
|
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
|
|
return 0;
|
|
|
}
|
|
@@ -1818,11 +1829,15 @@ void mccic_shutdown(struct mcam_camera *cam)
|
|
|
|
|
|
void mccic_suspend(struct mcam_camera *cam)
|
|
|
{
|
|
|
- enum mcam_state cstate = cam->state;
|
|
|
+ mutex_lock(&cam->s_mutex);
|
|
|
+ if (cam->users > 0) {
|
|
|
+ enum mcam_state cstate = cam->state;
|
|
|
|
|
|
- mcam_ctlr_stop_dma(cam);
|
|
|
- mcam_ctlr_power_down(cam);
|
|
|
- cam->state = cstate;
|
|
|
+ mcam_ctlr_stop_dma(cam);
|
|
|
+ mcam_ctlr_power_down(cam);
|
|
|
+ cam->state = cstate;
|
|
|
+ }
|
|
|
+ mutex_unlock(&cam->s_mutex);
|
|
|
}
|
|
|
|
|
|
int mccic_resume(struct mcam_camera *cam)
|
|
@@ -1839,8 +1854,15 @@ int mccic_resume(struct mcam_camera *cam)
|
|
|
mutex_unlock(&cam->s_mutex);
|
|
|
|
|
|
set_bit(CF_CONFIG_NEEDED, &cam->flags);
|
|
|
- if (cam->state == S_STREAMING)
|
|
|
+ if (cam->state == S_STREAMING) {
|
|
|
+ /*
|
|
|
+ * If there was a buffer in the DMA engine at suspend
|
|
|
+ * time, put it back on the queue or we'll forget about it.
|
|
|
+ */
|
|
|
+ if (cam->buffer_mode == B_DMA_sg && cam->vb_bufs[0])
|
|
|
+ list_add(&cam->vb_bufs[0]->queue, &cam->buffers);
|
|
|
ret = mcam_read_setup(cam);
|
|
|
+ }
|
|
|
return ret;
|
|
|
}
|
|
|
#endif /* CONFIG_PM */
|