mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-13 16:50:05 +00:00
[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: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
4c316b55fe
commit
bb0a896e3d
@ -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)
|
|||||||
} 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user