diff -urN linux-2.6.19-clean/drivers/media/video/omap/Kconfig linux-2.6.19/drivers/media/video/omap/Kconfig
--- linux-2.6.19-clean/drivers/media/video/omap/Kconfig	2007-01-16 01:06:50.000000000 +0000
+++ linux-2.6.19/drivers/media/video/omap/Kconfig	2007-01-23 02:14:45.000000000 +0000
@@ -1,7 +1,7 @@
 config VIDEO_OMAP_CAMERA
 	tristate "OMAP Camera support (EXPERIMENTAL)"
 	select VIDEO_BUF
-	depends on VIDEO_DEV && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+	depends on VIDEO_DEV && (ARCH_OMAP16XX || ARCH_OMAP24XX || MACH_AMS_DELTA)
 	help
 	  V4L2 camera driver support for OMAP1/2 based boards.
 	
@@ -10,3 +10,9 @@
 	depends on VIDEO_OMAP_CAMERA
 	help
 	  OmniVision 9640 camera sensor support
+
+config VIDEO_CAMERA_SENSOR_OV6650
+	bool "OV6650  sensor support"
+	depends on VIDEO_OMAP_CAMERA 
+	help
+	  E3 Camera
diff -urN linux-2.6.19-clean/drivers/media/video/omap/Makefile linux-2.6.19/drivers/media/video/omap/Makefile
--- linux-2.6.19-clean/drivers/media/video/omap/Makefile	2007-01-16 01:06:50.000000000 +0000
+++ linux-2.6.19/drivers/media/video/omap/Makefile	2007-01-23 02:18:50.000000000 +0000
@@ -2,7 +2,9 @@
 
 obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omapcamera.o
 obj-$(CONFIG_VIDEO_CAMERA_SENSOR_OV9640) += sensor_ov9640.o
+obj-$(CONFIG_VIDEO_CAMERA_SENSOR_OV6650) += sensor_ov6650.o
 
+objs-y$(CONFIG_MACH_AMS_DELTA) += omap1510cam.o camera_core.o 
 objs-y$(CONFIG_ARCH_OMAP16XX) += omap16xxcam.o camera_core.o
 objs-y$(CONFIG_MACH_OMAP_H3) += h3_sensor_power.o
 objs-y$(CONFIG_MACH_OMAP_H4) += h4_sensor_power.o
diff -urN linux-2.6.19-clean/drivers/media/video/omap/omap1510cam.c linux-2.6.19/drivers/media/video/omap/omap1510cam.c
--- linux-2.6.19-clean/drivers/media/video/omap/omap1510cam.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19/drivers/media/video/omap/omap1510cam.c	2007-01-23 02:39:17.000000000 +0000
@@ -0,0 +1,507 @@
+/*
+ * drivers/media/video/omap/omap1510cam.c
+ *
+ * Based on
+ * drivers/media/video/omap/omap16xxcam.c
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2006 Matt Callow
+ *
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP 1510 camera controller
+ *
+ * leverage some code from CEE distribution
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/hardware.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/mach-types.h>
+#include <asm/arch/board-ams-delta.h>
+
+
+#include "omap1510cam.h"
+#include "camera_hw_if.h"
+#include "camera_core.h"
+
+#define CONF_CAMERAIF_RESET_R 5
+#define EN_PER	  0
+
+typedef struct {
+        unsigned int ctrlclock;     /* 00 */
+        unsigned int it_status;     /* 04 */
+        unsigned int mode;          /* 08 */
+        unsigned int status;        /* 0C */
+        unsigned int camdata;       /* 10 */
+        unsigned int gpio;   	    /* 14 */
+        unsigned int peak_counter;  /* 18 */
+} camera_regs_t;
+
+struct camdma_state {
+	dma_callback_t callback;
+	void *arg1;
+	void *arg2;
+};
+
+struct omap1510cam {
+	camera_regs_t *camera_regs;
+	unsigned long iobase_phys;
+
+	/* dma related stuff */
+	spinlock_t dma_lock;
+	int free_dmach;
+	struct camdma_state camdma;
+	int dma_channel;
+
+	wait_queue_head_t vsync_wait;
+
+	int new;
+};
+static struct omap1510cam hardware_data;
+
+static int omap1510cam_set_xclk(int, void *);
+static void omap1510_cam_dma_link_callback(int, unsigned short, void *);
+
+/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration
+   register. */
+static void
+omap1510_cam_clear_fifo(struct omap1510cam *data)
+{
+	//data->camera_regs->ctrlclock &= ~LCLK_EN;
+	data->camera_regs->mode |= RAZ_FIFO;
+	udelay(10);
+	data->camera_regs->mode &= ~RAZ_FIFO;
+	//data->camera_regs->ctrlclock |= LCLK_EN;
+}
+
+static void
+omap1510_cam_reset(struct omap1510cam *data, int yes)
+{
+	data->camera_regs->gpio = yes ? 1 : 0;
+}
+
+static void
+omap1510_cam_init(void)
+{
+	printk(KERN_DEBUG "omap1510_cam_init\r\n");
+	/*
+	 * FIXME - Use mux API's instead of directly writing in to MUX registers
+	 */
+	omap_writel(omap_readl(FUNC_MUX_CTRL_4) & ~(0x1ff << 21), FUNC_MUX_CTRL_4);
+	omap_writel(0, FUNC_MUX_CTRL_5);
+	omap_writel(omap_readl(PULL_DWN_CTRL_0) & ~(0x1FFF << 17), PULL_DWN_CTRL_0);
+	omap_writel(omap_readl(PU_PD_SEL_0) & ~(0x1FFF << 17), PU_PD_SEL_0);
+
+	omap_writel(0xeaef, COMP_MODE_CTRL_0);
+	omap_writel(omap_readl(OMAP1610_RESET_CONTROL) & ~(1 << CONF_CAMERAIF_RESET_R),
+			OMAP1610_RESET_CONTROL);
+	omap_writel(omap_readl(OMAP1610_RESET_CONTROL) | (1 << CONF_CAMERAIF_RESET_R),
+			OMAP1610_RESET_CONTROL);
+
+	/* Enable peripheral reset */
+	omap_writew(omap_readw(ARM_RSTCT2) | (1 << EN_PER), ARM_RSTCT2);
+
+	/* enable peripheral clock */
+	clk_enable(clk_get(0, "armper_ck"));
+}
+
+static void
+omap1510_cam_waitfor_syncedge(struct omap1510cam *data, u32 edge_mask)
+{
+	data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT) | edge_mask;
+	do {
+		interruptible_sleep_on(&data->vsync_wait);
+	} while (signal_pending(current));
+}
+
+static void
+omap1510_cam_configure_dma(struct omap1510cam *data)
+{
+
+	data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT)
+			 | EN_DMA | EN_FIFO_FULL;
+	data->camera_regs->ctrlclock |= LCLK_EN;
+}
+
+/* acquire h/w resources DMA */
+static int
+omap1510_cam_link_open(struct omap1510cam *data)
+{
+	int ret;
+
+	/* Acquire dma channel */
+	if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX,
+				"camera dma 1", omap1510_cam_dma_link_callback,
+				(void *)data, &data->dma_channel))) {
+                return ret;
+	}
+	printk(KERN_DEBUG "Got DMA channel %d\n", data->dma_channel);
+	// set up sync
+	//OMAP_DMA_CCR_REG(data->dma_channel) |= OMAP_DMA_CAMERA_IF_RX;
+	return 0;
+}
+
+/* free h/w resources, stop i/f */
+static int
+omap1510_cam_link_close(struct omap1510cam *data)
+{
+	/* free dma */
+	omap_stop_dma(data->dma_channel);
+	omap_free_dma (data->dma_channel);
+
+	return 0;
+}
+
+/* dma callback routine. */
+static void
+omap1510_cam_dma_link_callback(int lch, unsigned short ch_status, void *data)
+{
+	void *arg1, *arg2;
+	struct sgdma_state *sgdma = sgdma;
+	struct omap1510cam *cam = (struct omap1510cam *)data;
+	dma_callback_t callback;
+
+	//printk("omap1510_cam_dma_link_callback ch=%d status=%d\n", lch, ch_status);
+	spin_lock(&cam->dma_lock);
+	if (cam->free_dmach == 1)
+	{
+		printk(KERN_WARNING "callback all CHANNELS WERE IDLE \n");
+		spin_unlock(&cam->dma_lock);
+		return;
+	}
+
+	if (OMAP_DMA_CCR_REG(cam->dma_channel) & (1 << 7)) {
+		printk(KERN_WARNING "transfer still in progress\n");
+	} else {
+
+		callback = cam->camdma.callback;
+ 		arg1 = cam->camdma.arg1;
+		arg2 = cam->camdma.arg2;
+		cam->free_dmach++;
+
+		spin_unlock(&cam->dma_lock);
+ 		callback(arg1, arg2);
+		spin_lock(&cam->dma_lock);
+	}
+
+	spin_unlock(&cam->dma_lock);
+
+}
+
+static irqreturn_t
+omap1510_cam_isr(int irq, void *client_data, struct pt_regs *regs)
+{
+	struct omap1510cam *data = (struct omap1510cam *)client_data;
+	unsigned int itstat = data->camera_regs->it_status;
+
+	/* VSYNC UP interrupt, start filling FIFO and enabling DMA */
+	if (itstat & V_UP) {
+		data->camera_regs->mode &= ~EN_V_UP;
+	 	omap1510_cam_clear_fifo(data);
+		omap1510_cam_configure_dma(data);
+		omap_start_dma(data->dma_channel);
+		wake_up_interruptible(&data->vsync_wait);
+	}
+
+	if (itstat & V_DOWN) {
+		data->camera_regs->mode &= ~EN_V_DOWN;
+		wake_up_interruptible(&data->vsync_wait);
+	}
+
+	if (itstat & H_UP)
+		printk(KERN_WARNING "H_UP\n");
+
+	if (itstat & H_DOWN)
+		printk(KERN_WARNING "H_DOWN\n");
+
+	if (itstat & FIFO_FULL) {
+		omap1510_cam_clear_fifo(data);
+		printk(KERN_WARNING "FIFO_FULL\n");
+	}
+
+	if (itstat & DATA_XFER)
+		printk(KERN_WARNING "DATA_TRANS\n");
+
+	return IRQ_HANDLED;
+}
+
+/* ------------- below are interface functions ----------------- */
+/* ------------- these functions are named omap1510cam_<name> -- */
+static int
+omap1510cam_init_dma(void *priv)
+{
+	struct omap1510cam *data = (struct omap1510cam *) priv;
+
+	printk(KERN_DEBUG "omap1510cam_init_dma\r\n");
+
+	data->free_dmach = 1;
+	data->camdma.callback = NULL;
+	data->camdma.arg1 = NULL;
+	data->camdma.arg2 = NULL;
+
+	return 0;
+}
+
+/* start the dma of chains */
+static int
+omap1510cam_start_dma(struct sgdma_state *sgdma,
+		dma_callback_t callback, void *arg1, void *arg2, void *priv)
+{
+	struct omap1510cam *data = (struct omap1510cam *) priv;
+	struct scatterlist *sglist;
+	unsigned long irqflags;
+	int dmach;
+
+	spin_lock_irqsave(&data->dma_lock, irqflags);
+	sglist = (struct scatterlist *)(sgdma->sglist + sgdma->next_sglist);
+
+	if (!data->free_dmach) {
+		spin_unlock_irqrestore(&data->dma_lock, irqflags);
+		return -EBUSY;
+	}
+	dmach = data->dma_channel;
+	data->camdma.callback = callback;
+	data->camdma.arg1 = arg1;
+	data->camdma.arg2 = arg2;
+	//printk("omap1510cam_start_dma dst=%u\n", sg_dma_address(sglist) );
+	omap_set_dma_dest_params(dmach, OMAP_DMA_PORT_EMIFF,
+	                     OMAP_DMA_AMODE_POST_INC, sg_dma_address(sglist),
+			     0, 0);
+
+	omap_set_dma_transfer_params(dmach, OMAP_DMA_DATA_TYPE_S32,
+			FIFO_TRIGGER_LVL,
+			sg_dma_len(sglist)/(DMA_ELEM_SIZE * FIFO_TRIGGER_LVL),
+ 			OMAP_DMA_SYNC_FRAME,
+			0, 0);
+
+	// set up sync device
+	//OMAP_DMA_CCR_REG(dmach) &= ~0x1f;
+	//OMAP_DMA_CCR_REG(dmach) |= OMAP_DMA_CAMERA_IF_RX;
+
+	if (data->new) {
+		data->new = 0;
+		omap_set_dma_src_params(dmach, OMAP_DMA_PORT_TIPB,
+			OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG,
+			0, 0);
+		omap1510_cam_waitfor_syncedge(data, EN_V_UP);
+	} else {
+		omap_start_dma(dmach);
+	}
+
+	data->free_dmach--;
+	spin_unlock_irqrestore(&data->dma_lock, irqflags);
+	return 0;
+}
+int static
+omap1510cam_finish_dma(void *priv)
+{
+	struct omap1510cam *data = (struct omap1510cam *) priv;
+
+	printk(KERN_DEBUG "omap1510cam_finish_dma\n");
+	while (data->free_dmach < 1)
+		mdelay(1);
+
+	return 0;
+}
+
+
+/* Enables the camera. Takes camera out of reset. Enables the clocks. */
+static int
+omap1510cam_enable(void *priv)
+{
+	struct omap1510cam *data = (struct omap1510cam *) priv;
+
+	printk(KERN_DEBUG "omap1510cam_enable\r\n");
+
+	omap1510_cam_reset(data, 1);
+
+	/* give clock to camera_module */
+	data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT);
+	data->camera_regs->ctrlclock = MCLK_EN | CAMEXCLK_EN;
+
+	omap1510_cam_clear_fifo(data);
+
+	/* wait for camera to settle down */
+	mdelay(5);
+
+	printk(KERN_DEBUG "exit omap1510cam_enable\r\n");
+	return 0;
+}
+
+/* Disables all the camera clocks. Put the camera interface in reset. */
+static int
+omap1510cam_disable(void *priv)
+{
+	struct omap1510cam *data = (struct omap1510cam *) priv;
+
+	omap1510_cam_clear_fifo(data);
+
+	data->camera_regs->ctrlclock = 0x00000000;
+	data->camera_regs->mode = 0x00000000;
+
+	omap1510_cam_reset(data, 0);
+
+	return 0;
+}
+
+/* Abort the data transfer */
+static int
+omap1510cam_abort(void *priv)
+{
+	return omap1510cam_disable(priv);
+}
+
+/*
+ * Set camera xclk
+ * Set to the requested frequency, or the next highest available
+ */
+static int
+omap1510cam_set_xclk(int requested_xclk, void *priv)
+{
+ 	int xclk_val;
+	int actual_xclk;
+	struct omap1510cam *data = (struct omap1510cam *) priv;
+
+	if (requested_xclk <= 6000000) {
+		actual_xclk = 6000000;
+		xclk_val = FOSCMOD_6MHz;
+	} else if (requested_xclk <= 8000000) {
+		actual_xclk = 8000000;
+		xclk_val = FOSCMOD_8MHz | DPLL_EN;
+	} else if (requested_xclk <= 9600000) {
+		actual_xclk = 9600000;
+		xclk_val = FOSCMOD_9_6MHz | DPLL_EN;
+	} else if (requested_xclk <= 12000000) {
+		actual_xclk = 12000000;
+		xclk_val = FOSCMOD_12MHz;
+	} else {
+		actual_xclk = 24000000;
+		xclk_val = FOSCMOD_24MHz | DPLL_EN;
+	}
+
+	/* follow the protocol to change the XCLK clock */
+	data->camera_regs->ctrlclock=data->camera_regs->ctrlclock&(~(MCLK_EN|DPLL_EN));
+        data->camera_regs->ctrlclock = data->camera_regs->ctrlclock | (CAMEXCLK_EN | xclk_val);
+        data->camera_regs->ctrlclock = data->camera_regs->ctrlclock | (MCLK_EN | LCLK_EN );
+
+	printk(KERN_DEBUG "omap1510cam_set_xclk requested=%d actual=%d\r\n", requested_xclk, actual_xclk);
+	return (actual_xclk);
+}
+
+static int
+omap1510cam_open(void *priv)
+{
+	struct omap1510cam *data = (struct omap1510cam *) priv;
+	int ret;
+
+	if ((ret = request_irq(INT_CAMERA, omap1510_cam_isr, SA_INTERRUPT,
+					"camera", data))) {
+		printk(KERN_ERR "FAILED to aquire irq\n");
+		return ret;
+	}
+
+	data->new = 1;
+	omap1510cam_enable(data);
+	omap1510cam_init_dma(data);
+
+	ams_delta_latch1_write(0x01, 0x01);
+	return omap1510_cam_link_open(data);
+}
+
+static int
+omap1510cam_close(void *priv)
+{
+	struct omap1510cam *data = (struct omap1510cam *) priv;
+
+	omap1510cam_disable(priv);
+
+	free_irq(INT_CAMERA, data);
+
+	ams_delta_latch1_write(0x01, 0x00);
+	return omap1510_cam_link_close(data);
+}
+
+static int
+omap1510cam_cleanup(void *priv)
+{
+	struct omap1510cam *data = (struct omap1510cam *) priv;
+
+	omap1510cam_disable(data);
+	if (data->iobase_phys) {
+		release_mem_region(data->iobase_phys, CAMERA_IOSIZE);
+		data->iobase_phys = 0;
+	}
+
+	return 0;
+}
+
+/* Initialise the OMAP camera interface */
+static void *
+omap1510cam_init(void)
+{
+	unsigned long cam_iobase;
+
+	printk(KERN_DEBUG "omap1510cam_init\r\n");
+
+	if (!request_region(CAMERA_BASE, CAMERA_IOSIZE, "OAMP1510 Camera")) {
+		printk (KERN_ERR "OMAP1510 Parallel Camera Interface is already in use\n");
+		return NULL;
+	}
+
+	cam_iobase = io_p2v(CAMERA_BASE);
+
+	printk(KERN_DEBUG "cam_iobase %lX\r\n", cam_iobase);
+
+	/* Set the base address of the camera registers */
+	hardware_data.camera_regs = (camera_regs_t *)cam_iobase;
+	hardware_data.iobase_phys = (unsigned long) CAMERA_BASE;
+
+	/* Init the camera IF */
+	omap1510_cam_init();
+	/* enable it. This is needed for sensor detection */
+	omap1510cam_enable((void*)&hardware_data);
+	/* Init dma data */
+	spin_lock_init(&hardware_data.dma_lock);
+
+	init_waitqueue_head(&hardware_data.vsync_wait);
+	printk(KERN_DEBUG "exit omap1510cam_init\r\n");
+	return (void*)&hardware_data;
+}
+
+struct camera_hardware camera_hardware_if = {
+	.version	= 0x01,
+	.name		= "OMAP1510 Camera Parallel",
+	.init		= omap1510cam_init,
+	.cleanup	= omap1510cam_cleanup,
+	.open		= omap1510cam_open,
+	.close		= omap1510cam_close,
+	.enable		= omap1510cam_enable,
+	.disable	= omap1510cam_disable,
+	.abort		= omap1510cam_abort,
+	.set_xclk	= omap1510cam_set_xclk,
+	.init_dma	= omap1510cam_init_dma,
+	.start_dma	= omap1510cam_start_dma,
+	.finish_dma	= omap1510cam_finish_dma,
+};
+
diff -urN linux-2.6.19-clean/drivers/media/video/omap/omap1510cam.h linux-2.6.19/drivers/media/video/omap/omap1510cam.h
--- linux-2.6.19-clean/drivers/media/video/omap/omap1510cam.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19/drivers/media/video/omap/omap1510cam.h	2007-01-23 02:14:45.000000000 +0000
@@ -0,0 +1,104 @@
+/*
+ *  drivers/media/video/omap/omap1510cam.h
+ *  based on omap16xxcam.h
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc. 
+ * Copyright (C) 2006 Matt Callow
+ * 
+ * This package is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. 
+ * 
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
+ */
+ 
+#ifndef OMAP_1510_CAM_H
+#define OMAP_1510_CAM_H
+
+#define DMA_ELEM_SIZE   4
+#define FIFO_TRIGGER_LVL (32)
+
+/*
+ * ---------------------------------------------------------------------------
+ *  OMAP1510 Camera Interface
+ * ---------------------------------------------------------------------------
+ */
+
+#define CAMERA_BASE          (IO_PHYS + 0x6800)
+
+#define CAM_CTRLCLOCK_REG    (CAMERA_BASE + 0x00)
+#define CAM_IT_STATUS_REG    (CAMERA_BASE + 0x04)
+#define CAM_MODE_REG         (CAMERA_BASE + 0x08)
+#define CAM_STATUS_REG       (CAMERA_BASE + 0x0C)
+#define CAM_CAMDATA_REG      (CAMERA_BASE + 0x10)
+#define CAM_GPIO_REG         (CAMERA_BASE + 0x14)
+#define CAM_PEAK_CTR_REG     (CAMERA_BASE + 0x18)
+#define CAMERA_IOSIZE        0x1C
+
+/* CTRLCLOCK bit shifts */
+#define FOSCMOD_BIT    		0
+#define FOSCMOD_MASK   		(0x7 << FOSCMOD_BIT)
+#define FOSCMOD_12MHz		0x0
+#define	FOSCMOD_6MHz		0x2
+#define	FOSCMOD_9_6MHz		0x4
+#define	FOSCMOD_24MHz		0x5
+#define	FOSCMOD_8MHz		0x6
+#define	FOSCMOD_TC2_CK2		0x3
+#define	FOSCMOD_TC2_CK3    	0x1
+#define	FOSCMOD_TC2_CK4     	0x5
+#define	FOSCMOD_TC2_CK8     	0x0
+#define	FOSCMOD_TC2_CK10     	0x4
+#define	FOSCMOD_TC2_CK12     	0x6
+#define	FOSCMOD_TC2_CK16     	0x2
+#define	POLCLK         		(1<<3)
+#define	CAMEXCLK_EN    		(1<<4)
+#define	MCLK_EN        		(1<<5)
+#define	DPLL_EN        		(1<<6)
+#define	LCLK_EN        		(1<<7)
+
+/* IT_STATUS bit shifts */
+#define V_UP           (1<<0)
+#define V_DOWN         (1<<1)
+#define H_UP           (1<<2)
+#define H_DOWN         (1<<3)
+#define FIFO_FULL      (1<<4)
+#define DATA_XFER      (1<<5)
+
+/* MODE bit shifts */
+#define CAMOSC         (1<<0)
+#define IMGSIZE_BIT    1
+#define IMGSIZE_MASK   (0x3 << IMGSIZE_BIT)
+#define	IMGSIZE_CIF      (0x0 << IMGSIZE_BIT)    /* 352x288 */
+#define	IMGSIZE_QCIF     (0x1 << IMGSIZE_BIT)    /* 176x144 */
+#define	IMGSIZE_VGA      (0x2 << IMGSIZE_BIT)    /* 640x480 */
+#define	IMGSIZE_QVGA     (0x3 << IMGSIZE_BIT)    /* 320x240 */
+#define ORDERCAMD      (1<<3)
+#define EN_V_UP        (1<<4)
+#define EN_V_DOWN      (1<<5)
+#define EN_H_UP        (1<<6)
+#define EN_H_DOWN      (1<<7)
+#define EN_DMA         (1<<8)
+#define THRESHOLD      (1<<9)
+#define THRESHOLD_BIT  9
+#define THRESHOLD_MASK (0x7f<<9)
+#define EN_NIRQ        (1<<16)
+#define EN_FIFO_FULL   (1<<17)
+#define RAZ_FIFO       (1<<18)
+
+/* STATUS bit shifts */
+#define VSTATUS        (1<<0)
+#define HSTATUS        (1<<1)
+
+/* GPIO bit shifts */
+#define CAM_RST        (1<<0)
+
+
+#define XCLK_6MHZ     6000000
+#define XCLK_8MHZ     8000000
+#define XCLK_9_6MHZ   9000000
+#define XCLK_12MHZ   12000000
+#define XCLK_24MHZ   24000000
+
+#endif /* OMAP_1510_CAM_H */
diff -urN linux-2.6.19-clean/drivers/media/video/omap/ov6650.h linux-2.6.19/drivers/media/video/omap/ov6650.h
--- linux-2.6.19-clean/drivers/media/video/omap/ov6650.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19/drivers/media/video/omap/ov6650.h	2007-01-23 02:14:45.000000000 +0000
@@ -0,0 +1,113 @@
+/*
+ * drivers/media/video/omap/ov6650.h
+ *
+ * Register definitions for the OmniVision OV6650 CameraChip.
+ *
+ * Copyright (c) 2006 Matt Callow
+ *
+ * This file is licensed under the terms of the GNU General Public License 
+ * version 2. This program is licensed "as is" without any warranty of any 
+ * kind, whether express or implied.
+ */
+
+#ifndef OV6650_H
+#define OV6650_H
+
+#define OV6650_I2C_ADDR	0x60
+
+#define OV6650_PIDH_MAGIC	0x66	/* high byte of product ID number */
+#define OV6650_PIDL_MAGIC	0x50	/* low byte of product ID number */
+#define OV6650_MIDH_MAGIC	0x7F	/* high byte of mfg ID */
+#define OV6650_MIDL_MAGIC	0xA2	/* low byte of mfg ID */
+
+/* define register offsets for the OV6650 sensor chip */
+#define OV6650_GAIN	0x00	/* range 00 - 3F */
+#define OV6650_BLUE	0x01
+#define OV6650_RED	0x02
+#define OV6650_SAT 	0x03	/* [7:4] saturation [0:3] reserved */
+#define OV6650_HUE 	0x04	/* [7:6] rsrvd [5] hue en [4:0] hue */
+#define OV6650_BRT  	0x06
+#define OV6650_PIDH	0x0A
+#define OV6650_PIDL 	0x0B
+#define OV6650_AECH 	0x10	/* Exposure Value */
+#define OV6650_CLKRC 	0x11	/* Data Format and Internal Clock */
+				/* [7:6] Input system clock (MHz)*/
+				/*   00=8, 01=12, 10=16, 11=24 */
+				/* [5:0]: Internal Clock Pre-Scaler */
+#define OV6650_COMA 	0x12	/* [7] Reset */
+#define OV6650_COMB 	0x13 
+#define OV6650_COMC 	0x14 
+#define OV6650_COMD 	0x15 
+#define OV6650_COML	0x16 
+#define OV6650_HSTART 	0x17 
+#define OV6650_HSTOP 	0x18 
+#define OV6650_VSTRT	0x19 
+#define OV6650_VSTOP	0x1A 
+#define OV6650_PSHFT	0x1B 
+#define OV6650_MIDH 	0x1C 
+#define OV6650_MIDL 	0x1D 
+#define OV6650_HSYNCS 	0x1E 
+#define OV6650_HSYNCE 	0x1F 
+#define OV6650_COME 	0x20 
+#define OV6650_YOFF	0x21 
+#define OV6650_UOFF	0x22 
+#define OV6650_VOFF	0x23 
+#define OV6650_AEW 	0x24 
+#define OV6650_AEB 	0x25 
+#define OV6650_COMF	0x26 
+#define OV6650_COMG 	0x27 
+#define OV6650_COMH 	0x28 
+#define OV6650_COMI 	0x29 
+#define OV6650_RSVD 	0x2A 
+#define OV6650_FRARL 	0x2B 
+#define OV6650_COMJ 	0x2C 
+#define OV6650_COMK 	0x2D 
+#define OV6650_AVGY 	0x2E 
+#define OV6650_REF0 	0x2F 
+#define OV6650_REF1 	0x30 
+#define OV6650_REF2 	0x31 
+#define OV6650_FRAJH 	0x32 
+#define OV6650_FRAJL 	0x33 
+#define OV6650_FACT 	0x34 
+#define OV6650_L1AEC 	0x35 
+#define OV6650_AVGU 	0x36 
+#define OV6650_AVGV 	0x37 
+#define OV6650_SPCB 	0x60 
+#define OV6650_SPCC 	0x61 
+#define OV6650_GAM1 	0x62 
+#define OV6650_GAM2 	0x63 
+#define OV6650_GAM3 	0x64 
+#define OV6650_SPCD 	0x65 
+#define OV6650_SPCE 	0x68 
+#define OV6650_ADCL 	0x69 
+#define OV6650_RMCO 	0x6C 
+#define OV6650_GMCO 	0x6D 
+#define OV6650_BMCO 	0x6E 
+#define OV6650_NUM_REGS		(OV6650_BMCO + 1)
+
+/* define a structure for register initialization values */
+struct ov6650_reg {
+	unsigned char reg;
+	unsigned char val;
+};
+
+enum image_size { QCIF, CIF };
+enum pixel_format { YUV, RGB565, RGB555 };
+#define NUM_IMAGE_SIZES 2
+#define NUM_PIXEL_FORMATS 3
+
+struct capture_size {
+	unsigned long width;
+	unsigned long height;
+};
+
+/* Array of image sizes supported by OV6650.  These must be ordered from 
+ * smallest image size to largest.
+ */
+const static struct capture_size ov6650_sizes[] = {
+	{  176, 144 },	/* QCIF */
+	{  352, 288 },	/* CIF */
+};
+
+#endif /* ifndef OV6650_H */
+
diff -urN linux-2.6.19-clean/drivers/media/video/omap/sensor_ov6650.c linux-2.6.19/drivers/media/video/omap/sensor_ov6650.c
--- linux-2.6.19-clean/drivers/media/video/omap/sensor_ov6650.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19/drivers/media/video/omap/sensor_ov6650.c	2007-01-23 03:08:07.000000000 +0000
@@ -0,0 +1,894 @@
+
+/*
+ * drivers/media/video/omap/sensor_ov6650.c
+ *
+ * Ov6650 Sensor driver for OMAP camera sensor interface
+ * Based on sensor_ov9640.c, by Andy Lowe
+ *
+ * Author: Matt Callow (matt.callow at gmail.com)
+ * Author: Andy Lowe (source at mvista.com)
+ *
+ * Copyright (c) 2006 Matt Callow
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <media/video-buf.h>
+#include <linux/delay.h>
+#include <asm/mach-types.h>
+
+#include "sensor_if.h"
+#include "ov6650.h"
+
+#define CAMERA_OV6650
+#ifdef CAMERA_OV6650
+
+struct ov6650_sensor {
+	/* I2C parameters */
+	struct i2c_client client;
+};
+
+static struct ov6650_sensor ov6650;
+
+/* list of image formats supported by OV9640 sensor */
+const static struct v4l2_fmtdesc ov6650_formats[] = {
+	{
+		/* Note:  V4L2 defines RGB565 as:
+		 *
+		 *	Byte 0			  Byte 1
+		 *	g2 g1 g0 r4 r3 r2 r1 r0	  b4 b3 b2 b1 b0 g5 g4 g3
+		 *
+		 * We interpret RGB565 as:
+		 *
+		 *	Byte 0			  Byte 1
+		 *	g2 g1 g0 b4 b3 b2 b1 b0	  r4 r3 r2 r1 r0 g5 g4 g3
+		 */
+		.description	= "RGB565, le",
+		.pixelformat	= V4L2_PIX_FMT_RGB565,
+	},{
+		/* Note:  V4L2 defines RGB565X as:
+		 *
+		 *	Byte 0			  Byte 1
+		 *	b4 b3 b2 b1 b0 g5 g4 g3	  g2 g1 g0 r4 r3 r2 r1 r0
+		 *
+		 * We interpret RGB565X as:
+		 *
+		 *	Byte 0			  Byte 1
+		 *	r4 r3 r2 r1 r0 g5 g4 g3	  g2 g1 g0 b4 b3 b2 b1 b0
+		 */
+		.description	= "RGB565, be",
+		.pixelformat	= V4L2_PIX_FMT_RGB565X,
+	},
+	{
+		.description	= "YUYV (YUV 4:2:2), packed",
+		.pixelformat	= V4L2_PIX_FMT_YUYV,
+	},{
+		.description	= "UYVY, packed",
+		.pixelformat	= V4L2_PIX_FMT_UYVY,
+	},
+	{
+		/* Note:  V4L2 defines RGB555 as:
+		 *
+		 *	Byte 0			  Byte 1
+		 *	g2 g1 g0 r4 r3 r2 r1 r0	  x  b4 b3 b2 b1 b0 g4 g3
+		 *
+		 * We interpret RGB555 as:
+		 *
+		 *	Byte 0			  Byte 1
+		 *	g2 g1 g0 b4 b3 b2 b1 b0	  x  r4 r3 r2 r1 r0 g4 g3
+		 */
+		.description	= "RGB555, le",
+		.pixelformat	= V4L2_PIX_FMT_RGB555,
+	},{
+		/* Note:  V4L2 defines RGB555X as:
+		 *
+		 *	Byte 0			  Byte 1
+		 *	x  b4 b3 b2 b1 b0 g4 g3	  g2 g1 g0 r4 r3 r2 r1 r0
+		 *
+		 * We interpret RGB555X as:
+		 *
+		 *	Byte 0			  Byte 1
+		 *	x  r4 r3 r2 r1 r0 g4 g3	  g2 g1 g0 b4 b3 b2 b1 b0
+		 */
+		.description	= "RGB555, be",
+		.pixelformat	= V4L2_PIX_FMT_RGB555X,
+	}
+};
+
+#define NUM_CAPTURE_FORMATS (sizeof(ov6650_formats)/sizeof(ov6650_formats[0]))
+#define NUM_OVERLAY_FORMATS 2
+
+/* register initialization tables for OV9640 */
+
+#define OV6650_REG_TERM 0xFF	/* terminating list entry for reg */
+#define OV6650_VAL_TERM 0xFF	/* terminating list entry for val */
+
+/* Updated to new values for V2 */
+static struct ov6650_reg init_regtbl_6650[] = {
+	{ OV6650_COMA, 0x80}, // reset
+	{ OV6650_BLUE, 0xC0},
+	{ OV6650_RED, 0x98},
+	{ OV6650_SAT, 0x00},//0ld Value{ 0x03, 0x50} //Old Value{ 0x03, 0x48},
+	{ OV6650_HUE, 0x32}, //New Register
+	{ OV6650_BRT, 0x96}, //Old Value{ 0x06, 0x70},
+	{ OV6650_CLKRC, 0xC1},
+	{ OV6650_COMA, 0x21},
+	{ OV6650_COMB, 0x5F},
+	{ OV6650_COMC, 0xE3}, //Old Value{ 0x14, 0xc3},
+	{ OV6650_COMD, 0x42}, //Old Value{ 0x15, 0x00},
+	{ OV6650_COML, 0x82},
+	{ OV6650_AEW, 0x91}, //Old Value{ 0x24, 0x80},
+	{ OV6650_AEB, 0x81}, //Old Value{ 0x25, 0x70},
+	{ 0x26, 0x01},
+	{ 0x27, 0x5C},
+	{ 0x29, 0x80},
+	{ 0x22, 0x80},
+	{ 0x23, 0x80},
+	{ 0x28, 0x18},
+	{ 0x2C, 0x09},
+	{ 0x2D, 0x08},
+	{ 0x34, 0xE4},
+	{ 0x30, 0x40},
+	{ 0x32, 0x00},
+	{ 0x33, 0x00},
+	{ 0x60, 0xC0}, //Old Value{ 0x60, 0xC1},
+	{ 0x61, 0x60},
+	{ 0x62, 0x88},
+	{ 0x63, 0x92},
+	{ 0x68, 0x04},
+	{ 0x6C, 0x11},
+	{ 0x6D, 0x01},
+	{ 0x6E, 0x06},
+	{ OV6650_REG_TERM, OV6650_VAL_TERM }
+};
+
+
+
+#define DEF_GAIN          0
+#define DEF_AUTOGAIN      1
+#define DEF_EXPOSURE    0x4d
+#define DEF_AEC           1
+#define DEF_FREEZE_AGCAEC 0
+#define DEF_BLUE        153
+#define DEF_RED         (255 - DEF_BLUE)
+#define DEF_AWB           1
+#define DEF_HFLIP         0
+#define DEF_VFLIP         0
+
+/* Our own specific controls */
+#define V4L2_CID_FREEZE_AGCAEC V4L2_CID_PRIVATE_BASE+0
+#define V4L2_CID_AUTOEXPOSURE V4L2_CID_PRIVATE_BASE+1
+#define V4L2_CID_LAST_PRIV  V4L2_CID_AUTOEXPOSURE
+
+/*  Video controls  */
+static struct vcontrol {
+        struct v4l2_queryctrl qc;
+        int current_value;
+        u8 reg;
+        u8 mask;
+        u8 start_bit;
+} control[] = {
+        { { V4L2_CID_GAIN, V4L2_CTRL_TYPE_INTEGER, "Gain", 0, 63, 1,
+            DEF_GAIN },
+          0, OV6650_GAIN, 0x3f, 0 },
+	/*
+        { { V4L2_CID_AUTOGAIN, V4L2_CTRL_TYPE_BOOLEAN, "Auto Gain", 0, 1, 0,
+            DEF_AUTOGAIN },
+          0, OV9640_COM8, 0x04, 2 },
+	  */
+        { { V4L2_CID_EXPOSURE, V4L2_CTRL_TYPE_INTEGER, "Exposure", 0, 255, 1,
+            DEF_EXPOSURE },
+          0, OV6650_AECH, 0xff, 0 },
+	/*
+        { { V4L2_CID_AUTOEXPOSURE, V4L2_CTRL_TYPE_BOOLEAN, "Auto Exposure", 0, 1, 0,
+            DEF_AEC },
+          0, OV9640_COM8, 0x01, 0 },
+        { { V4L2_CID_FREEZE_AGCAEC, V4L2_CTRL_TYPE_BOOLEAN, "Freeze AGC/AEC", 0,1,0,
+            DEF_FREEZE_AGCAEC },
+          0, OV9640_COM9, 0x01, 0 },
+        { { V4L2_CID_RED_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Red Balance", 0, 255, 1,
+            DEF_RED },
+          0, OV9640_RED, 0xff, 0 },
+        { { V4L2_CID_BLUE_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Blue Balance", 0, 255, 1,
+            DEF_BLUE },
+          0, OV9640_BLUE, 0xff, 0 },
+        { { V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CTRL_TYPE_BOOLEAN, "Auto White Balance", 0,1,0,
+            DEF_AWB },
+          0, OV9640_COM8, 0x02, 1 },
+	  */
+        { { V4L2_CID_HFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Mirror Image", 0, 1, 0,
+            DEF_HFLIP },
+          0, OV6650_COMB, 0x20, 5 },
+        { { V4L2_CID_VFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Vertical Flip", 0, 1, 0,
+            DEF_VFLIP },
+          0, OV6650_COMB, 0x80, 7 },
+};
+
+#define NUM_CONTROLS (sizeof(control)/sizeof(control[0]))
+
+
+/*
+ * returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int
+ov6650_read_reg(struct i2c_client *client, u8 reg, u8 *val)
+{
+	int err;
+	struct i2c_msg msg[1];
+	unsigned char data[1];
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg->addr = client->addr;
+	msg->flags = 0;
+	msg->len = 1;
+	msg->buf = data;
+	*data = reg;
+	err = i2c_transfer(client->adapter, msg, 1);
+	if (err >= 0) {
+		msg->flags = I2C_M_RD;
+		err = i2c_transfer(client->adapter, msg, 1);
+	}
+	if (err >= 0) {
+		*val = *data;
+		return 0;
+	}
+	return err;
+}
+
+/* Write a value to a register in an OV6650 sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int
+ov6650_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+	int err;
+	struct i2c_msg msg[1];
+	unsigned char data[2];
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg->addr = client->addr;
+	msg->flags = 0;
+	msg->len = 2;
+	msg->buf = data;
+	data[0] = reg;
+	data[1] = val;
+	err = i2c_transfer(client->adapter, msg, 1);
+	if (err >= 0)
+		return 0;
+	return err;
+}
+
+static int
+ov6650_write_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+	u8 oldval, newval;
+	int rc;
+
+	if (mask == 0xff) {
+		newval = *val;
+	} else {
+		/* need to do read - modify - write */
+		if ((rc = ov6650_read_reg(client, reg, &oldval)))
+			return rc;
+		oldval &= (~mask);              /* Clear the masked bits */
+		*val &= mask;                  /* Enforce mask on value */
+		newval = oldval | *val;        /* Set the desired bits */
+	}
+
+	/* write the new value to the register */
+	if ((rc = ov6650_write_reg(client, reg, newval)))
+		return rc;
+
+	if ((rc = ov6650_read_reg(client, reg, &newval)))
+		return rc;
+
+	*val = newval & mask;
+	return 0;
+}
+
+static int
+ov6650_read_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+	int rc;
+
+	if ((rc = ov6650_read_reg(client, reg, val)))
+		return rc;
+	(*val) &= mask;
+
+	return 0;
+}
+
+/* Initialize a list of OV6650 registers.
+ * The list of registers is terminated by the pair of values
+ * { OV6650_REG_TERM, OV6650_VAL_TERM }.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int
+ov6650_write_regs(struct i2c_client *client, const struct ov6650_reg reglist[])
+{
+	int err;
+	const struct ov6650_reg *next = reglist;
+
+	while (!((next->reg == OV6650_REG_TERM)
+		&& (next->val == OV6650_VAL_TERM)))
+	{
+		err = ov6650_write_reg(client, next->reg, next->val);
+		udelay(100);
+		if (err)
+			return err;
+		next++;
+	}
+	return 0;
+}
+
+/* Returns the index of the requested ID from the control structure array */
+static int
+find_vctrl(int id)
+{
+	int i;
+
+	if (id < V4L2_CID_BASE)
+		return -EDOM;
+
+	for (i = NUM_CONTROLS - 1; i >= 0; i--)
+		if (control[i].qc.id == id)
+			break;
+	if (i < 0)
+		i = -EINVAL;
+	return i;
+}
+
+/* Calculate the internal clock divisor (value of the CLKRC register) of the
+ * OV6650 given the image size, the frequency (in Hz) of its XCLK input and a
+ * desired frame period (in seconds).  The frame period 'fper' is expressed as
+ * a fraction.  The frame period is an input/output parameter.
+ * Returns the value of the OV6650 CLKRC register that will yield the frame
+ * period returned in 'fper' at the specified xclk frequency.  The
+ * returned period will be as close to the requested period as possible.
+ */
+static unsigned char
+ov6650_clkrc(enum image_size isize, unsigned long xclk, struct v4l2_fract *fper)
+{
+	unsigned long fpm, fpm_max;	/* frames per minute */
+	unsigned long divisor;
+	const unsigned long divisor_max = 64;
+	const static unsigned long clks_per_frame[] =
+		{ 200000, 200000, 200000, 200000, 400000, 800000, 3200000 };
+	unsigned char clkrc = 0;
+
+	printk(KERN_DEBUG "ov6650_clkrc(isize=%d xclk=%lu fper=%d/%d)\r\n", isize, xclk, fper->numerator, fper->denominator);
+	if (fper->numerator > 0)
+		fpm = (fper->denominator*60)/fper->numerator;
+	else
+		fpm = 0xffffffff;
+	fpm_max = (xclk*60)/clks_per_frame[isize];
+	if (fpm_max == 0)
+		fpm_max = 1;
+	if (fpm > fpm_max)
+		fpm = fpm_max;
+	if (fpm == 0)
+		fpm = 1;
+	divisor = fpm_max/fpm;
+	if (divisor > divisor_max)
+		divisor = divisor_max;
+	fper->numerator = divisor*60;
+	fper->denominator = fpm_max;
+
+	/* try to reduce the fraction */
+	while (!(fper->denominator % 5) && !(fper->numerator % 5)) {
+		fper->numerator /= 5;
+		fper->denominator /= 5;
+	}
+	while (!(fper->denominator % 3) && !(fper->numerator % 3)) {
+		fper->numerator /= 3;
+		fper->denominator /= 3;
+	}
+	while (!(fper->denominator % 2) && !(fper->numerator % 2)) {
+		fper->numerator /= 2;
+		fper->denominator /= 2;
+	}
+	if (fper->numerator < fper->denominator) {
+		if (!(fper->denominator % fper->numerator)) {
+			fper->denominator /= fper->numerator;
+			fper->numerator = 1;
+		}
+	}
+	else {
+		if (!(fper->numerator % fper->denominator)) {
+			fper->numerator /= fper->denominator;
+			fper->denominator = 1;
+		}
+	}
+
+	clkrc = divisor - 1;
+	clkrc &= 0x3f;
+	switch (xclk) {
+		case 8000000:
+			clkrc |= 0x00;
+			break;
+		case 12000000:
+			clkrc |= 0x40;
+			break;
+		case 16000000:
+			clkrc |= 0x80;
+			break;
+		case 24000000:
+			clkrc |= 0xC0;
+			break;
+	}
+	/*
+	 * TODO - fix this. For now, just return a known, working  value
+	 * Getting the value wrong seems to affect the AGC
+	 */
+	clkrc = 0xc1;
+	printk(KERN_DEBUG "ov6650_clkrc(xclk=%ld fper=%d/%d) divisor=%ld clkrc=0x%x\r\n", xclk, fper->numerator, fper->denominator, divisor, clkrc);
+	return clkrc;
+}
+
+/* Configure the OV6650 for a specified image size, pixel format, and frame
+ * period.  xclk is the frequency (in Hz) of the xclk input to the OV9640.
+ * fper is the frame period (in seconds) expressed as a fraction.
+ * Returns zero if successful, or non-zero otherwise.
+ * The actual frame period is returned in fper.
+ */
+static int
+ov6650_configure(struct i2c_client *client,
+	enum image_size isize,
+	enum pixel_format pfmt,
+	unsigned long xclk,
+	struct v4l2_fract *fper)
+{
+	int err;
+	u8 format_val = 0x00; // CIF 0x20; // QCIF
+	u8 format_mask = 0x20;
+	unsigned char clkrc;
+
+	printk(KERN_DEBUG "ov6650_configure(isize=%d pfmt=%d xclk=%lu)\r\n", isize, pfmt, xclk);
+
+	/* common register initialization */
+	err = ov6650_write_regs(client, init_regtbl_6650);
+	if (err)
+		return err;
+
+	/* configure image size */
+	if (isize == QCIF) format_val = 0x20;
+	else format_val = 0x00;
+	err = ov6650_write_reg_mask(client, 0x12, &format_val, format_mask);
+	if (err)
+		return err;
+
+	// TODO - set pixel format
+	/* configure frame rate */
+	clkrc = ov6650_clkrc(isize, xclk, fper);
+	err = ov6650_write_reg(client, OV6650_CLKRC, clkrc);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/* Detect if an OV6650 is present
+ * A device is considered to be detected if the manufacturer ID (MIDH and MIDL)
+ * and the product ID (PIDH and PIDL) registers match the expected values.
+ * Here are the version numbers we know about:
+ *	0x48 --> OV9640 Revision 1 or OV9640 Revision 2
+ *	0x49 --> OV9640 Revision 3
+ * Returns a negative error number if no device is detected, or 0
+ * if a device is detected.
+ */
+static int
+ov6650_detect(struct i2c_client *client)
+{
+	u8 midh, midl, pidh, pidl;
+
+	if (!client)
+		return -ENODEV;
+
+	if (ov6650_read_reg(client, OV6650_MIDH, &midh))
+		return -ENODEV;
+	if (ov6650_read_reg(client, OV6650_MIDL, &midl))
+		return -ENODEV;
+	if (ov6650_read_reg(client, OV6650_PIDH, &pidh))
+		return -ENODEV;
+	if (ov6650_read_reg(client, OV6650_PIDL, &pidl))
+		return -ENODEV;
+
+	if ((midh != OV6650_MIDH_MAGIC)
+		|| (midl != OV6650_MIDL_MAGIC)
+		|| (pidh != OV6650_PIDH_MAGIC)
+		|| (pidl != OV6650_PIDL_MAGIC))
+	{
+		/* We didn't read the values we expected, so
+		 * this must not be an OV6650.
+		 */
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static struct i2c_driver ov6650sensor_i2c_driver;
+
+/* This function registers an I2C client via i2c_attach_client() for an OV6650
+ * sensor device.  If 'probe' is non-zero, then the I2C client is only
+ * registered if the device can be detected.  If 'probe' is zero, then no
+ * device detection is attempted and the I2C client is always registered.
+ * Returns zero if an I2C client is successfully registered, or non-zero
+ * otherwise.
+ */
+static int
+ov6650_i2c_attach_client(struct i2c_adapter *adap, int addr, int probe)
+{
+	struct ov6650_sensor *sensor = &ov6650;
+	struct i2c_client *client = &sensor->client;
+	int err;
+
+	if (client->adapter)
+		return -EBUSY;	/* our client is already attached */
+
+	client->addr = addr;
+	client->driver = &ov6650sensor_i2c_driver;
+	client->adapter = adap;
+
+	err = i2c_attach_client(client);
+	if (err) {
+		client->adapter = NULL;
+		return err;
+	}
+
+	if (probe) {
+		err = ov6650_detect(client);
+		if (err < 0) {
+			i2c_detach_client(client);
+			client->adapter = NULL;
+			return err;
+		}
+	}
+	return 0;
+}
+
+/* This function is called by i2c_del_adapter() and i2c_del_driver()
+ * if the adapter or driver with which this I2C client is associated is
+ * removed.  This function unregisters the client via i2c_detach_client().
+ * Returns zero if the client is successfully detached, or non-zero
+ * otherwise.
+ */
+static int
+ov6650_i2c_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if (!client->adapter)
+		return -ENODEV;	/* our client isn't attached */
+
+	err = i2c_detach_client(client);
+	client->adapter = NULL;
+
+	return err;
+}
+
+/* This function will be called for each registered I2C bus adapter when our
+ * I2C driver is registered via i2c_add_driver().  It will also be called
+ * whenever a new I2C adapter is registered after our I2C driver is registered.
+ * This function probes the specified I2C bus adapter to determine if an
+ * OV6650 sensor device is present.  If a device is detected, an I2C client
+ * is registered for it via ov6650_i2c_attach_client().  Note that we can't use
+ * the standard i2c_probe() function to look for the sensor because the OMAP
+ * I2C controller doesn't support probing.
+ * Returns zero if an OV6650 device is detected and an I2C client successfully
+ * registered for it, or non-zero otherwise.
+ */
+static int
+ov6650_i2c_probe_adapter(struct i2c_adapter *adap)
+{
+	return ov6650_i2c_attach_client(adap, OV6650_I2C_ADDR, 1);
+}
+
+/* Find the best match for a requested image capture size.  The best match
+ * is chosen as the nearest match that has the same number or fewer pixels
+ * as the requested size, or the smallest image size if the requested size
+ * has fewer pixels than the smallest image.
+ */
+static enum image_size
+ov6650_find_size(unsigned int width, unsigned int height)
+{
+	unsigned long pixels = width*height;
+
+	if (ov6650_sizes[CIF].height*
+		ov6650_sizes[CIF].width > pixels)
+	{
+		return QCIF;
+	}
+	return CIF;
+}
+
+/* following are sensor interface functions implemented by
+ * OV9640 sensor driver.
+ */
+static int
+ov6650sensor_query_control(struct v4l2_queryctrl *qc, void *priv)
+{
+	int i;
+
+	i = find_vctrl (qc->id);
+	if (i == -EINVAL) {
+		qc->flags = V4L2_CTRL_FLAG_DISABLED;
+		return 0;
+	}
+	if (i < 0)
+		return -EINVAL;
+
+	*qc = control[i].qc;
+	return 0;
+}
+
+static int
+ov6650sensor_get_control(struct v4l2_control *vc, void *priv)
+{
+	struct ov6650_sensor *sensor = (struct ov6650_sensor *) priv;
+	struct i2c_client *client = &sensor->client;
+	int i, val;
+	struct vcontrol * lvc;
+
+	i = find_vctrl(vc->id);
+	if (i < 0)
+		return -EINVAL;
+
+	lvc = &control[i];
+	if (ov6650_read_reg_mask(client, lvc->reg, (u8 *)&val, lvc->mask))
+		return -EIO;
+
+	val = val >> lvc->start_bit;
+	if (val >= 0) {
+		vc->value = lvc->current_value = val;
+		return 0;
+	} else
+		return val;
+}
+
+static int
+ov6650sensor_set_control(struct v4l2_control *vc, void *priv)
+{
+	struct ov6650_sensor *sensor = (struct ov6650_sensor *) priv;
+	struct i2c_client *client = &sensor->client;
+	struct vcontrol *lvc;
+	int val = vc->value;
+	int i;
+
+	i = find_vctrl(vc->id);
+	if (i < 0)
+		return -EINVAL;
+
+	lvc = &control[i];
+	val = val << lvc->start_bit;
+	if (ov6650_write_reg_mask(client, lvc->reg, (u8 *)&val, (u8)lvc->mask))
+		return -EIO;
+
+	val = val>> lvc->start_bit;
+	if (val >= 0) {
+		lvc->current_value = val;
+		return 0;
+	} else
+		return val;
+}
+
+/* Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
+ */
+static int
+ov6650sensor_enum_pixformat(struct v4l2_fmtdesc *fmt, void *priv)
+{
+	int index = fmt->index;
+	enum v4l2_buf_type type = fmt->type;
+
+	memset(fmt, 0, sizeof(*fmt));
+	fmt->index = index;
+	fmt->type = type;
+
+	switch (fmt->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (index >= NUM_CAPTURE_FORMATS)
+			return -EINVAL;
+		break;
+
+		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+		if (index >= NUM_OVERLAY_FORMATS)
+			return -EINVAL;
+		break;
+
+		default:
+			return -EINVAL;
+	}
+
+	fmt->flags = ov6650_formats[index].flags;
+	strlcpy(fmt->description, ov6650_formats[index].description, sizeof(fmt->description));
+	fmt->pixelformat = ov6650_formats[index].pixelformat;
+
+	return 0;
+}
+
+/* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.  This
+ * ioctl is used to negotiate the image capture size and pixel format
+ * without actually making it take effect.
+ */
+static int
+ov6650sensor_try_format(struct v4l2_pix_format *pix, void *priv)
+{
+	enum image_size isize;
+	int ifmt;
+
+	isize = ov6650_find_size(pix->width, pix->height);
+	pix->width = ov6650_sizes[isize].width;
+	pix->height = ov6650_sizes[isize].height;
+	for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
+		if (pix->pixelformat == ov6650_formats[ifmt].pixelformat)
+			break;
+	}
+	if (ifmt == NUM_CAPTURE_FORMATS)
+		ifmt = 0;
+	pix->pixelformat = ov6650_formats[ifmt].pixelformat;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = pix->width*2;
+	pix->sizeimage = pix->bytesperline*pix->height;
+	printk(KERN_DEBUG "6650sensor_try_format sizeimage=%d\n", pix->sizeimage);
+	pix->priv = 0;
+	switch (pix->pixelformat) {
+		case V4L2_PIX_FMT_YUYV:
+		case V4L2_PIX_FMT_UYVY:
+		default:
+			pix->colorspace = V4L2_COLORSPACE_JPEG;
+			break;
+		case V4L2_PIX_FMT_RGB565:
+		case V4L2_PIX_FMT_RGB565X:
+		case V4L2_PIX_FMT_RGB555:
+		case V4L2_PIX_FMT_RGB555X:
+			pix->colorspace = V4L2_COLORSPACE_SRGB;
+			break;
+	}
+	return 0;
+}
+
+/* Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate the required xclk frequency
+ */
+static unsigned long
+ov6650sensor_calc_xclk(struct v4l2_pix_format *pix,
+			struct v4l2_fract *timeperframe, void *priv)
+{
+	unsigned long tgt_xclk;			/* target xclk */
+
+	printk(KERN_DEBUG "ov6650sensor_calc_xclk\r\n");
+	/*
+	 * For now, just return a fixed value
+	 * Typical frequency for the 6650 is 24MHz, min is 8MHz and max is 27MHz
+	 */
+	tgt_xclk = 24000000;
+	printk(KERN_DEBUG "ov6650sensor_calc_xclk returning %ld\r\n", tgt_xclk);
+	return tgt_xclk;
+}
+
+/* Given a capture format in pix, the frame period in timeperframe, and
+ * the xclk frequency, set the capture format of the OV9640 sensor.
+ * The actual frame period will be returned in timeperframe.
+ */
+static int
+ov6650sensor_configure(struct v4l2_pix_format *pix, unsigned long xclk,
+			struct v4l2_fract *timeperframe, void *priv)
+{
+	struct ov6650_sensor *sensor = (struct ov6650_sensor *) priv;
+  	enum pixel_format pfmt = YUV;
+
+	switch (pix->pixelformat) {
+		case V4L2_PIX_FMT_RGB565:
+		case V4L2_PIX_FMT_RGB565X:
+			pfmt = RGB565;
+			break;
+		case V4L2_PIX_FMT_RGB555:
+		case V4L2_PIX_FMT_RGB555X:
+			pfmt = RGB555;
+			break;
+		case V4L2_PIX_FMT_YUYV:
+		case V4L2_PIX_FMT_UYVY:
+		default:
+			pfmt = YUV;
+ 	}
+
+	return ov6650_configure(&sensor->client,
+				ov6650_find_size(pix->width, pix->height),
+				pfmt, xclk, timeperframe);
+}
+
+/* Prepare for the driver to exit.
+ * Balances ov6650sensor_init().
+ * This function must de-initialize the sensor and its associated data
+ * structures.
+ */
+static int
+ov6650sensor_cleanup(void *priv)
+{
+	struct ov6650_sensor *sensor = (struct ov6650_sensor *) priv;
+
+	if (sensor) {
+		i2c_del_driver(&ov6650sensor_i2c_driver);
+ 	}
+	return 0;
+}
+
+static struct i2c_driver ov6650sensor_i2c_driver = {
+	.driver = {
+		.name		= "ov6650",
+	},
+	.id		= I2C_DRIVERID_MISC, /*FIXME:accroding to i2c-ids.h */
+	.attach_adapter	= ov6650_i2c_probe_adapter,
+	.detach_client	= ov6650_i2c_detach_client,
+};
+
+/* Initialize the OV6650 sensor.
+ * This routine allocates and initializes the data structure for the sensor,
+ * registers the I2C driver, and sets a default image
+ * capture format in pix.  The capture format is not actually programmed
+ * into the OV6650 sensor by this routine.
+ * This function must return a non-NULL value to indicate that
+ * initialization is successful.
+ */
+static void *
+ov6650sensor_init(struct v4l2_pix_format *pix)
+{
+	struct ov6650_sensor *sensor = &ov6650;
+ 	int err;
+
+	memset(sensor, 0, sizeof(*sensor));
+
+	err = i2c_add_driver(&ov6650sensor_i2c_driver);
+	if (err) {
+		printk(KERN_ERR "Failed to register OV6650 I2C client.\n");
+		return NULL;
+	}
+	if (!sensor->client.adapter) {
+		printk(KERN_WARNING
+			"Failed to detect OV6650 sensor chip.\n");
+		return NULL;
+	}
+	else {
+		printk(KERN_INFO
+			"OV6650 sensor chip\n");
+	}
+
+	/* set initial image size and pixel format */
+	pix->width = ov6650_sizes[CIF].width;
+	pix->height = ov6650_sizes[CIF].height;
+	pix->pixelformat = V4L2_PIX_FMT_YUYV;
+	ov6650sensor_try_format(pix, NULL);
+
+	return (void *)sensor;
+}
+
+struct omap_camera_sensor camera_sensor_if = {
+	.version	= 0x01,
+	.name		= "OV6650",
+	.init		= ov6650sensor_init,
+	.cleanup	= ov6650sensor_cleanup,
+	.enum_pixformat = ov6650sensor_enum_pixformat,
+	.try_format	= ov6650sensor_try_format,
+	.calc_xclk	= ov6650sensor_calc_xclk,
+	.configure	= ov6650sensor_configure,
+	.query_control	= ov6650sensor_query_control,
+	.get_control	= ov6650sensor_get_control,
+	.set_control	= ov6650sensor_set_control,
+};
+
+
+EXPORT_SYMBOL(camera_sensor_if);
+#endif	/* ifdef CAMERA_OV6650 */
Files linux-2.6.19-clean/scripts/kconfig/mconf and linux-2.6.19/scripts/kconfig/mconf differ

