Commit bb0a896e authored by Jonathan Corbet's avatar Jonathan Corbet Committed by Mauro Carvalho Chehab

[media] marvell-cam: Make suspend/resume work on MMP2

Somehow I didn't ever quite get around to implementing suspend/resume on
the MMP2 platform; this patch fixes that little oversight.  A bit of core
work was necessary to do the right thing in the s/g DMA case.
Signed-off-by: default avatarJonathan Corbet <corbet@lwn.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 4c316b55
...@@ -522,6 +522,15 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam) ...@@ -522,6 +522,15 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam)
*/ */
static void mcam_ctlr_dma_sg(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_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
mcam_sg_next_buffer(cam); mcam_sg_next_buffer(cam);
mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); 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) ...@@ -566,6 +575,7 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
} else { } else {
set_bit(CF_SG_RESTART, &cam->flags); set_bit(CF_SG_RESTART, &cam->flags);
singles++; singles++;
cam->vb_bufs[0] = NULL;
} }
/* /*
* Now we can give the completed frame back to user space. * Now we can give the completed frame back to user space.
...@@ -661,10 +671,10 @@ static int mcam_ctlr_configure(struct mcam_camera *cam) ...@@ -661,10 +671,10 @@ static int mcam_ctlr_configure(struct mcam_camera *cam)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&cam->dev_lock, flags); spin_lock_irqsave(&cam->dev_lock, flags);
clear_bit(CF_SG_RESTART, &cam->flags);
cam->dma_setup(cam); cam->dma_setup(cam);
mcam_ctlr_image(cam); mcam_ctlr_image(cam);
mcam_set_config_needed(cam, 0); mcam_set_config_needed(cam, 0);
clear_bit(CF_SG_RESTART, &cam->flags);
spin_unlock_irqrestore(&cam->dev_lock, flags); spin_unlock_irqrestore(&cam->dev_lock, flags);
return 0; return 0;
} }
...@@ -873,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam) ...@@ -873,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam)
mcam_reset_buffers(cam); mcam_reset_buffers(cam);
mcam_ctlr_irq_enable(cam); mcam_ctlr_irq_enable(cam);
cam->state = S_STREAMING; 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); spin_unlock_irqrestore(&cam->dev_lock, flags);
return 0; return 0;
} }
...@@ -1818,11 +1829,15 @@ void mccic_shutdown(struct mcam_camera *cam) ...@@ -1818,11 +1829,15 @@ void mccic_shutdown(struct mcam_camera *cam)
void mccic_suspend(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_stop_dma(cam);
mcam_ctlr_power_down(cam); mcam_ctlr_power_down(cam);
cam->state = cstate; cam->state = cstate;
}
mutex_unlock(&cam->s_mutex);
} }
int mccic_resume(struct mcam_camera *cam) int mccic_resume(struct mcam_camera *cam)
...@@ -1839,8 +1854,15 @@ int mccic_resume(struct mcam_camera *cam) ...@@ -1839,8 +1854,15 @@ int mccic_resume(struct mcam_camera *cam)
mutex_unlock(&cam->s_mutex); mutex_unlock(&cam->s_mutex);
set_bit(CF_CONFIG_NEEDED, &cam->flags); 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); ret = mcam_read_setup(cam);
}
return ret; return ret;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/pm.h>
#include "mcam-core.h" #include "mcam-core.h"
...@@ -310,10 +311,44 @@ static int mmpcam_platform_remove(struct platform_device *pdev) ...@@ -310,10 +311,44 @@ static int mmpcam_platform_remove(struct platform_device *pdev)
return mmpcam_remove(cam); return mmpcam_remove(cam);
} }
/*
* Suspend/resume support.
*/
#ifdef CONFIG_PM
static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state)
{
struct mmp_camera *cam = mmpcam_find_device(pdev);
if (state.event != PM_EVENT_SUSPEND)
return 0;
mccic_suspend(&cam->mcam);
return 0;
}
static int mmpcam_resume(struct platform_device *pdev)
{
struct mmp_camera *cam = mmpcam_find_device(pdev);
/*
* Power up unconditionally just in case the core tries to
* touch a register even if nothing was active before; trust
* me, it's better this way.
*/
mmpcam_power_up(&cam->mcam);
return mccic_resume(&cam->mcam);
}
#endif
static struct platform_driver mmpcam_driver = { static struct platform_driver mmpcam_driver = {
.probe = mmpcam_probe, .probe = mmpcam_probe,
.remove = mmpcam_platform_remove, .remove = mmpcam_platform_remove,
#ifdef CONFIG_PM
.suspend = mmpcam_suspend,
.resume = mmpcam_resume,
#endif
.driver = { .driver = {
.name = "mmp-camera", .name = "mmp-camera",
.owner = THIS_MODULE .owner = THIS_MODULE
......
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