Web lists-archives.org

Re: [PATCH 2/6] V4L2 soc_camera driver for PXA27x processors




From: Guennadi Liakhovetski <g.liakhovetski@xxxxxxxxxxxxxx>

This patch adds a driver for the Quick Capture Interface on the PXA270.
It is based on the original driver from Intel, but has been re-worked
multiple times since then, now for the first time it supports the
V4L2 API.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@xxxxxxxxxxxxxx>

---

Thanks for the review, Russell. An updated version is below. Hopefully, 
I've addressed all your comments.

On Mon, 11 Feb 2008, Russell King - ARM Linux wrote:

> On Tue, Feb 05, 2008 at 06:46:25PM +0100, Guennadi Liakhovetski wrote:
> > +	DRCMR68 = pcdev->dma_chan_y  | DRCMR_MAPVLD;
> 
> Is this the same on all PXA SoCs?  Might be a question for Eric...

No, it is not. At the moment the Kconfig entry depends on PXA27x, so, is 
safe. We did hope PXA3x0 would be similar enough, indeed it does have 
similarities, but it has 4 dedicated DMA-channels for the camera 
interface...

> > +/*
> > + * Suspend the Camera Module.
> > + */
> > +static int pxa_camera_suspend(struct platform_device *pdev, pm_message_t level)
> > +{
> > +	struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
> > +
> > +	dev_info(&pdev->dev, "camera suspend\n");
> > +	disable_irq(pcdev->irq);
> 
> IRQs are disabled over suspend anyway...

I've removed suspend/resume so far. I never tested them, and they don't 
seem to be doing anything useful, like stopping the clock, dma, etc.

Thanks
Guennadi

 arch/arm/mach-pxa/devices.c         |   32 ++
 drivers/media/video/Kconfig         |    7 +
 drivers/media/video/Makefile        |    1 +
 drivers/media/video/pxa_camera.c    |  937 +++++++++++++++++++++++++++++++++++
 include/asm-arm/arch-pxa/camera.h   |   48 ++
 include/asm-arm/arch-pxa/pxa-regs.h |   94 ++++
 6 files changed, 1119 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/pxa_camera.c
 create mode 100644 include/asm-arm/arch-pxa/camera.h

diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index bfccb80..3838aab 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -11,6 +11,7 @@
 #include <asm/arch/irda.h>
 #include <asm/arch/i2c.h>
 #include <asm/arch/ohci.h>
+#include <asm/arch/camera.h>
 
 #include "devices.h"
 
@@ -540,6 +541,37 @@ struct platform_device pxa27x_device_ssp3 = {
 	.resource	= pxa27x_resource_ssp3,
 	.num_resources	= ARRAY_SIZE(pxa27x_resource_ssp3),
 };
+
+static struct resource pxa27x_resource_camera[] = {
+	[0] = {
+		.start	= 0x50000000,
+		.end	= 0x50000fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_CAMERA,
+		.end	= IRQ_CAMERA,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 pxa27x_dma_mask_camera = DMA_BIT_MASK(32);
+
+static struct platform_device pxa27x_device_camera = {
+	.name		= "pxa27x-camera",
+	.id		= 0, /* This is used to put cameras on this interface */
+	.dev		= {
+		.dma_mask      		= &pxa27x_dma_mask_camera,
+		.coherent_dma_mask	= 0xffffffff,
+	},
+	.num_resources	= ARRAY_SIZE(pxa27x_resource_camera),
+	.resource	= pxa27x_resource_camera,
+};
+
+void __init pxa_set_camera_info(struct pxacamera_platform_data *info)
+{
+	pxa_register_device(&pxa27x_device_camera, info);
+}
 #endif /* CONFIG_PXA27x || CONFIG_PXA3xx */
 
 #ifdef CONFIG_PXA3xx
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ba1e3ac..36a333a 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -845,4 +845,11 @@ config SOC_CAMERA
 	  over a bus like PCI or USB. For example some i2c camera connected
 	  directly to the data bus of an SoC.
 
+config VIDEO_PXA27x
+	tristate "PXA27x Quick Capture Interface driver"
+	depends on VIDEO_DEV && PXA27x
+	select SOC_CAMERA
+	---help---
+	  This is a v4l2 driver for the PXA27x Quick Capture Interface
+
 endif # VIDEO_CAPTURE_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index bfc1457..fa04fa0 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -135,6 +135,7 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
+obj-$(CONFIG_VIDEO_PXA27x)	+= pxa_camera.o
 obj-$(CONFIG_SOC_CAMERA)	+= soc_camera.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
new file mode 100644
index 0000000..2347040
--- /dev/null
+++ b/drivers/media/video/pxa_camera.c
@@ -0,0 +1,901 @@
+/*
+ * V4L2 Driver for PXA camera host
+ *
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@xxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/soc_camera.h>
+
+#include <linux/videodev2.h>
+
+#include <asm/dma.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/camera.h>
+
+#define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+#define PXA_CAM_DRV_NAME "pxa27x-camera"
+
+#define CICR0_IRQ_MASK (CICR0_TOM | CICR0_RDAVM | CICR0_FEM | CICR0_EOLM | \
+			CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
+			CICR0_EOFM | CICR0_FOM)
+
+static DEFINE_MUTEX(camera_lock);
+
+/*
+ * Structures
+ */
+
+/* buffer for one video frame */
+struct pxa_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	const struct soc_camera_data_format        *fmt;
+
+	/* our descriptor list needed for the PXA DMA engine */
+	dma_addr_t		sg_dma;
+	struct pxa_dma_desc	*sg_cpu;
+	size_t			sg_size;
+	int			inwork;
+};
+
+struct pxa_framebuffer_queue {
+	dma_addr_t		sg_last_dma;
+	struct pxa_dma_desc	*sg_last_cpu;
+};
+
+struct pxa_camera_dev {
+	struct device		*dev;
+	/* PXA27x is only supposed to handle one camera on its Quick Capture
+	 * interface. If anyone ever builds hardware to enable more than
+	 * one camera, they will have to modify this driver too */
+	struct soc_camera_device *icd;
+	struct clk		*clk;
+
+	unsigned int		irq;
+	void __iomem		*base;
+	unsigned int		dma_chan_y;
+
+	enum v4l2_buf_type	type;
+
+	struct pxacamera_platform_data *pdata;
+	struct resource		*res;
+	unsigned long		platform_flags;
+	unsigned long		platform_mclk_10khz;
+
+	struct list_head	capture;
+
+	spinlock_t		lock;
+
+	int			dma_running;
+
+	struct pxa_buffer	*active;
+};
+
+static const char *pxa_cam_driver_description = "PXA_Camera";
+
+static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
+
+/*
+ *  Videobuf operations
+ */
+static int
+pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+		   unsigned int *size)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+
+	dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+
+	*size = icd->width * icd->height * ((icd->current_fmt->depth + 7) >> 3);
+
+	if (0 == *count)
+		*count = 32;
+	while (*size * *count > vid_limit * 1024 * 1024)
+		(*count)--;
+
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+	BUG_ON(in_interrupt());
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+		&buf->vb, buf->vb.baddr, buf->vb.bsize);
+
+	/* This waits until this buffer is out of danger, i.e., until it is no
+	 * longer in STATE_QUEUED or STATE_ACTIVE */
+	videobuf_waiton(&buf->vb, 0, 0);
+	videobuf_dma_unmap(vq, dma);
+	videobuf_dma_free(dma);
+
+	if (buf->sg_cpu)
+		dma_free_coherent(pcdev->dev, buf->sg_size, buf->sg_cpu,
+				  buf->sg_dma);
+	buf->sg_cpu = NULL;
+
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+pxa_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+						enum v4l2_field field)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+	int i, ret;
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+		vb, vb->baddr, vb->bsize);
+
+	/* Added list head initialization on alloc */
+	WARN_ON(!list_empty(&vb->queue));
+
+#ifdef DEBUG
+	/* This can be useful if you want to see if we actually fill
+	 * the buffer with something */
+	memset((void *)vb->baddr, 0xaa, vb->bsize);
+#endif
+
+	BUG_ON(NULL == icd->current_fmt);
+
+	/* I think, in buf_prepare you only have to protect global data,
+	 * the actual buffer is yours */
+	buf->inwork = 1;
+
+	if (buf->fmt	!= icd->current_fmt ||
+	    vb->width	!= icd->width ||
+	    vb->height	!= icd->height ||
+	    vb->field	!= field) {
+		buf->fmt	= icd->current_fmt;
+		vb->width	= icd->width;
+		vb->height	= icd->height;
+		vb->field	= field;
+		vb->state	= VIDEOBUF_NEEDS_INIT;
+	}
+
+	vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3);
+	if (0 != vb->baddr && vb->bsize < vb->size) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		unsigned int size = vb->size;
+		struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+		ret = videobuf_iolock(vq, vb, NULL);
+		if (ret)
+			goto fail;
+
+		if (buf->sg_cpu)
+			dma_free_coherent(pcdev->dev, buf->sg_size, buf->sg_cpu,
+					  buf->sg_dma);
+
+		buf->sg_size = (dma->sglen + 1) * sizeof(struct pxa_dma_desc);
+		buf->sg_cpu = dma_alloc_coherent(pcdev->dev, buf->sg_size,
+						 &buf->sg_dma, GFP_KERNEL);
+		if (!buf->sg_cpu) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		dev_dbg(&icd->dev, "nents=%d size: %d sg=0x%p\n",
+			dma->sglen, size, dma->sglist);
+		for (i = 0; i < dma->sglen; i++) {
+			struct scatterlist *sg = dma->sglist;
+			unsigned int dma_len = sg_dma_len(&sg[i]), xfer_len;
+
+			/* CIBR0 */
+			buf->sg_cpu[i].dsadr = pcdev->res->start + 0x28;
+			buf->sg_cpu[i].dtadr = sg_dma_address(&sg[i]);
+			/* PXA270 Developer's Manual 27.4.4.1:
+			 * round up to 8 bytes */
+			xfer_len = (min(dma_len, size) + 7) & ~7;
+			if (xfer_len & 7)
+				dev_err(&icd->dev, "Unaligned buffer: "
+					"dma_len %u, size %u\n", dma_len, size);
+			buf->sg_cpu[i].dcmd = DCMD_FLOWSRC | DCMD_BURST8 |
+				DCMD_INCTRGADDR | xfer_len;
+			size -= dma_len;
+			buf->sg_cpu[i].ddadr = buf->sg_dma + (i + 1) *
+					sizeof(struct pxa_dma_desc);
+		}
+		buf->sg_cpu[dma->sglen - 1].ddadr = DDADR_STOP;
+		buf->sg_cpu[dma->sglen - 1].dcmd |= DCMD_ENDIRQEN;
+
+		vb->state = VIDEOBUF_PREPARED;
+	}
+
+	buf->inwork = 0;
+
+	return 0;
+
+fail:
+	free_buffer(vq, buf);
+out:
+	buf->inwork = 0;
+	return ret;
+}
+
+static void
+pxa_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct soc_camera_device *icd = vq->priv_data;
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+	struct pxa_buffer *active;
+	struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+	int nents = dma->sglen;
+	unsigned long flags;
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+		vb, vb->baddr, vb->bsize);
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	list_add_tail(&vb->queue, &pcdev->capture);
+
+	vb->state = VIDEOBUF_ACTIVE;
+	active = pcdev->active;
+
+	if (!active) {
+		CIFR |= CIFR_RESET_F;
+		DDADR(pcdev->dma_chan_y) = buf->sg_dma;
+		DCSR(pcdev->dma_chan_y) = DCSR_RUN;
+		pcdev->active = buf;
+		CICR0 |= CICR0_ENB;
+	} else {
+		struct videobuf_dmabuf *active_dma =
+			videobuf_to_dma(&active->vb);
+		/* Stop DMA engine */
+		DCSR(pcdev->dma_chan_y) = 0;
+
+		/* Add the descriptors we just initialized to the currently
+		 * running chain
+		 */
+		active->sg_cpu[active_dma->sglen - 1].ddadr = buf->sg_dma;
+
+		/* Setup a dummy descriptor with the DMA engines current
+		 * state
+		 */
+		/* CIBR0 */
+		buf->sg_cpu[nents].dsadr = pcdev->res->start + 0x28;
+		buf->sg_cpu[nents].dtadr = DTADR(pcdev->dma_chan_y);
+		buf->sg_cpu[nents].dcmd = DCMD(pcdev->dma_chan_y);
+
+		if (DDADR(pcdev->dma_chan_y) == DDADR_STOP) {
+			/* The DMA engine is on the last descriptor, set the
+			 * next descriptors address to the descriptors
+			 * we just initialized
+			 */
+			buf->sg_cpu[nents].ddadr = buf->sg_dma;
+		} else {
+			buf->sg_cpu[nents].ddadr = DDADR(pcdev->dma_chan_y);
+		}
+
+		/* The next descriptor is the dummy descriptor */
+		DDADR(pcdev->dma_chan_y) = buf->sg_dma + nents *
+			sizeof(struct pxa_dma_desc);
+
+#ifdef DEBUG
+		if (CISR & CISR_IFO_0) {
+			dev_warn(pcdev->dev, "FIFO overrun\n");
+			DDADR(pcdev->dma_chan_y) = pcdev->active->sg_dma;
+
+			CICR0 &= ~CICR0_ENB;
+			CIFR |= CIFR_RESET_F;
+			DCSR(pcdev->dma_chan_y) = DCSR_RUN;
+			CICR0 |= CICR0_ENB;
+		} else
+#endif
+			DCSR(pcdev->dma_chan_y) = DCSR_RUN;
+	}
+
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+
+}
+
+static void pxa_videobuf_release(struct videobuf_queue *vq,
+				 struct videobuf_buffer *vb)
+{
+	struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+#ifdef DEBUG
+	struct soc_camera_device *icd = vq->priv_data;
+
+	dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+		vb, vb->baddr, vb->bsize);
+
+	switch (vb->state) {
+	case VIDEOBUF_ACTIVE:
+		dev_dbg(&icd->dev, "%s (active)\n", __FUNCTION__);
+		break;
+	case VIDEOBUF_QUEUED:
+		dev_dbg(&icd->dev, "%s (queued)\n", __FUNCTION__);
+		break;
+	case VIDEOBUF_PREPARED:
+		dev_dbg(&icd->dev, "%s (prepared)\n", __FUNCTION__);
+		break;
+	default:
+		dev_dbg(&icd->dev, "%s (unknown)\n", __FUNCTION__);
+		break;
+	}
+#endif
+
+	free_buffer(vq, buf);
+}
+
+static void pxa_camera_dma_irq_y(int channel, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	struct pxa_buffer *buf;
+	unsigned long flags;
+	unsigned int status;
+	struct videobuf_buffer *vb;
+
+	spin_lock_irqsave(&pcdev->lock, flags);
+
+	status = DCSR(pcdev->dma_chan_y);
+	DCSR(pcdev->dma_chan_y) = status;
+
+	if (status & DCSR_BUSERR) {
+		dev_err(pcdev->dev, "DMA Bus Error IRQ!\n");
+		goto out;
+	}
+
+	if (!(status & DCSR_ENDINTR)) {
+		dev_err(pcdev->dev, "Unknown DMA IRQ source, "
+			"status: 0x%08x\n", status);
+		goto out;
+	}
+
+	if (!pcdev->active) {
+		dev_err(pcdev->dev, "DMA End IRQ with no active buffer!\n");
+		goto out;
+	}
+
+	vb = &pcdev->active->vb;
+	buf = container_of(vb, struct pxa_buffer, vb);
+	WARN_ON(buf->inwork || list_empty(&vb->queue));
+	dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+		vb, vb->baddr, vb->bsize);
+
+	/* _init is used to debug races, see comment in pxa_is_reqbufs() */
+	list_del_init(&vb->queue);
+	vb->state = VIDEOBUF_DONE;
+	do_gettimeofday(&vb->ts);
+	vb->field_count++;
+	wake_up(&vb->done);
+
+	if (list_empty(&pcdev->capture)) {
+		pcdev->active = NULL;
+		DCSR(pcdev->dma_chan_y) = 0;
+		CICR0 &= ~CICR0_ENB;
+		goto out;
+	}
+
+	pcdev->active = list_entry(pcdev->capture.next, struct pxa_buffer,
+				   vb.queue);
+
+out:
+	spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static struct videobuf_queue_ops pxa_video_ops = {
+	.buf_setup      = pxa_videobuf_setup,
+	.buf_prepare    = pxa_videobuf_prepare,
+	.buf_queue      = pxa_videobuf_queue,
+	.buf_release    = pxa_videobuf_release,
+};
+
+static int mclk_get_divisor(struct pxa_camera_dev *pcdev)
+{
+	unsigned int mclk_10khz = pcdev->platform_mclk_10khz;
+	unsigned long div;
+	unsigned long lcdclk;
+
+	lcdclk = clk_get_rate(pcdev->clk) / 10000;
+
+	/* We verify platform_mclk_10khz != 0, so if anyone breaks it, here
+	 * they get a nice Oops */
+	div = (lcdclk + 2 * mclk_10khz - 1) / (2 * mclk_10khz) - 1;
+
+	dev_dbg(pcdev->dev, "LCD clock %lukHz, target freq %dkHz, "
+		"divisor %lu\n", lcdclk * 10, mclk_10khz * 10, div);
+
+	return div;
+}
+
+static void pxa_is_activate(struct pxa_camera_dev *pcdev)
+{
+	struct pxacamera_platform_data *pdata = pcdev->pdata;
+	u32 cicr4 = 0;
+
+	dev_dbg(pcdev->dev, "Registered platform device at %p data %p\n",
+		pcdev, pdata);
+
+	if (pdata && pdata->init) {
+		dev_dbg(pcdev->dev, "%s: Init gpios\n", __FUNCTION__);
+		pdata->init(pcdev->dev);
+	}
+
+	if (pdata && pdata->power) {
+		dev_dbg(pcdev->dev, "%s: Power on camera\n", __FUNCTION__);
+		pdata->power(pcdev->dev, 1);
+	}
+
+	if (pdata && pdata->reset) {
+		dev_dbg(pcdev->dev, "%s: Releasing camera reset\n",
+			__FUNCTION__);
+		pdata->reset(pcdev->dev, 1);
+	}
+
+	CICR0 = 0x3FF;   /* disable all interrupts */
+
+	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+		cicr4 |= CICR4_PCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+		cicr4 |= CICR4_MCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_PCP)
+		cicr4 |= CICR4_PCP;
+	if (pcdev->platform_flags & PXA_CAMERA_HSP)
+		cicr4 |= CICR4_HSP;
+	if (pcdev->platform_flags & PXA_CAMERA_VSP)
+		cicr4 |= CICR4_VSP;
+
+	CICR4 = mclk_get_divisor(pcdev) | cicr4;
+
+	clk_enable(pcdev->clk);
+}
+
+static void pxa_is_deactivate(struct pxa_camera_dev *pcdev)
+{
+	struct pxacamera_platform_data *board = pcdev->pdata;
+
+	clk_disable(pcdev->clk);
+
+	if (board && board->reset) {
+		dev_dbg(pcdev->dev, "%s: Asserting camera reset\n",
+			__FUNCTION__);
+		board->reset(pcdev->dev, 0);
+	}
+
+	if (board && board->power) {
+		dev_dbg(pcdev->dev, "%s: Power off camera\n", __FUNCTION__);
+		board->power(pcdev->dev, 0);
+	}
+}
+
+static irqreturn_t pxa_camera_irq(int irq, void *data)
+{
+	struct pxa_camera_dev *pcdev = data;
+	unsigned int status = CISR;
+
+	dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);
+
+	CISR = status;
+
+	return IRQ_HANDLED;
+}
+
+/* The following two functions absolutely depend on the fact, that
+ * there can be only one camera on PXA quick capture interface */
+static int pxa_is_add_device(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 ret;
+
+	mutex_lock(&camera_lock);
+
+	if (pcdev->icd) {
+		ret = -EBUSY;
+		goto ebusy;
+	}
+
+	dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
+		 icd->devnum);
+
+	pxa_is_activate(pcdev);
+	ret = icd->ops->init(icd);
+
+	if (!ret)
+		pcdev->icd = icd;
+
+ebusy:
+	mutex_unlock(&camera_lock);
+
+	return ret;
+}
+
+static void pxa_is_remove_device(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+
+	BUG_ON(icd != pcdev->icd);
+
+	dev_info(&icd->dev, "PXA Camera driver detached from camera %d\n",
+		 icd->devnum);
+
+	/* disable capture, disable interrupts */
+	CICR0 = 0x3ff;
+	/* Stop DMA engine */
+	DCSR(pcdev->dma_chan_y) = 0;
+
+	icd->ops->release(icd);
+
+	pxa_is_deactivate(pcdev);
+
+	pcdev->icd = NULL;
+}
+
+static int pxa_is_set_capture_format(struct soc_camera_device *icd,
+				     __u32 pixfmt, struct v4l2_rect *rect)
+{
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	unsigned int datawidth = 0, dw, bpp;
+	u32 cicr0, cicr4 = 0;
+	int ret;
+
+	/* If requested data width is supported by the platform, use it */
+	switch (icd->cached_datawidth) {
+	case 10:
+		if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)
+			datawidth = IS_DATAWIDTH_10;
+		break;
+	case 9:
+		if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9)
+			datawidth = IS_DATAWIDTH_9;
+		break;
+	case 8:
+		if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)
+			datawidth = IS_DATAWIDTH_8;
+	}
+	if (!datawidth)
+		return -EINVAL;
+
+	ret = icd->ops->set_capture_format(icd, pixfmt, rect,
+			datawidth |
+			(pcdev->platform_flags & PXA_CAMERA_MASTER ?
+			 IS_MASTER : 0) |
+			(pcdev->platform_flags & PXA_CAMERA_HSP ?
+			 0 : IS_HSYNC_ACTIVE_HIGH) |
+			(pcdev->platform_flags & PXA_CAMERA_VSP ?
+			 0 : IS_VSYNC_ACTIVE_HIGH) |
+			(pcdev->platform_flags & PXA_CAMERA_PCP ?
+			 0 : IS_PCLK_SAMPLE_RISING));
+	if (ret < 0)
+		return ret;
+
+	/* Datawidth is now guaranteed to be equal to one of the three values.
+	 * We fix bit-per-pixel equal to data-width... */
+	switch (datawidth) {
+	case IS_DATAWIDTH_10:
+		icd->cached_datawidth = 10;
+		dw = 4;
+		bpp = 0x40;
+		break;
+	case IS_DATAWIDTH_9:
+		icd->cached_datawidth = 9;
+		dw = 3;
+		bpp = 0x20;
+		break;
+	default:
+		/* Actually it can only be 8 now,
+		 * default is just to silence compiler warnings */
+	case IS_DATAWIDTH_8:
+		icd->cached_datawidth = 8;
+		dw = 2;
+		bpp = 0;
+	}
+
+	if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+		cicr4 |= CICR4_PCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+		cicr4 |= CICR4_MCLK_EN;
+	if (pcdev->platform_flags & PXA_CAMERA_PCP)
+		cicr4 |= CICR4_PCP;
+	if (pcdev->platform_flags & PXA_CAMERA_HSP)
+		cicr4 |= CICR4_HSP;
+	if (pcdev->platform_flags & PXA_CAMERA_VSP)
+		cicr4 |= CICR4_VSP;
+
+	cicr0 = CICR0;
+	if (cicr0 & CICR0_ENB)
+		CICR0 = cicr0 & ~CICR0_ENB;
+	CICR1 = CICR1_PPL_VAL(rect->width - 1) | bpp | dw;
+	CICR2 = 0;
+	CICR3 = CICR3_LPF_VAL(rect->height - 1) |
+		CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
+	CICR4 = mclk_get_divisor(pcdev) | cicr4;
+
+	/* CIF interrupts are not used, only DMA */
+	CICR0 = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+			0 : (CICR0_SL_CAP_EN | CICR0_SIM_SP)) |
+		CICR0_DMAEN | CICR0_IRQ_MASK | (cicr0 & CICR0_ENB);
+
+	return 0;
+}
+
+static int pxa_is_try_fmt_cap(struct soc_camera_host *ici,
+			      struct v4l2_format *f)
+{
+	/* limit to pxa hardware capabilities */
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.height > 2048)
+		f->fmt.pix.height = 2048;
+	if (f->fmt.pix.width < 48)
+		f->fmt.pix.width = 48;
+	if (f->fmt.pix.width > 2048)
+		f->fmt.pix.width = 2048;
+	f->fmt.pix.width &= ~0x01;
+
+	return 0;
+}
+
+static int pxa_is_reqbufs(struct soc_camera_file *icf,
+			  struct v4l2_requestbuffers *p)
+{
+	int i;
+
+	/* This is for locking debugging only. I removed spinlocks and now I
+	 * check whether .prepare is ever called on a linked buffer, or whether
+	 * a dma IRQ can occur for an in-work or unlinked buffer. Until now
+	 * it hadn't triggered */
+	for (i = 0; i < p->count; i++) {
+		struct pxa_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+						      struct pxa_buffer, vb);
+		buf->inwork = 0;
+		INIT_LIST_HEAD(&buf->vb.queue);
+	}
+
+	return 0;
+}
+
+static unsigned int pxa_is_poll(struct file *file, poll_table *pt)
+{
+	struct soc_camera_file *icf = file->private_data;
+	struct pxa_buffer *buf;
+
+	buf = list_entry(icf->vb_vidq.stream.next, struct pxa_buffer,
+			 vb.stream);
+
+	poll_wait(file, &buf->vb.done, pt);
+
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		return POLLIN|POLLRDNORM;
+
+	return 0;
+}
+
+static int pxa_is_querycap(struct soc_camera_host *ici,
+			   struct v4l2_capability *cap)
+{
+	/* cap->name is set by the firendly caller:-> */
+	strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
+	cap->version = PXA_CAM_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+	return 0;
+}
+
+/* Should beallocated dynamically too, but we have only one. */
+static struct soc_camera_host pxa_soc_camera_host = {
+	.drv_name		= PXA_CAM_DRV_NAME,
+	.vbq_ops		= &pxa_video_ops,
+	.add			= pxa_is_add_device,
+	.remove			= pxa_is_remove_device,
+	.msize			= sizeof(struct pxa_buffer),
+	.set_capture_format	= pxa_is_set_capture_format,
+	.try_fmt_cap		= pxa_is_try_fmt_cap,
+	.reqbufs		= pxa_is_reqbufs,
+	.poll			= pxa_is_poll,
+	.querycap		= pxa_is_querycap,
+};
+
+static int pxa_camera_probe(struct platform_device *pdev)
+{
+	struct pxa_camera_dev *pcdev;
+	struct resource *res;
+	void __iomem *base;
+	unsigned int irq;
+	int err = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!res || !irq) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+	if (!pcdev) {
+		dev_err(&pdev->dev, "Could not allocate pcdev\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	pcdev->clk = clk_get(&pdev->dev, "CAMCLK");
+	if (IS_ERR(pcdev->clk)) {
+		err = PTR_ERR(pcdev->clk);
+		goto exit_kfree;
+	}
+
+	dev_set_drvdata(&pdev->dev, pcdev);
+	pcdev->res = res;
+
+	pcdev->pdata = pdev->dev.platform_data;
+	pcdev->platform_flags = pcdev->pdata->flags;
+	if (!pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
+			PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10)) {
+		/* Platform hasn't set available data widths. This is bad.
+		 * Warn and use a default. */
+		dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
+			 "data widths, using default 10 bit\n");
+		pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10;
+	}
+	pcdev->platform_mclk_10khz = pcdev->pdata->mclk_10khz;
+	if (!pcdev->platform_mclk_10khz) {
+		dev_warn(&pdev->dev,
+			 "mclk_10khz == 0! Please, fix your platform data. "
+			 "Using default 20MHz\n");
+		pcdev->platform_mclk_10khz = 2000;
+	}
+
+	INIT_LIST_HEAD(&pcdev->capture);
+	spin_lock_init(&pcdev->lock);
+
+	/*
+	 * Request the regions.
+	 */
+	if (!request_mem_region(res->start, res->end - res->start + 1,
+				PXA_CAM_DRV_NAME)) {
+		err = -EBUSY;
+		goto exit_clk;
+	}
+
+	base = ioremap(res->start, res->end - res->start + 1);
+	if (!base) {
+		err = -ENOMEM;
+		goto exit_release;
+	}
+	pcdev->irq = irq;
+	pcdev->base = base;
+	pcdev->dev = &pdev->dev;
+
+	/* request dma */
+	pcdev->dma_chan_y = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
+					    pxa_camera_dma_irq_y, pcdev);
+	if (pcdev->dma_chan_y < 0) {
+		dev_err(pcdev->dev, "Can't request DMA for Y\n");
+		err = -ENOMEM;
+		goto exit_iounmap;
+	}
+	dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chan_y);
+
+	DRCMR68 = pcdev->dma_chan_y  | DRCMR_MAPVLD;
+
+	/* request irq */
+	err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
+			  pcdev);
+	if (err) {
+		dev_err(pcdev->dev, "Camera interrupt register failed \n");
+		goto exit_free_dma;
+	}
+
+	pxa_soc_camera_host.priv	= pcdev;
+	pxa_soc_camera_host.dev.parent	= &pdev->dev;
+	pxa_soc_camera_host.nr		= pdev->id;
+	err = soc_camera_host_register(&pxa_soc_camera_host, THIS_MODULE);
+	if (err)
+		goto exit_free_irq;
+
+	return 0;
+
+exit_free_irq:
+	free_irq(pcdev->irq, pcdev);
+exit_free_dma:
+	pxa_free_dma(pcdev->dma_chan_y);
+exit_iounmap:
+	iounmap(base);
+exit_release:
+	release_mem_region(res->start, res->end - res->start + 1);
+exit_clk:
+	clk_put(pcdev->clk);
+exit_kfree:
+	kfree(pcdev);
+exit:
+	return err;
+}
+
+static int __devexit pxa_camera_remove(struct platform_device *pdev)
+{
+	struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	clk_put(pcdev->clk);
+
+	pxa_free_dma(pcdev->dma_chan_y);
+	free_irq(pcdev->irq, pcdev);
+
+	soc_camera_host_unregister(&pxa_soc_camera_host);
+
+	iounmap(pcdev->base);
+
+	res = pcdev->res;
+	release_mem_region(res->start, res->end - res->start + 1);
+
+	kfree(pcdev);
+
+	dev_info(&pdev->dev, "PXA Camera driver unloaded\n");
+
+	return 0;
+}
+
+static struct platform_driver pxa_camera_driver = {
+	.driver 	= {
+		.name	= PXA_CAM_DRV_NAME,
+	},
+	.probe		= pxa_camera_probe,
+	.remove		= __exit_p(pxa_camera_remove),
+};
+
+
+static int __devinit pxa_camera_init(void)
+{
+	return platform_driver_register(&pxa_camera_driver);
+}
+
+static void __exit pxa_camera_exit(void)
+{
+	return platform_driver_unregister(&pxa_camera_driver);
+}
+
+module_init(pxa_camera_init);
+module_exit(pxa_camera_exit);
+
+MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@xxxxxxxxxxxxxx>");
+MODULE_LICENSE("GPL");
diff --git a/include/asm-arm/arch-pxa/camera.h b/include/asm-arm/arch-pxa/camera.h
new file mode 100644
index 0000000..39516ce
--- /dev/null
+++ b/include/asm-arm/arch-pxa/camera.h
@@ -0,0 +1,48 @@
+/*
+    camera.h - PXA camera driver header file
+
+    Copyright (C) 2003, Intel Corporation
+    Copyright (C) 2008, Guennadi Liakhovetski <kernel@xxxxxxxxxxxxxx>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __ASM_ARCH_CAMERA_H_
+#define __ASM_ARCH_CAMERA_H_
+
+#define PXA_CAMERA_MASTER	1
+#define PXA_CAMERA_DATAWIDTH_4	2
+#define PXA_CAMERA_DATAWIDTH_5	4
+#define PXA_CAMERA_DATAWIDTH_8	8
+#define PXA_CAMERA_DATAWIDTH_9	0x10
+#define PXA_CAMERA_DATAWIDTH_10	0x20
+#define PXA_CAMERA_PCLK_EN	0x40
+#define PXA_CAMERA_MCLK_EN	0x80
+#define PXA_CAMERA_PCP		0x100
+#define PXA_CAMERA_HSP		0x200
+#define PXA_CAMERA_VSP		0x400
+
+struct pxacamera_platform_data {
+	int (*init)(struct device *);
+	int (*power)(struct device *, int);
+	int (*reset)(struct device *, int);
+
+	unsigned long flags;
+	unsigned long mclk_10khz;
+};
+
+extern void pxa_set_camera_info(struct pxacamera_platform_data *);
+
+#endif /* __ASM_ARCH_CAMERA_H_ */
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index ac175b4..8dd9334 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1245,19 +1245,26 @@
 #define GPIO10_RTCCLK		10	/* real time clock (1 Hz) */
 #define GPIO11_3_6MHz		11	/* 3.6 MHz oscillator out */
 #define GPIO12_32KHz		12	/* 32 kHz out */
+#define GPIO12_CIF_DD7		12	/* Capture Interface D7 (PXA27x) */
 #define GPIO13_MBGNT		13	/* memory controller grant */
 #define GPIO14_MBREQ		14	/* alternate bus master request */
 #define GPIO15_nCS_1		15	/* chip select 1 */
 #define GPIO16_PWM0		16	/* PWM0 output */
 #define GPIO17_PWM1		17	/* PWM1 output */
+#define GPIO17_CIF_DD6		17	/* Capture Interface D6 (PXA27x) */
 #define GPIO18_RDY		18	/* Ext. Bus Ready */
 #define GPIO19_DREQ1		19	/* External DMA Request */
 #define GPIO20_DREQ0		20	/* External DMA Request */
 #define GPIO23_SCLK		23	/* SSP clock */
+#define GPIO23_CIF_MCLK		23	/* Capture Interface MCLK (PXA27x) */
 #define GPIO24_SFRM		24	/* SSP Frame */
+#define GPIO24_CIF_FV		24	/* Capture Interface FV (PXA27x) */
 #define GPIO25_STXD		25	/* SSP transmit */
+#define GPIO25_CIF_LV		25	/* Capture Interface LV (PXA27x) */
 #define GPIO26_SRXD		26	/* SSP receive */
+#define GPIO26_CIF_PCLK		26	/* Capture Interface PCLK (PXA27x) */
 #define GPIO27_SEXTCLK		27	/* SSP ext_clk */
+#define GPIO27_CIF_DD0		27	/* Capture Interface D0 (PXA27x) */
 #define GPIO28_BITCLK		28	/* AC97/I2S bit_clk */
 #define GPIO29_SDATA_IN		29	/* AC97 Sdata_in0 / I2S Sdata_in */
 #define GPIO30_SDATA_OUT	30	/* AC97/I2S Sdata_out */
@@ -1278,28 +1285,40 @@
 #define GPIO41_FFRTS		41	/* FFUART request to send */
 #define GPIO42_BTRXD		42	/* BTUART receive data */
 #define GPIO42_HWRXD		42	/* HWUART receive data */
+#define GPIO42_CIF_MCLK		42	/* Capture interface MCLK (PXA27x) */
 #define GPIO43_BTTXD		43	/* BTUART transmit data */
 #define GPIO43_HWTXD		43	/* HWUART transmit data */
+#define GPIO43_CIF_FV		43	/* Capture interface FV (PXA27x) */
 #define GPIO44_BTCTS		44	/* BTUART clear to send */
 #define GPIO44_HWCTS		44	/* HWUART clear to send */
+#define GPIO44_CIF_LV		44	/* Capture interface LV (PXA27x) */
 #define GPIO45_BTRTS		45	/* BTUART request to send */
 #define GPIO45_HWRTS		45	/* HWUART request to send */
 #define GPIO45_AC97_SYSCLK	45	/* AC97 System Clock */
+#define GPIO45_CIF_PCLK		45	/* Capture interface PCLK (PXA27x) */
 #define GPIO46_ICPRXD		46	/* ICP receive data */
 #define GPIO46_STRXD		46	/* STD_UART receive data */
 #define GPIO47_ICPTXD		47	/* ICP transmit data */
 #define GPIO47_STTXD		47	/* STD_UART transmit data */
+#define GPIO47_CIF_DD0		47	/* Capture interface D0 (PXA27x) */
 #define GPIO48_nPOE		48	/* Output Enable for Card Space */
+#define GPIO48_CIF_DD5		48	/* Capture interface D5 (PXA27x) */
 #define GPIO49_nPWE		49	/* Write Enable for Card Space */
 #define GPIO50_nPIOR		50	/* I/O Read for Card Space */
+#define GPIO50_CIF_DD3		50	/* Capture interface D3 (PXA27x) */
 #define GPIO51_nPIOW		51	/* I/O Write for Card Space */
+#define GPIO51_CIF_DD2		51	/* Capture interface D2 (PXA27x) */
 #define GPIO52_nPCE_1		52	/* Card Enable for Card Space */
+#define GPIO52_CIF_DD4		52	/* Capture interface D4 (PXA27x) */
 #define GPIO53_nPCE_2		53	/* Card Enable for Card Space */
 #define GPIO53_MMCCLK		53	/* MMC Clock */
+#define GPIO53_CIF_MCLK		53	/* Capture interface MCLK (PXA27x) */
 #define GPIO54_MMCCLK		54	/* MMC Clock */
 #define GPIO54_pSKTSEL		54	/* Socket Select for Card Space */
 #define GPIO54_nPCE_2		54	/* Card Enable for Card Space (PXA27x) */
+#define GPIO54_CIF_PCLK		54	/* Capture interface PCLK (PXA27x) */
 #define GPIO55_nPREG		55	/* Card Address bit 26 */
+#define GPIO55_CIF_DD1		55	/* Capture interface D1 (PXA27x) */
 #define GPIO56_nPWAIT		56	/* Wait signal for Card Space */
 #define GPIO57_nIOIS16		57	/* Bus Width select for I/O Card Space */
 #define GPIO58_LDD_0		58	/* LCD data pin 0 */
@@ -1334,11 +1353,28 @@
 #define GPIO79_nCS_3		79	/* chip select 3 */
 #define GPIO80_nCS_4		80	/* chip select 4 */
 #define GPIO81_NSCLK		81	/* NSSP clock */
+#define GPIO81_CIF_DD0		81	/* Capture Interface D0 (PXA27x) */
 #define GPIO82_NSFRM		82	/* NSSP Frame */
+#define GPIO82_CIF_DD5		82	/* Capture Interface D5 (PXA27x) */
 #define GPIO83_NSTXD		83	/* NSSP transmit */
+#define GPIO83_CIF_DD4		83	/* Capture Interface D4 (PXA27x) */
 #define GPIO84_NSRXD		84	/* NSSP receive */
+#define GPIO84_CIF_FV		84	/* Capture Interface FV (PXA27x) */
 #define GPIO85_nPCE_1		85	/* Card Enable for Card Space (PXA27x) */
+#define GPIO85_CIF_LV		85	/* Capture Interface LV (PXA27x) */
+#define GPIO90_CIF_DD4		90	/* Capture Interface DD4 (PXA27x) */
+#define GPIO91_CIF_DD5		91	/* Capture Interface DD5 (PXA27x) */
 #define GPIO92_MMCDAT0		92	/* MMC DAT0 (PXA27x) */
+#define GPIO93_CIF_DD6		93	/* Capture interface D6 (PXA27x) */
+#define GPIO94_CIF_DD5		94	/* Capture interface D5 (PXA27x) */
+#define GPIO95_CIF_DD4		95	/* Capture interface D4 (PXA27x) */
+#define GPIO98_CIF_DD0		98	/* Capture interface D0 (PXA27x) */
+#define GPIO103_CIF_DD3		103	/* Capture interface D3 (PXA27x) */
+#define GPIO104_CIF_DD2		104	/* Capture interface D2 (PXA27x) */
+#define GPIO105_CIF_DD1		105	/* Capture interface D1 (PXA27x) */
+#define GPIO106_CIF_DD9		106	/* Capture interface D9 (PXA27x) */
+#define GPIO107_CIF_DD8		107	/* Capture interface D8 (PXA27x) */
+#define GPIO108_CIF_DD7		108	/* Capture interface D7 (PXA27x) */
 #define GPIO102_nPCE_1		102	/* PCMCIA (PXA27x) */
 #define GPIO109_MMCDAT1		109	/* MMC DAT1 (PXA27x) */
 #define GPIO110_MMCDAT2		110	/* MMC DAT2 (PXA27x) */
@@ -1348,6 +1384,9 @@
 #define GPIO112_MMCCMD		112	/* MMC CMD (PXA27x) */
 #define GPIO113_I2S_SYSCLK	113	/* I2S System Clock (PXA27x) */
 #define GPIO113_AC97_RESET_N	113	/* AC97 NRESET on (PXA27x) */
+#define GPIO114_CIF_DD1		114	/* Capture interface D1 (PXA27x) */
+#define GPIO115_CIF_DD3		115	/* Capture interface D3 (PXA27x) */
+#define GPIO116_CIF_DD2		116	/* Capture interface D2 (PXA27x) */
 
 /* GPIO alternate function mode & direction */
 
@@ -1373,19 +1412,26 @@
 #define GPIO10_RTCCLK_MD	(10 | GPIO_ALT_FN_1_OUT)
 #define GPIO11_3_6MHz_MD	(11 | GPIO_ALT_FN_1_OUT)
 #define GPIO12_32KHz_MD		(12 | GPIO_ALT_FN_1_OUT)
+#define GPIO12_CIF_DD7_MD	(12 | GPIO_ALT_FN_2_IN)
 #define GPIO13_MBGNT_MD		(13 | GPIO_ALT_FN_2_OUT)
 #define GPIO14_MBREQ_MD		(14 | GPIO_ALT_FN_1_IN)
 #define GPIO15_nCS_1_MD		(15 | GPIO_ALT_FN_2_OUT)
 #define GPIO16_PWM0_MD		(16 | GPIO_ALT_FN_2_OUT)
 #define GPIO17_PWM1_MD		(17 | GPIO_ALT_FN_2_OUT)
+#define GPIO17_CIF_DD6_MD	(17 | GPIO_ALT_FN_2_IN)
 #define GPIO18_RDY_MD		(18 | GPIO_ALT_FN_1_IN)
 #define GPIO19_DREQ1_MD		(19 | GPIO_ALT_FN_1_IN)
 #define GPIO20_DREQ0_MD		(20 | GPIO_ALT_FN_1_IN)
+#define GPIO23_CIF_MCLK_MD	(23 | GPIO_ALT_FN_1_OUT)
 #define GPIO23_SCLK_MD		(23 | GPIO_ALT_FN_2_OUT)
+#define GPIO24_CIF_FV_MD	(24 | GPIO_ALT_FN_1_OUT)
 #define GPIO24_SFRM_MD		(24 | GPIO_ALT_FN_2_OUT)
+#define GPIO25_CIF_LV_MD	(25 | GPIO_ALT_FN_1_OUT)
 #define GPIO25_STXD_MD		(25 | GPIO_ALT_FN_2_OUT)
 #define GPIO26_SRXD_MD		(26 | GPIO_ALT_FN_1_IN)
+#define GPIO26_CIF_PCLK_MD	(26 | GPIO_ALT_FN_2_IN)
 #define GPIO27_SEXTCLK_MD	(27 | GPIO_ALT_FN_1_IN)
+#define GPIO27_CIF_DD0_MD	(27 | GPIO_ALT_FN_3_IN)
 #define GPIO28_BITCLK_AC97_MD	(28 | GPIO_ALT_FN_1_IN)
 #define GPIO28_BITCLK_IN_I2S_MD	(28 | GPIO_ALT_FN_2_IN)
 #define GPIO28_BITCLK_OUT_I2S_MD	(28 | GPIO_ALT_FN_1_OUT)
@@ -1410,34 +1456,46 @@
 #define GPIO40_FFDTR_MD		(40 | GPIO_ALT_FN_2_OUT)
 #define GPIO41_FFRTS_MD		(41 | GPIO_ALT_FN_2_OUT)
 #define GPIO42_BTRXD_MD		(42 | GPIO_ALT_FN_1_IN)
+#define GPIO42_CIF_MCLK_MD	(42 | GPIO_ALT_FN_3_OUT)
 #define GPIO42_HWRXD_MD		(42 | GPIO_ALT_FN_3_IN)
 #define GPIO43_BTTXD_MD		(43 | GPIO_ALT_FN_2_OUT)
+#define GPIO43_CIF_FV_MD	(43 | GPIO_ALT_FN_3_OUT)
 #define GPIO43_HWTXD_MD		(43 | GPIO_ALT_FN_3_OUT)
 #define GPIO44_BTCTS_MD		(44 | GPIO_ALT_FN_1_IN)
 #define GPIO44_HWCTS_MD		(44 | GPIO_ALT_FN_3_IN)
+#define GPIO44_CIF_LV_MD	(44 | GPIO_ALT_FN_3_OUT)
 #define GPIO45_BTRTS_MD		(45 | GPIO_ALT_FN_2_OUT)
 #define GPIO45_HWRTS_MD		(45 | GPIO_ALT_FN_3_OUT)
 #define GPIO45_SYSCLK_AC97_MD		(45 | GPIO_ALT_FN_1_OUT)
+#define GPIO45_CIF_PCLK_MD	(45 | GPIO_ALT_FN_3_IN)
 #define GPIO46_ICPRXD_MD	(46 | GPIO_ALT_FN_1_IN)
 #define GPIO46_STRXD_MD		(46 | GPIO_ALT_FN_2_IN)
 #define GPIO47_ICPTXD_MD	(47 | GPIO_ALT_FN_2_OUT)
 #define GPIO47_STTXD_MD		(47 | GPIO_ALT_FN_1_OUT)
+#define GPIO47_CIF_DD0_MD	(47 | GPIO_ALT_FN_1_IN)
 #define GPIO48_nPOE_MD		(48 | GPIO_ALT_FN_2_OUT)
+#define GPIO48_CIF_DD5_MD	(48 | GPIO_ALT_FN_1_IN)
 #define GPIO48_HWTXD_MD         (48 | GPIO_ALT_FN_1_OUT)
 #define GPIO48_nPOE_MD          (48 | GPIO_ALT_FN_2_OUT)
 #define GPIO49_HWRXD_MD		(49 | GPIO_ALT_FN_1_IN)
 #define GPIO49_nPWE_MD		(49 | GPIO_ALT_FN_2_OUT)
 #define GPIO50_nPIOR_MD		(50 | GPIO_ALT_FN_2_OUT)
+#define GPIO50_CIF_DD3_MD	(50 | GPIO_ALT_FN_1_IN)
 #define GPIO50_HWCTS_MD         (50 | GPIO_ALT_FN_1_IN)
 #define GPIO51_HWRTS_MD         (51 | GPIO_ALT_FN_1_OUT)
 #define GPIO51_nPIOW_MD		(51 | GPIO_ALT_FN_2_OUT)
+#define GPIO51_CIF_DD2_MD	(51 | GPIO_ALT_FN_1_IN)
 #define GPIO52_nPCE_1_MD	(52 | GPIO_ALT_FN_2_OUT)
+#define GPIO52_CIF_DD4_MD	(52 | GPIO_ALT_FN_1_IN)
 #define GPIO53_nPCE_2_MD	(53 | GPIO_ALT_FN_2_OUT)
 #define GPIO53_MMCCLK_MD	(53 | GPIO_ALT_FN_1_OUT)
+#define GPIO53_CIF_MCLK_MD	(53 | GPIO_ALT_FN_2_OUT)
 #define GPIO54_MMCCLK_MD	(54 | GPIO_ALT_FN_1_OUT)
 #define GPIO54_nPCE_2_MD	(54 | GPIO_ALT_FN_2_OUT)
 #define GPIO54_pSKTSEL_MD	(54 | GPIO_ALT_FN_2_OUT)
+#define GPIO54_CIF_PCLK_MD	(54 | GPIO_ALT_FN_3_IN)
 #define GPIO55_nPREG_MD		(55 | GPIO_ALT_FN_2_OUT)
+#define GPIO55_CIF_DD1_MD	(55 | GPIO_ALT_FN_1_IN)
 #define GPIO56_nPWAIT_MD	(56 | GPIO_ALT_FN_1_IN)
 #define GPIO57_nIOIS16_MD	(57 | GPIO_ALT_FN_1_IN)
 #define GPIO58_LDD_0_MD		(58 | GPIO_ALT_FN_2_OUT)
@@ -1474,16 +1532,33 @@
 #define GPIO80_nCS_4_MD		(80 | GPIO_ALT_FN_2_OUT)
 #define GPIO81_NSSP_CLK_OUT 	(81 | GPIO_ALT_FN_1_OUT)
 #define GPIO81_NSSP_CLK_IN  	(81 | GPIO_ALT_FN_1_IN)
+#define GPIO81_CIF_DD0_MD	(81 | GPIO_ALT_FN_2_IN)
 #define GPIO82_NSSP_FRM_OUT 	(82 | GPIO_ALT_FN_1_OUT)
 #define GPIO82_NSSP_FRM_IN  	(82 | GPIO_ALT_FN_1_IN)
+#define GPIO82_CIF_DD5_MD	(82 | GPIO_ALT_FN_3_IN)
 #define GPIO83_NSSP_TX      	(83 | GPIO_ALT_FN_1_OUT)
 #define GPIO83_NSSP_RX      	(83 | GPIO_ALT_FN_2_IN)
+#define GPIO83_CIF_DD4_MD	(83 | GPIO_ALT_FN_3_IN)
 #define GPIO84_NSSP_TX      	(84 | GPIO_ALT_FN_1_OUT)
 #define GPIO84_NSSP_RX      	(84 | GPIO_ALT_FN_2_IN)
+#define GPIO84_CIF_FV_MD	(84 | GPIO_ALT_FN_3_OUT)
 #define GPIO85_nPCE_1_MD	(85 | GPIO_ALT_FN_1_OUT)
+#define GPIO85_CIF_LV_MD	(85 | GPIO_ALT_FN_3_OUT)
+#define GPIO90_CIF_DD4_MD	(90 | GPIO_ALT_FN_3_IN)
+#define GPIO91_CIF_DD5_MD	(91 | GPIO_ALT_FN_3_IN)
 #define GPIO92_MMCDAT0_MD	(92 | GPIO_ALT_FN_1_OUT)
+#define GPIO93_CIF_DD6_MD	(93 | GPIO_ALT_FN_2_IN)
+#define GPIO94_CIF_DD5_MD	(94 | GPIO_ALT_FN_2_IN)
+#define GPIO95_CIF_DD4_MD	(95 | GPIO_ALT_FN_2_IN)
+#define GPIO98_CIF_DD0_MD	(98 | GPIO_ALT_FN_2_IN)
 #define GPIO102_nPCE_1_MD	(102 | GPIO_ALT_FN_1_OUT)
+#define GPIO103_CIF_DD3_MD	(103 | GPIO_ALT_FN_1_IN)
 #define GPIO104_pSKTSEL_MD	(104 | GPIO_ALT_FN_1_OUT)
+#define GPIO104_CIF_DD2_MD	(104 | GPIO_ALT_FN_1_IN)
+#define GPIO105_CIF_DD1_MD	(105 | GPIO_ALT_FN_1_IN)
+#define GPIO106_CIF_DD9_MD	(106 | GPIO_ALT_FN_1_IN)
+#define GPIO107_CIF_DD8_MD	(107 | GPIO_ALT_FN_1_IN)
+#define GPIO108_CIF_DD7_MD	(108 | GPIO_ALT_FN_1_IN)
 #define GPIO109_MMCDAT1_MD	(109 | GPIO_ALT_FN_1_OUT)
 #define GPIO110_MMCDAT2_MD	(110 | GPIO_ALT_FN_1_OUT)
 #define GPIO110_MMCCS0_MD	(110 | GPIO_ALT_FN_1_OUT)
@@ -1938,6 +2013,11 @@
 #define CICR0_ENB	(1 << 28)	/* Camera interface enable */
 #define CICR0_DIS	(1 << 27)	/* Camera interface disable */
 #define CICR0_SIM	(0x7 << 24)	/* Sensor interface mode mask */
+#define CICR0_SIM_MP	(0 << 24)
+#define CICR0_SIM_SP	(1 << 24)
+#define CICR0_SIM_MS	(2 << 24)
+#define CICR0_SIM_EP	(3 << 24)
+#define CICR0_SIM_ES	(4 << 24)
 #define CICR0_TOM	(1 << 9)	/* Time-out mask */
 #define CICR0_RDAVM	(1 << 8)	/* Receive-data-available mask */
 #define CICR0_FEM	(1 << 7)	/* FIFO-empty mask */
@@ -1988,6 +2068,20 @@
 #define CICR4_FR_RATE	(0x7 << 8)	/* Frame rate mask */
 #define CICR4_DIV	(0xff << 0)	/* Clock divisor mask */
 
+#define CICR1_DW_VAL(x)		((x) & CICR1_DW)		/* Data bus width */
+#define CICR1_PPL_VAL(x)	(((x) << 15) & CICR1_PPL)	/* Pixels per line */
+
+#define CICR2_BLW_VAL(x)	(((x) << 24) & CICR2_BLW)	/* Beginning-of-line pixel clock wait count */
+#define CICR2_ELW_VAL(x)	(((x) << 16) & CICR2_ELW)	/* End-of-line pixel clock wait count */
+#define CICR2_HSW_VAL(x)	(((x) << 10) & CICR2_HSW)	/* Horizontal sync pulse width */
+#define CICR2_BFPW_VAL(x)	(((x) << 3) & CICR2_BFPW)	/* Beginning-of-frame pixel clock wait count */
+#define CICR2_FSW_VAL(x)	(((x) << 0) & CICR2_FSW)	/* Frame stabilization wait count */
+
+#define CICR3_BFW_VAL(x)	(((x) << 24) & CICR3_BFW)	/* Beginning-of-frame line clock wait count  */
+#define CICR3_EFW_VAL(x)	(((x) << 16) & CICR3_EFW)	/* End-of-frame line clock wait count */
+#define CICR3_VSW_VAL(x)	(((x) << 11) & CICR3_VSW)	/* Vertical sync pulse width */
+#define CICR3_LPF_VAL(x)	(((x) << 0) & CICR3_LPF)	/* Lines per frame */
+
 #define CISR_FTO	(1 << 15)	/* FIFO time-out */
 #define CISR_RDAV_2	(1 << 14)	/* Channel 2 receive data available */
 #define CISR_RDAV_1	(1 << 13)	/* Channel 1 receive data available */
-- 
1.5.3.4


--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@xxxxxxxxxx?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list