diff options
author | Jonathan Corbet <corbet@lwn.net> | 2011-12-30 12:13:41 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-01-06 08:39:38 -0500 |
commit | bb0a896e3d50833a43f94264ec8e66900b796b8b (patch) | |
tree | 133c208ff4f578c31506d961c0764c8a93ec3170 /drivers/media/video | |
parent | 4c316b55fe284fa6364f6b817808ef3d1f6b18a8 (diff) |
[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>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/marvell-ccic/mcam-core.c | 36 | ||||
-rw-r--r-- | drivers/media/video/marvell-ccic/mmp-driver.c | 35 |
2 files changed, 64 insertions, 7 deletions
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 80ec64d2d6d8..c1f12f96aca6 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c | |||
@@ -522,6 +522,15 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam) | |||
522 | */ | 522 | */ |
523 | static void mcam_ctlr_dma_sg(struct mcam_camera *cam) | 523 | static void mcam_ctlr_dma_sg(struct mcam_camera *cam) |
524 | { | 524 | { |
525 | /* | ||
526 | * The list-empty condition can hit us at resume time | ||
527 | * if the buffer list was empty when the system was suspended. | ||
528 | */ | ||
529 | if (list_empty(&cam->buffers)) { | ||
530 | set_bit(CF_SG_RESTART, &cam->flags); | ||
531 | return; | ||
532 | } | ||
533 | |||
525 | mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); | 534 | mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); |
526 | mcam_sg_next_buffer(cam); | 535 | mcam_sg_next_buffer(cam); |
527 | mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); | 536 | 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 | } else { | 575 | } else { |
567 | set_bit(CF_SG_RESTART, &cam->flags); | 576 | set_bit(CF_SG_RESTART, &cam->flags); |
568 | singles++; | 577 | singles++; |
578 | cam->vb_bufs[0] = NULL; | ||
569 | } | 579 | } |
570 | /* | 580 | /* |
571 | * Now we can give the completed frame back to user space. | 581 | * 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 | unsigned long flags; | 671 | unsigned long flags; |
662 | 672 | ||
663 | spin_lock_irqsave(&cam->dev_lock, flags); | 673 | spin_lock_irqsave(&cam->dev_lock, flags); |
674 | clear_bit(CF_SG_RESTART, &cam->flags); | ||
664 | cam->dma_setup(cam); | 675 | cam->dma_setup(cam); |
665 | mcam_ctlr_image(cam); | 676 | mcam_ctlr_image(cam); |
666 | mcam_set_config_needed(cam, 0); | 677 | mcam_set_config_needed(cam, 0); |
667 | clear_bit(CF_SG_RESTART, &cam->flags); | ||
668 | spin_unlock_irqrestore(&cam->dev_lock, flags); | 678 | spin_unlock_irqrestore(&cam->dev_lock, flags); |
669 | return 0; | 679 | return 0; |
670 | } | 680 | } |
@@ -873,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam) | |||
873 | mcam_reset_buffers(cam); | 883 | mcam_reset_buffers(cam); |
874 | mcam_ctlr_irq_enable(cam); | 884 | mcam_ctlr_irq_enable(cam); |
875 | cam->state = S_STREAMING; | 885 | cam->state = S_STREAMING; |
876 | mcam_ctlr_start(cam); | 886 | if (!test_bit(CF_SG_RESTART, &cam->flags)) |
887 | mcam_ctlr_start(cam); | ||
877 | spin_unlock_irqrestore(&cam->dev_lock, flags); | 888 | spin_unlock_irqrestore(&cam->dev_lock, flags); |
878 | return 0; | 889 | return 0; |
879 | } | 890 | } |
@@ -1818,11 +1829,15 @@ void mccic_shutdown(struct mcam_camera *cam) | |||
1818 | 1829 | ||
1819 | void mccic_suspend(struct mcam_camera *cam) | 1830 | void mccic_suspend(struct mcam_camera *cam) |
1820 | { | 1831 | { |
1821 | enum mcam_state cstate = cam->state; | 1832 | mutex_lock(&cam->s_mutex); |
1833 | if (cam->users > 0) { | ||
1834 | enum mcam_state cstate = cam->state; | ||
1822 | 1835 | ||
1823 | mcam_ctlr_stop_dma(cam); | 1836 | mcam_ctlr_stop_dma(cam); |
1824 | mcam_ctlr_power_down(cam); | 1837 | mcam_ctlr_power_down(cam); |
1825 | cam->state = cstate; | 1838 | cam->state = cstate; |
1839 | } | ||
1840 | mutex_unlock(&cam->s_mutex); | ||
1826 | } | 1841 | } |
1827 | 1842 | ||
1828 | int mccic_resume(struct mcam_camera *cam) | 1843 | int mccic_resume(struct mcam_camera *cam) |
@@ -1839,8 +1854,15 @@ int mccic_resume(struct mcam_camera *cam) | |||
1839 | mutex_unlock(&cam->s_mutex); | 1854 | mutex_unlock(&cam->s_mutex); |
1840 | 1855 | ||
1841 | set_bit(CF_CONFIG_NEEDED, &cam->flags); | 1856 | set_bit(CF_CONFIG_NEEDED, &cam->flags); |
1842 | if (cam->state == S_STREAMING) | 1857 | if (cam->state == S_STREAMING) { |
1858 | /* | ||
1859 | * If there was a buffer in the DMA engine at suspend | ||
1860 | * time, put it back on the queue or we'll forget about it. | ||
1861 | */ | ||
1862 | if (cam->buffer_mode == B_DMA_sg && cam->vb_bufs[0]) | ||
1863 | list_add(&cam->vb_bufs[0]->queue, &cam->buffers); | ||
1843 | ret = mcam_read_setup(cam); | 1864 | ret = mcam_read_setup(cam); |
1865 | } | ||
1844 | return ret; | 1866 | return ret; |
1845 | } | 1867 | } |
1846 | #endif /* CONFIG_PM */ | 1868 | #endif /* CONFIG_PM */ |
diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c index fb0b124b35f3..0d64e2d7474a 100644 --- a/drivers/media/video/marvell-ccic/mmp-driver.c +++ b/drivers/media/video/marvell-ccic/mmp-driver.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/io.h> | 26 | #include <linux/io.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
29 | #include <linux/pm.h> | ||
29 | 30 | ||
30 | #include "mcam-core.h" | 31 | #include "mcam-core.h" |
31 | 32 | ||
@@ -310,10 +311,44 @@ static int mmpcam_platform_remove(struct platform_device *pdev) | |||
310 | return mmpcam_remove(cam); | 311 | return mmpcam_remove(cam); |
311 | } | 312 | } |
312 | 313 | ||
314 | /* | ||
315 | * Suspend/resume support. | ||
316 | */ | ||
317 | #ifdef CONFIG_PM | ||
318 | |||
319 | static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state) | ||
320 | { | ||
321 | struct mmp_camera *cam = mmpcam_find_device(pdev); | ||
322 | |||
323 | if (state.event != PM_EVENT_SUSPEND) | ||
324 | return 0; | ||
325 | mccic_suspend(&cam->mcam); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int mmpcam_resume(struct platform_device *pdev) | ||
330 | { | ||
331 | struct mmp_camera *cam = mmpcam_find_device(pdev); | ||
332 | |||
333 | /* | ||
334 | * Power up unconditionally just in case the core tries to | ||
335 | * touch a register even if nothing was active before; trust | ||
336 | * me, it's better this way. | ||
337 | */ | ||
338 | mmpcam_power_up(&cam->mcam); | ||
339 | return mccic_resume(&cam->mcam); | ||
340 | } | ||
341 | |||
342 | #endif | ||
343 | |||
313 | 344 | ||
314 | static struct platform_driver mmpcam_driver = { | 345 | static struct platform_driver mmpcam_driver = { |
315 | .probe = mmpcam_probe, | 346 | .probe = mmpcam_probe, |
316 | .remove = mmpcam_platform_remove, | 347 | .remove = mmpcam_platform_remove, |
348 | #ifdef CONFIG_PM | ||
349 | .suspend = mmpcam_suspend, | ||
350 | .resume = mmpcam_resume, | ||
351 | #endif | ||
317 | .driver = { | 352 | .driver = { |
318 | .name = "mmp-camera", | 353 | .name = "mmp-camera", |
319 | .owner = THIS_MODULE | 354 | .owner = THIS_MODULE |