Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f6ac497 authored by Robert Jarzmik's avatar Robert Jarzmik Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (8611): Add suspend/resume to pxa_camera driver



PXA suspend switches off DMA core, which loses all context
of previously assigned descriptors. As pxa_camera driver
relies on DMA transfers, setup the lost descriptors on
resume and retrigger frame acquisition if needed.

Signed-off-by: default avatarRobert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 2e521061
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -128,6 +128,8 @@ struct pxa_camera_dev {

	struct pxa_buffer	*active;
	struct pxa_dma_desc	*sg_tail[3];

	u32			save_cicr[5];
};

static const char *pxa_cam_driver_description = "PXA_Camera";
@@ -997,10 +999,64 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
	return 0;
}

static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
{
	struct soc_camera_host *ici =
		to_soc_camera_host(icd->dev.parent);
	struct pxa_camera_dev *pcdev = ici->priv;
	int i = 0, ret = 0;

	pcdev->save_cicr[i++] = CICR0;
	pcdev->save_cicr[i++] = CICR1;
	pcdev->save_cicr[i++] = CICR2;
	pcdev->save_cicr[i++] = CICR3;
	pcdev->save_cicr[i++] = CICR4;

	if ((pcdev->icd) && (pcdev->icd->ops->suspend))
		ret = pcdev->icd->ops->suspend(pcdev->icd, state);

	return ret;
}

static int pxa_camera_resume(struct soc_camera_device *icd)
{
	struct soc_camera_host *ici =
		to_soc_camera_host(icd->dev.parent);
	struct pxa_camera_dev *pcdev = ici->priv;
	int i = 0, ret = 0;

	DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD;
	DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD;
	DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD;

	CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB;
	CICR1 = pcdev->save_cicr[i++];
	CICR2 = pcdev->save_cicr[i++];
	CICR3 = pcdev->save_cicr[i++];
	CICR4 = pcdev->save_cicr[i++];

	if ((pcdev->icd) && (pcdev->icd->ops->resume))
		ret = pcdev->icd->ops->resume(pcdev->icd);

	/* Restart frame capture if active buffer exists */
	if (!ret && pcdev->active) {
		/* Reset the FIFOs */
		CIFR |= CIFR_RESET_F;
		/* Enable End-Of-Frame Interrupt */
		CICR0 &= ~CICR0_EOFM;
		/* Restart the Capture Interface */
		CICR0 |= CICR0_ENB;
	}

	return ret;
}

static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
	.owner		= THIS_MODULE,
	.add		= pxa_camera_add_device,
	.remove		= pxa_camera_remove_device,
	.suspend	= pxa_camera_suspend,
	.resume		= pxa_camera_resume,
	.set_fmt_cap	= pxa_camera_set_fmt_cap,
	.try_fmt_cap	= pxa_camera_try_fmt_cap,
	.init_videobuf	= pxa_camera_init_videobuf,