All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/5] OV3640: Add driver
@ 2009-03-03 20:44 Aguirre Rodriguez, Sergio Alberto
  2009-03-05  0:23 ` Alexey Klimov
  2009-03-05  1:42 ` Trent Piepho
  0 siblings, 2 replies; 8+ messages in thread
From: Aguirre Rodriguez, Sergio Alberto @ 2009-03-03 20:44 UTC (permalink / raw)
  To: linux-media, linux-omap
  Cc: Sakari Ailus, Tuukka.O Toivonen, Hiroshi DOYU,
	DongSoo(Nathaniel) Kim, MiaoStanley, Nagalla, Hari, Hiremath,
	Vaibhav, Lakhani, Amish, Menon, Nishanth

This driver has been currently being tested with:
 - OMAP3430SDP platform, working in Parallel and CSI2 modes.
 - OMAPZOOM (LDP) platform, working in CSI2 mode.

Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
---
 drivers/media/video/Kconfig       |   15 +
 drivers/media/video/Makefile      |    1 +
 drivers/media/video/ov3640.c      | 2202 +++++++++++++++++++++++++++++++++++++
 drivers/media/video/ov3640_regs.h |  600 ++++++++++
 include/media/ov3640.h            |   31 +
 5 files changed, 2849 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/ov3640.c
 create mode 100644 drivers/media/video/ov3640_regs.h
 create mode 100644 include/media/ov3640.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 225d9cf..e99c93f 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -321,6 +321,21 @@ config VIDEO_DW9710
          DW9710 coil.  It is currently working with the TI OMAP3
          camera controller and micron MT9P012 sensor.

+config VIDEO_OV3640
+       tristate "OmniVision ov3640 smart sensor driver (3MP)"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the OmniVision
+         OV3640 camera.  It is currently working with the TI OMAP3
+          camera controller.
+
+config VIDEO_OV3640_CSI2
+       bool "CSI2 bus support for OmniVision ov3640 sensor"
+       depends on I2C && VIDEO_V4L2 && VIDEO_OV3640
+       ---help---
+         This enables the use of the CSI2 serial bus for the ov3640
+         camera.
+
 config VIDEO_SAA7110
        tristate "Philips SAA7110 video decoder"
        depends on VIDEO_V4L1 && I2C
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 52a34d9..33b3976 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -113,6 +113,7 @@ obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 obj-$(CONFIG_VIDEO_MT9P012)     += mt9p012.o
 obj-$(CONFIG_VIDEO_DW9710)     += dw9710.o
+obj-$(CONFIG_VIDEO_OV3640)     += ov3640.o

 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
diff --git a/drivers/media/video/ov3640.c b/drivers/media/video/ov3640.c
new file mode 100644
index 0000000..9f5cb13
--- /dev/null
+++ b/drivers/media/video/ov3640.c
@@ -0,0 +1,2202 @@
+/*
+ * drivers/media/video/ov3640.c
+ *
+ * ov3640 sensor driver
+ *
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * Leverage ov3640.c
+ *
+ * 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/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-int-device.h>
+#include <media/ov3640.h>
+#include "ov3640_regs.h"
+#include "omap34xxcam.h"
+#include "isp/ispcsi2.h"
+
+#define OV3640_DRIVER_NAME  "ov3640"
+#define MOD_NAME "OV3640: "
+
+#define I2C_M_WR 0
+
+/* Register initialization tables for ov3640 */
+/* Terminating list entry for reg */
+#define OV3640_REG_TERM                0xFFFF
+/* Terminating list entry for val */
+#define OV3640_VAL_TERM                0xFF
+
+#define OV3640_USE_XCLKA       0
+#define OV3640_USE_XCLKB       1
+
+#define OV3640_CSI2_VIRTUAL_ID 0x1
+
+/* FPS Capabilities */
+#define OV3640_MIN_FPS                 5
+#define OV3640_DEF_FPS                 15
+#define OV3640_MAX_FPS                 30
+
+#define OV3640_MIN_BRIGHT              0
+#define OV3640_MAX_BRIGHT              6
+#define OV3640_DEF_BRIGHT              0
+#define OV3640_BRIGHT_STEP             1
+
+#define OV3640_DEF_CONTRAST            0
+#define OV3640_MIN_CONTRAST            0
+#define OV3640_MAX_CONTRAST            6
+#define OV3640_CONTRAST_STEP           1
+
+#define OV3640_DEF_COLOR               0
+#define OV3640_MIN_COLOR               0
+#define OV3640_MAX_COLOR               2
+#define OV3640_COLOR_STEP              1
+
+#define SENSOR_DETECTED                1
+#define SENSOR_NOT_DETECTED    0
+
+/* NOTE: Set this as 0 for enabling SoC mode */
+#define OV3640_RAW_MODE        1
+
+/* XCLK Frequency in Hz*/
+#define OV3640_XCLK_MIN                24000000
+#define OV3640_XCLK_MAX                24000000
+
+
+/* High byte of product ID */
+#define OV3640_PIDH_MAGIC      0x36
+/* Low byte of product ID  */
+#define OV3640_PIDL_MAGIC1     0x41
+#define OV3640_PIDL_MAGIC2     0x4C
+
+/* define a structure for ov3640 register initialization values */
+struct ov3640_reg {
+       unsigned int reg;
+       unsigned char val;
+};
+
+enum image_size_ov {
+       XGA,
+       QXGA
+};
+enum pixel_format_ov {
+       YUV,
+       RGB565,
+       RGB555,
+       RAW10
+};
+
+#define OV_NUM_IMAGE_SIZES             2
+#define OV_NUM_PIXEL_FORMATS           4
+#define OV_NUM_FPS                     3
+
+struct capture_size_ov {
+       unsigned long width;
+       unsigned long height;
+};
+
+const static struct ov3640_reg ov3640_common[2][100] = {
+       /* XGA_Default settings */
+       {
+               {OV3640_AEC_H, 0x03},
+               {OV3640_AEC_L, 0x0F},
+               {OV3640_AGC_L, 0x07},
+               {0x304d, 0x45},
+               {0x30aa, 0x45},
+               {OV3640_IO_CTRL1, 0xff},
+               {OV3640_IO_CTRL2, 0x10},
+               {OV3640_WPT_HISH, 0x38},
+               {OV3640_BPT_HISL, 0x30},
+               {OV3640_VPT, 0x61},
+               {0x3082, 0x20},
+               {OV3640_AUTO_3, OV3640_AUTO_3_DUMMYFC_1FRAME |
+                                               OV3640_AUTO_3_AGCGAINCEIL_32X},
+               {OV3640_AUTO_1, OV3640_AUTO_1_FASTAEC |
+                                       OV3640_AUTO_1_AECBIGSTEPS |
+                                       OV3640_AUTO_1_BANDINGFILTEREN |
+                                       OV3640_AUTO_1_AUTOBANDINGFILTER |
+                                       OV3640_AUTO_1_EXTRBRIGHTEXPEN
+#if (OV3640_RAW_MODE == 0)
+                                       | OV3640_AUTO_1_AGCEN
+                                       | OV3640_AUTO_1_AECEN
+#endif
+                                       },
+               {OV3640_AHW_H, 0x08},
+               {OV3640_AHW_L, 0x18},
+               {OV3640_AVH_H, 0x06},
+               {OV3640_AVH_L, 0x0c},
+               {OV3640_WEIGHT0, 0x62},
+               {OV3640_WEIGHT1, 0x26},
+               {OV3640_WEIGHT2, 0xe6},
+               {OV3640_WEIGHT3, 0x6e},
+               {OV3640_WEIGHT4, 0xea},
+               {OV3640_WEIGHT5, 0xae},
+               {OV3640_WEIGHT6, 0xa6},
+               {OV3640_WEIGHT7, 0x6a},
+               {OV3640_SC_SYN_CTRL0, 0x02},
+               {OV3640_SC_SYN_CTRL1, 0xfd},
+               {OV3640_SC_SYN_CTRL2, 0x00},
+               {OV3640_SC_SYN_CTRL3, 0xff},
+               {OV3640_DSP_CTRL_0, 0x13},
+               {OV3640_DSP_CTRL_1, 0xde},
+               {OV3640_DSP_CTRL_2, 0xef},
+               {0x3316, 0xff},
+               {0x3317, 0x00},
+               {0x3312, 0x26},
+               {0x3314, 0x42},
+               {0x3313, 0x2b},
+               {0x3315, 0x42},
+               {0x3310, 0xd0},
+               {0x3311, 0xbd},
+               {0x330c, 0x18},
+               {0x330d, 0x18},
+               {0x330e, 0x56},
+               {0x330f, 0x5c},
+               {0x330b, 0x1c},
+               {0x3306, 0x5c},
+               {0x3307, 0x11},
+               {OV3640_R_A1, 0x52},
+               {OV3640_G_A1, 0x46},
+               {OV3640_B_A1, 0x38},
+               {OV3640_DSPC0, 0x20},
+               {OV3640_DSPC1, 0x17},
+               {OV3640_DSPC2, 0x04},
+               {OV3640_DSPC3, 0x08},
+               {0x3507, 0x06},
+               {0x350a, 0x4f},
+               {OV3640_SC_CTRL0, 0x02},
+               {OV3640_DSP_CTRL_1, 0xde},
+               {OV3640_DSP_CTRL_4, 0xfc},
+               {OV3640_SYS, OV3640_SYS_BASERES_XGA},
+               {OV3640_VS_L, 0x06 + 1},
+               {OV3640_VH_H, 0x03},
+               {OV3640_VH_L, 0x04},
+               {OV3640_VSYNCOPT, 0x24},
+               {OV3640_PCLK, OV3640_PCLK_DIVBY2},
+               {0x30d7, 0x90},
+               {OV3640_SIZE_IN_MISC, 0x34},
+               {OV3640_HSIZE_IN_L, 0x0c},
+               {OV3640_VSIZE_IN_L, 0x04},
+               {OV3640_SIZE_OUT_MISC, 0x34},
+               {OV3640_HSIZE_OUT_L, 0x08},
+               {OV3640_VSIZE_OUT_L, 0x04},
+               {OV3640_ISP_PAD_CTR2, 0x42},
+               {OV3640_ISP_XOUT_H, 0x04},
+               {OV3640_ISP_XOUT_L, 0x00},
+               {OV3640_ISP_YOUT_H, 0x03},
+               {OV3640_ISP_YOUT_L, 0x00},
+               {OV3640_TMC13, 0x04},
+               {OV3640_OUT_CTRL00, OV3640_OUT_CTRL00_VSYNCSEL2 |
+                                       OV3640_OUT_CTRL00_VSYNCGATE |
+                                       OV3640_OUT_CTRL00_VSYNCPOL_NEG},
+               {OV3640_MISC_CTRL, 0x00},
+               {OV3640_Y_EDGE_MT, 0x60},
+               {OV3640_BASE1, 0x03},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* QXGA Default settings */
+       {
+               {OV3640_AEC_H, 0x06},
+               {OV3640_AEC_L, 0x1F},
+               {OV3640_AGC_L, 0x12},
+               {0x304d, 0x45},
+               {0x30aa, 0x45},
+               {OV3640_IO_CTRL0, 0xff},
+               {OV3640_IO_CTRL1, 0xff},
+               {OV3640_IO_CTRL2, 0x10},
+               {0x30d7, 0x10},
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x60},
+               {OV3640_BPT_HISL, 0x58},
+               {OV3640_VPT, 0xa1},
+               {OV3640_TMC11, 0x02},
+               {0x3082, 0x20},
+               {OV3640_AHW_H, 0x08},
+               {OV3640_AHW_L, 0x18},
+               {OV3640_AVH_H, 0x06},
+               {OV3640_AVH_L, 0x0c},
+               {OV3640_WEIGHT0, 0x62},
+               {OV3640_WEIGHT1, 0x26},
+               {OV3640_WEIGHT2, 0xe6},
+               {OV3640_WEIGHT3, 0x6e},
+               {OV3640_WEIGHT4, 0xea},
+               {OV3640_WEIGHT5, 0xae},
+               {OV3640_WEIGHT6, 0xa6},
+               {OV3640_WEIGHT7, 0x6a},
+               {OV3640_AUTO_3, OV3640_AUTO_3_DUMMYFC_1FRAME |
+                                               OV3640_AUTO_3_AGCGAINCEIL_8X},
+               {OV3640_AUTO_1, OV3640_AUTO_1_FASTAEC |
+                                       OV3640_AUTO_1_AECBIGSTEPS |
+                                       OV3640_AUTO_1_BANDINGFILTEREN |
+                                       OV3640_AUTO_1_AUTOBANDINGFILTER |
+                                       OV3640_AUTO_1_EXTRBRIGHTEXPEN
+#if (OV3640_RAW_MODE == 0)
+                                       | OV3640_AUTO_1_AGCEN
+                                       | OV3640_AUTO_1_AECEN
+#endif
+                                       },
+               {OV3640_SC_SYN_CTRL0, 0x02},
+               {OV3640_SC_SYN_CTRL1, 0xfd},
+               {OV3640_SC_SYN_CTRL2, 0x00},
+               {OV3640_SC_SYN_CTRL3, 0xff},
+               {OV3640_AWB_CTRL_3, 0xa5},
+               {0x3316, 0xff},
+               {0x3317, 0x00},
+               {OV3640_TMC11, 0x02},
+               {0x3082, 0x20},
+               {OV3640_DSP_CTRL_0, 0x13},
+               {OV3640_DSP_CTRL_1, 0xd6},
+               {OV3640_DSP_CTRL_2, 0xef},
+               {OV3640_DSPC0, 0x20},
+               {OV3640_DSPC1, 0x17},
+               {OV3640_DSPC2, 0x04},
+               {OV3640_DSPC3, 0x08},
+               {OV3640_HS_H, 0x01},
+               {OV3640_HS_L, 0x1d},
+               {OV3640_VS_H, 0x00},
+               {OV3640_VS_L, 0x0a + 1},
+               {OV3640_HW_H, 0x08},
+               {OV3640_HW_L, 0x18},
+               {OV3640_VH_H, 0x06},
+               {OV3640_VH_L, 0x0c},
+               {OV3640_SIZE_IN_MISC, 0x68},
+               {OV3640_HSIZE_IN_L, 0x18},
+               {OV3640_VSIZE_IN_L, 0x0c},
+               {OV3640_SIZE_OUT_MISC, 0x68},
+               {OV3640_HSIZE_OUT_L, 0x08},
+               {OV3640_VSIZE_OUT_L, 0x04},
+               {OV3640_ISP_PAD_CTR2, 0x42},
+               {OV3640_ISP_XOUT_H, 0x08},
+               {OV3640_ISP_XOUT_L, 0x00},
+               {OV3640_ISP_YOUT_H, 0x06},
+               {OV3640_ISP_YOUT_L, 0x00},
+               {0x3507, 0x06},
+               {0x350a, 0x4f},
+               {OV3640_OUT_CTRL00, 0xc4},
+               /* Light Mode - Auto */
+               {OV3640_MISC_CTRL, 0x00},
+               /* Sharpness - Level 5 */
+               {OV3640_Y_EDGE_MT, 0x45},
+               /* Sharpness - Auto */
+               {OV3640_Y_EDGE_MT, 0x60},
+               {OV3640_BASE1, 0x03},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+};
+
+const static struct ov3640_reg ov3640_common_csi2[] = {
+       /* NM OUT_CONTROL2 SOL/EOL off */
+       {OV3640_MIPI_CTRL02, 0x22},
+       /* NM OUT_CONTROL1E h_sel? */
+       {OV3640_OUT_CTRL1E, 0x00},
+       /* min_hs_zero: 6UI + 105ns */
+       {OV3640_MIPI_CTRL22, ((6 & 0x3F) << 2) | ((105 & 0x300) >> 8)},
+       {OV3640_MIPI_CTRL23, (105 & 0xFF)},
+       /* min_clk_zero: 240ns */
+       {OV3640_MIPI_CTRL26, ((0 & 0x3F) << 2) | ((240 & 0x300) >> 8)},
+       {OV3640_MIPI_CTRL27, (240 & 0xFF)},
+       /* min_clk_prepare: 38ns */
+       {OV3640_MIPI_CTRL28, ((0 & 0x3F) << 2) | ((38 & 0x300) >> 8)},
+       {OV3640_MIPI_CTRL29, (38 & 0xFF)},
+       /* max_clk_prepare: 95ns */
+       {OV3640_MIPI_CTRL2A, ((0 & 0x3F) << 2) | ((95 & 0x300) >> 8)},
+       {OV3640_MIPI_CTRL2B, (95 & 0xFF)},
+       /* min_clk_post: 52UI + 60ns */
+       {OV3640_MIPI_CTRL2C, ((52 & 0x3F) << 2) | ((60 & 0x300) >> 8)},
+       {OV3640_MIPI_CTRL2D, (60 & 0xFF)},
+       /* min_hs_prepare: 4UI + 40ns */
+       {OV3640_MIPI_CTRL32, ((4 & 0x3F) << 2) | ((40 & 0x300) >> 8)},
+       {OV3640_MIPI_CTRL33, (40 & 0xFF)},
+       /* ph_byte_order {DI,WC_h,WC_l} */
+       {OV3640_MIPI_CTRL03, 0x49 | OV3640_MIPI_CTRL03_ECC_PHBYTEORDER},
+       /* ph_byte_order2 ph={WC,DI} */
+       {OV3640_MIPI_CTRL4C, OV3640_MIPI_CTRL4C_ECC_PHBYTEORDER2},
+       {0x309e, 0x00},
+       {OV3640_REG_TERM, OV3640_VAL_TERM},
+};
+
+/* Array of image sizes supported by OV3640.  These must be ordered from
+ * smallest image size to largest.
+ */
+const static struct capture_size_ov ov3640_sizes[] = {
+       /* XGA */
+       { 1024, 768 },
+       /* QXGA */
+       { 2048, 1536 },
+};
+
+/**
+ * struct ov3640_sensor - main structure for storage of sensor information
+ * @pdata: access functions and data for platform level information
+ * @v4l2_int_device: V4L2 device structure structure
+ * @i2c_client: iic client device structure
+ * @pix: V4L2 pixel format information structure
+ * @timeperframe: time per frame expressed as V4L fraction
+ * @isize: base image size
+ * @ver: ov3640 chip version
+ * @width: configured width
+ * @height: configuredheight
+ * @vsize: vertical size for the image
+ * @hsize: horizontal size for the image
+ * @crop_rect: crop rectangle specifying the left,top and width and height
+ */
+struct ov3640_sensor {
+       const struct ov3640_platform_data *pdata;
+       struct v4l2_int_device *v4l2_int_device;
+       struct i2c_client *i2c_client;
+       struct v4l2_pix_format pix;
+       struct v4l2_fract timeperframe;
+       int isize;
+       int ver;
+       int fps;
+       unsigned long width;
+       unsigned long height;
+       unsigned long vsize;
+       unsigned long hsize;
+       struct v4l2_rect crop_rect;
+       int state;
+};
+
+static struct ov3640_sensor ov3640;
+static struct i2c_driver ov3640sensor_i2c_driver;
+static unsigned long xclk_current = OV3640_XCLK_MIN;
+
+/* List of image formats supported by OV3640 sensor */
+const static struct v4l2_fmtdesc ov3640_formats[] = {
+#if OV3640_RAW_MODE
+       {
+               .description    = "RAW10",
+               .pixelformat    = V4L2_PIX_FMT_SGRBG10,
+       },
+#else
+       {
+               /* 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,
+       },
+#endif
+};
+
+#define NUM_CAPTURE_FORMATS (sizeof(ov3640_formats) / sizeof(ov3640_formats[0]))
+
+/* register initialization tables for ov3640 */
+#define OV3640_REG_TERM 0xFFFF /* terminating list entry for reg */
+#define OV3640_VAL_TERM 0xFF   /* terminating list entry for val */
+
+const static struct ov3640_reg ov3640_out_xga[] = {
+       {OV3640_ISP_XOUT_H, 0x04},  /* ISP_XOUT */
+       {OV3640_ISP_XOUT_L, 0x00},  /* ISP_XOUT */
+       {OV3640_ISP_YOUT_H, 0x03},  /* ISP_YOUT */
+       {OV3640_ISP_YOUT_L, 0x00},  /* ISP_YOUT */
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+const static struct ov3640_reg ov3640_out_qxga[] = {
+       {OV3640_ISP_XOUT_H, 0x08},  /* ISP_XOUT */
+       {OV3640_ISP_XOUT_L, 0x00},  /* ISP_XOUT */
+       {OV3640_ISP_YOUT_H, 0x06},  /* ISP_YOUT */
+       {OV3640_ISP_YOUT_L, 0x00},  /* ISP_YOUT */
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+/* Brightness Settings - 7 levels */
+const static struct ov3640_reg brightness[7][5] = {
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_SGNSET, 0x09},
+               {OV3640_YBRIGHT, 0x30},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_SGNSET, 0x09},
+               {OV3640_YBRIGHT, 0x20},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_SGNSET, 0x09},
+               {OV3640_YBRIGHT, 0x10},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_SGNSET, 0x01},
+               {OV3640_YBRIGHT, 0x00},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_SGNSET, 0x01},
+               {OV3640_YBRIGHT, 0x10},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_SGNSET, 0x01},
+               {OV3640_YBRIGHT, 0x20},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_SGNSET, 0x01},
+               {OV3640_YBRIGHT, 0x30},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+};
+
+/* Contrast Settings - 7 levels */
+const static struct ov3640_reg contrast[7][5] = {
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_YOFFSET, 0x14},
+               {OV3640_YGAIN, 0x14},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_YOFFSET, 0x18},
+               {OV3640_YGAIN, 0x18},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_YOFFSET, 0x1c},
+               {OV3640_YGAIN, 0x1c},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_YOFFSET, 0x20},
+               {OV3640_YGAIN, 0x20},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_YOFFSET, 0x24},
+               {OV3640_YGAIN, 0x24},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_YOFFSET, 0x28},
+               {OV3640_YGAIN, 0x28},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x04},
+               {OV3640_YOFFSET, 0x2c},
+               {OV3640_YGAIN, 0x2c},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+};
+
+/* Color Settings - 3 colors */
+const static struct ov3640_reg colors[3][5] = {
+       {
+               {OV3640_SDE_CTRL, 0x00},
+               {OV3640_UREG, 0x80},
+               {OV3640_VREG, 0x80},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x18},
+               {OV3640_UREG, 0x40},
+               {OV3640_VREG, 0xa6},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       {
+               {OV3640_SDE_CTRL, 0x18},
+               {OV3640_UREG, 0x80},
+               {OV3640_VREG, 0x80},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+};
+
+/* Average Based Algorithm - Based on target Luminance */
+const static struct ov3640_reg exposure_avg[11][5] = {
+       /* -1.7EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x10},
+               {OV3640_BPT_HISL, 0x08},
+               {OV3640_VPT, 0x21},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* -1.3EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x18},
+               {OV3640_BPT_HISL, 0x10},
+               {OV3640_VPT, 0x31},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* -1.0EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x20},
+               {OV3640_BPT_HISL, 0x18},
+               {OV3640_VPT, 0x41},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* -0.7EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x28},
+               {OV3640_BPT_HISL, 0x20},
+               {OV3640_VPT, 0x51},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* -0.3EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x30},
+               {OV3640_BPT_HISL, 0x28},
+               {OV3640_VPT, 0x61},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* default */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x38},
+               {OV3640_BPT_HISL, 0x30},
+               {OV3640_VPT, 0x61},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 0.3EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x40},
+               {OV3640_BPT_HISL, 0x38},
+               {OV3640_VPT, 0x71},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 0.7EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x48},
+               {OV3640_BPT_HISL, 0x40},
+               {OV3640_VPT, 0x81},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 1.0EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x50},
+               {OV3640_BPT_HISL, 0x48},
+               {OV3640_VPT, 0x91},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 1.3EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x58},
+               {OV3640_BPT_HISL, 0x50},
+               {OV3640_VPT, 0x91},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 1.7EV */
+       {
+               {OV3640_HISTO7, 0x00},
+               {OV3640_WPT_HISH, 0x60},
+               {OV3640_BPT_HISL, 0x58},
+               {OV3640_VPT, 0xa1},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+};
+
+/* Histogram Based Algorithm - Based on histogram and probability */
+const static struct ov3640_reg exposure_hist[11][5] = {
+       /* -1.7EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0x58},
+               {OV3640_BPT_HISL, 0x38},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* -1.3EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0x60},
+               {OV3640_BPT_HISL, 0x40},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* -1.0EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0x68},
+               {OV3640_BPT_HISL, 0x48},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* -0.7EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0x70},
+               {OV3640_BPT_HISL, 0x50},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* -0.3EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0x78},
+               {OV3640_BPT_HISL, 0x58},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* default */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0x80},
+               {OV3640_BPT_HISL, 0x60},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 0.3EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0x88},
+               {OV3640_BPT_HISL, 0x68},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 0.7EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0x90},
+               {OV3640_BPT_HISL, 0x70},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 1.0EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0x98},
+               {OV3640_BPT_HISL, 0x78},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 1.3EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0xa0},
+               {OV3640_BPT_HISL, 0x80},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+       /* 1.7EV */
+       {
+               {OV3640_HISTO7, 0x80},
+               {OV3640_WPT_HISH, 0xa8},
+               {OV3640_BPT_HISL, 0x88},
+               {OV3640_REG_TERM, OV3640_VAL_TERM}
+       },
+};
+
+/* ov3640 register configuration for combinations of pixel format and
+ * image size
+ */
+
+const static struct ov3640_reg qxga_yuv[] = {
+       {OV3640_SC_CTRL0, 0x02},
+       {OV3640_DSP_CTRL_4, 0xFC},
+       {OV3640_FMT_MUX_CTRL0, 0x00},
+       {OV3640_FMT_CTRL00, 0x00},
+       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
+       {OV3640_VTS_H, 0x06},
+       {OV3640_VTS_L, 0x20},
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+const static struct ov3640_reg qxga_565[] = {
+       {OV3640_SC_CTRL0, 0x02},
+       {OV3640_DSP_CTRL_4, 0xFC},
+       {OV3640_FMT_MUX_CTRL0, 0x01},
+       {OV3640_FMT_CTRL00, 0x11},
+       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
+       {OV3640_VTS_H, 0x06},
+       {OV3640_VTS_L, 0x20},
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+const static struct ov3640_reg qxga_555[] = {
+       {OV3640_SC_CTRL0, 0x02},
+       {OV3640_DSP_CTRL_4, 0xFC},
+       {OV3640_FMT_MUX_CTRL0, 0x01},
+       {OV3640_FMT_CTRL00, 0x13},
+       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
+       {OV3640_VTS_H, 0x06},
+       {OV3640_VTS_L, 0x20},
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+const static struct ov3640_reg qxga_raw10[] = {
+       {OV3640_SC_CTRL0, 0x22},
+       {OV3640_DSP_CTRL_4, 0x01},
+       {OV3640_FMT_MUX_CTRL0, 0x04},
+       {OV3640_FMT_CTRL00, 0x18},
+       {OV3640_OUT_CTRL01, 0x00},
+       {OV3640_VTS_H, 0x06},
+       {OV3640_VTS_L, 0x20},
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+const static struct ov3640_reg xga_yuv[] = {
+       {OV3640_SC_CTRL0, 0x02},
+       {OV3640_DSP_CTRL_4, 0xFC},
+       {OV3640_FMT_MUX_CTRL0, 0x00},
+       {OV3640_FMT_CTRL00, 0x00},
+       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
+       {OV3640_VTS_H, 0x03},
+       {OV3640_VTS_L, 0x10},
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+const static struct ov3640_reg xga_565[] = {
+       {OV3640_SC_CTRL0, 0x02},
+       {OV3640_DSP_CTRL_4, 0xFC},
+       {OV3640_FMT_MUX_CTRL0, 0x01},
+       {OV3640_FMT_CTRL00, 0x11},
+       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
+       {OV3640_VTS_H, 0x03},
+       {OV3640_VTS_L, 0x10},
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+const static struct ov3640_reg xga_555[] = {
+       {OV3640_SC_CTRL0, 0x02},
+       {OV3640_DSP_CTRL_4, 0xFC},
+       {OV3640_FMT_MUX_CTRL0, 0x01},
+       {OV3640_FMT_CTRL00, 0x13},
+       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
+       {OV3640_VTS_H, 0x03},
+       {OV3640_VTS_L, 0x10},
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+const static struct ov3640_reg xga_raw10[] = {
+       {OV3640_SC_CTRL0, 0x22},
+       {OV3640_DSP_CTRL_4, 0x01},
+       {OV3640_FMT_MUX_CTRL0, 0x04},
+       {OV3640_FMT_CTRL00, 0x18},
+       {OV3640_OUT_CTRL01, 0x00},
+       {OV3640_VTS_H, 0x03},
+       {OV3640_VTS_L, 0x10},
+       {OV3640_REG_TERM, OV3640_VAL_TERM}
+};
+
+const static struct ov3640_reg
+       *ov3640_reg_init[OV_NUM_PIXEL_FORMATS][OV_NUM_IMAGE_SIZES] = {
+       {xga_yuv, qxga_yuv},
+       {xga_565, qxga_565},
+       {xga_555, qxga_555},
+       {xga_raw10, qxga_raw10}
+};
+
+/*
+ * struct vcontrol - Video controls
+ * @v4l2_queryctrl: V4L2 VIDIOC_QUERYCTRL ioctl structure
+ * @current_value: current value of this control
+ */
+static struct vcontrol {
+       struct v4l2_queryctrl qc;
+       int current_value;
+} video_control[] = {
+#if (OV3640_RAW_MODE == 0)
+       {
+               {
+               .id = V4L2_CID_BRIGHTNESS,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Brightness",
+               .minimum = OV3640_MIN_BRIGHT,
+               .maximum = OV3640_MAX_BRIGHT,
+               .step = OV3640_BRIGHT_STEP,
+               .default_value = OV3640_DEF_BRIGHT,
+               },
+       .current_value = OV3640_DEF_BRIGHT,
+       },
+       {
+               {
+               .id = V4L2_CID_CONTRAST,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Contrast",
+               .minimum = OV3640_MIN_CONTRAST,
+               .maximum = OV3640_MAX_CONTRAST,
+               .step = OV3640_CONTRAST_STEP,
+               .default_value = OV3640_DEF_CONTRAST,
+               },
+       .current_value = OV3640_DEF_CONTRAST,
+       },
+       {
+               {
+               .id = V4L2_CID_PRIVATE_BASE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Color Effects",
+               .minimum = OV3640_MIN_COLOR,
+               .maximum = OV3640_MAX_COLOR,
+               .step = OV3640_COLOR_STEP,
+               .default_value = OV3640_DEF_COLOR,
+               },
+       .current_value = OV3640_DEF_COLOR,
+       }
+#endif
+};
+
+/*
+ * find_vctrl - Finds the requested ID in the video control structure array
+ * @id: ID of control to search the video control array.
+ *
+ * Returns the index of the requested ID from the control structure array
+ */
+static int find_vctrl(int id)
+{
+       int i = 0;
+
+       if (id < V4L2_CID_BASE)
+               return -EDOM;
+
+       for (i = (ARRAY_SIZE(video_control) - 1); i >= 0; i--)
+               if (video_control[i].qc.id == id)
+                       break;
+       if (i < 0)
+               i = -EINVAL;
+       return i;
+}
+
+/*
+ * Read a value from a register in ov3640 sensor device.
+ * The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ov3640_read_reg(struct i2c_client *client, u16 data_length, u16 reg,
+                                                               u32 *val)
+{
+       int err = 0;
+       struct i2c_msg msg[1];
+       unsigned char data[4];
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       msg->addr = client->addr;
+       msg->flags = I2C_M_WR;
+       msg->len = 2;
+       msg->buf = data;
+
+       /* High byte goes out first */
+       data[0] = (u8) (reg >> 8);
+       data[1] = (u8) (reg & 0xff);
+
+       err = i2c_transfer(client->adapter, msg, 1);
+       if (err >= 0) {
+               mdelay(3);
+               msg->flags = I2C_M_RD;
+               msg->len = data_length;
+               err = i2c_transfer(client->adapter, msg, 1);
+       }
+       if (err >= 0) {
+               *val = 0;
+               /* High byte comes first */
+               if (data_length == 1)
+                       *val = data[0];
+               else if (data_length == 2)
+                       *val = data[1] + (data[0] << 8);
+               else
+                       *val = data[3] + (data[2] << 8) +
+                               (data[1] << 16) + (data[0] << 24);
+               return 0;
+       }
+       dev_err(&client->dev, "read from offset 0x%x error %d", reg, err);
+       return err;
+}
+
+/* Write a value to a register in ov3640 sensor device.
+ * @client: i2c driver client structure.
+ * @reg: Address of the register to read value from.
+ * @val: Value to be written to a specific register.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ov3640_write_reg(struct i2c_client *client, u16 reg, u8 val)
+{
+       int err = 0;
+       struct i2c_msg msg[1];
+       unsigned char data[3];
+       int retries = 0;
+
+       if (!client->adapter)
+               return -ENODEV;
+retry:
+       msg->addr = client->addr;
+       msg->flags = I2C_M_WR;
+       msg->len = 3;
+       msg->buf = data;
+
+       /* high byte goes out first */
+       data[0] = (u8) (reg >> 8);
+       data[1] = (u8) (reg & 0xff);
+       data[2] = val;
+
+       err = i2c_transfer(client->adapter, msg, 1);
+       udelay(50);
+
+       if (err >= 0)
+               return 0;
+
+       if (retries <= 5) {
+               dev_dbg(&client->dev, "Retrying I2C... %d", retries);
+               retries++;
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(msecs_to_jiffies(20));
+               goto retry;
+       }
+
+       return err;
+}
+
+/*
+ * Initialize a list of ov3640 registers.
+ * The list of registers is terminated by the pair of values
+ * {OV3640_REG_TERM, OV3640_VAL_TERM}.
+ * @client: i2c driver client structure.
+ * @reglist[]: List of address of the registers to write data.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ov3640_write_regs(struct i2c_client *client,
+                                       const struct ov3640_reg reglist[])
+{
+       int err = 0;
+       const struct ov3640_reg *next = reglist;
+
+       while (!((next->reg == OV3640_REG_TERM)
+               && (next->val == OV3640_VAL_TERM))) {
+               err = ov3640_write_reg(client, next->reg, next->val);
+               udelay(100);
+               if (err)
+                       return err;
+               next++;
+       }
+       return 0;
+}
+
+/* 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_ov
+ov3640_find_size(unsigned int width, unsigned int height)
+{
+       if ((width > ov3640_sizes[XGA].width) ||
+               (height > ov3640_sizes[XGA].height))
+               return QXGA;
+       return XGA;
+}
+
+/*
+ * Set CSI2 Virtual ID.
+ */
+static int ov3640_set_virtual_id(struct i2c_client *client, u32 id)
+{
+       return ov3640_write_reg(client, OV3640_MIPI_CTRL0C, (0x3 & id) << 6 |
+                                                                       0x02);
+}
+
+
+/*
+ * Calculates the MIPIClk.
+ * 1) Calculate fclk
+ *     fclk = (64 - OV3640_PLL_1[5:0]) * N * Bit8Div * MCLK / M
+ *    where N = 1/1.5/2/3 for OV3640_PLL_2[7:6]=0~3
+ *          M = 1/1.5/2/3 for OV3640_PLL_2[1:0]=0~3
+ *    Bit8Div = 1/1/4/5 for OV3640_PLL_2[5:4]
+ * 2) Calculate MIPIClk
+ *     MIPIClk = fclk / ScaleDiv / MIPIDiv
+ *             = fclk * (1/ScaleDiv) / MIPIDiv
+ *    where 1/ScaleDiv = 0x3010[3:0]*2
+ *          MIPIDiv = 0x3010[5] + 1
+ * NOTE:
+ *  - The lookup table 'lut1' has been multiplied by 2 so all its values
+ *    are integers. Since both N & M use the same table, and they are
+ *    used as a ratio then the factor of 2 is already take into account.
+ *    i.e.  2N/2M = N/M
+ */
+static u32 ov3640_calc_mipiclk(struct v4l2_int_device *s)
+{
+       struct ov3640_sensor *sensor = s->priv;
+       struct i2c_client *client = sensor->i2c_client;
+       u32 rxpll, val, n, m, bit8div;
+       u32 sdiv_inv, mipidiv;
+       u32 fclk, mipiclk, mclk = 24000000;
+       u8 lut1[4] = {2, 3, 4, 6};
+       u8 lut2[4] = {1, 1, 4, 5};
+
+       /* Calculate fclk */
+       ov3640_read_reg(client, 1, OV3640_PLL_1, &val);
+       rxpll = val & 0x3F;
+
+       ov3640_read_reg(client, 1, OV3640_PLL_2, &val);
+       n = lut1[(val >> 6) & 0x3];
+       m = lut1[val & 0x3];
+       bit8div = lut2[(val >> 4) & 0x3];
+       fclk = (64 - rxpll) * n * bit8div * mclk / m;
+
+       ov3640_read_reg(client, 1, OV3640_PLL_3, &val);
+       mipidiv = ((val >> 5) & 1) + 1;
+       sdiv_inv = (val & 0xF) * 2;
+
+       if ((val & 0xF) >= 1)
+               mipiclk = fclk / sdiv_inv / mipidiv;
+       else
+               mipiclk = fclk / mipidiv;
+       dev_dbg(&client->dev, "mipiclk=%u  fclk=%u  val&0xF=%u  sdiv_inv=%u  "
+                                                       "mipidiv=%u\n",
+                                                       mipiclk, fclk, val&0xF,
+                                                       sdiv_inv, mipidiv);
+       return mipiclk;
+}
+
+/**
+ * ov3640_set_framerate
+ **/
+static int ov3640_set_framerate(struct i2c_client *client,
+                                               struct v4l2_fract *fper,
+                                               enum image_size_ov isize)
+{
+       u32 tempfps1, tempfps2;
+       u8 clkval;
+/*
+       u32 origvts, newvts, templineperiod;
+       u32 origvts_h, origvts_l, newvts_h, newvts_l;
+*/
+       int err = 0;
+
+       /* FIXME: QXGA framerate setting forced to 15 FPS */
+       if (isize == QXGA) {
+               err = ov3640_write_reg(client, OV3640_PLL_1, 0x32);
+               err = ov3640_write_reg(client, OV3640_PLL_2, 0x21);
+               err = ov3640_write_reg(client, OV3640_PLL_3, 0x21);
+               err = ov3640_write_reg(client, OV3640_CLK, 0x01);
+               err = ov3640_write_reg(client, 0x304c, 0x81);
+               return err;
+       }
+
+       tempfps1 = fper->denominator * 10000;
+       tempfps1 /= fper->numerator;
+       tempfps2 = fper->denominator / fper->numerator;
+       if ((tempfps1 % 10000) != 0)
+               tempfps2++;
+       clkval = (u8)((30 / tempfps2) - 1);
+
+       err = ov3640_write_reg(client, OV3640_CLK, clkval);
+       /* RxPLL = 50d = 32h */
+       err = ov3640_write_reg(client, OV3640_PLL_1, 0x32);
+       /* RxPLL = 50d = 32h */
+       err = ov3640_write_reg(client, OV3640_PLL_2,
+                                       OV3640_PLL_2_BIT8DIV_4 |
+                                       OV3640_PLL_2_INDIV_1_5);
+       /*
+        * NOTE: Sergio's Fix for MIPI CLK timings, not suggested by OV
+        */
+       err = ov3640_write_reg(client, OV3640_PLL_3, 0x21 +
+                                                       (clkval & 0xF));
+       /* Setting DVP divisor value */
+       err = ov3640_write_reg(client, 0x304c, 0x82);
+/* FIXME: Time adjustment to add granularity to the available fps */
+/*
+       ov3640_read_reg(client, 1, OV3640_VTS_H, &origvts_h);
+       ov3640_read_reg(client, 1, OV3640_VTS_L, &origvts_l);
+       origvts = (u32)((origvts_h << 8) + origvts_l);
+       templineperiod = 1000000 / (tempfps2 * origvts);
+       newvts = 1000000 / (tempfps2 * templineperiod);
+       newvts_h = (u8)((newvts & 0xFF00) >> 8);
+       newvts_l = (u8)(newvts & 0xFF);
+       err = ov3640_write_reg(client, OV3640_VTS_H, newvts_h);
+       err = ov3640_write_reg(client, OV3640_VTS_L, newvts_l);
+*/
+       return err;
+}
+
+/*
+ * Configure the ov3640 for a specified image size, pixel format, and frame
+ * period.  xclk is the frequency (in Hz) of the xclk input to the OV3640.
+ * 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 ov3640_configure(struct v4l2_int_device *s)
+{
+       struct ov3640_sensor *sensor = s->priv;
+       struct v4l2_pix_format *pix = &sensor->pix;
+       struct i2c_client *client = sensor->i2c_client;
+       enum image_size_ov isize = XGA;
+       unsigned char hsize_l = 0, hsize_h = 0;
+       unsigned char vsize_l = 0, vsize_h = 0;
+       int vsize = 0, hsize = 0, height_l = 0, height_h = 0, width_l = 0;
+       int width_h = 0, ratio = 0, err = 0;
+       u32 mipiclk;
+       enum pixel_format_ov pfmt = YUV;
+       u32 min_hs_zero_nui, min_hs_zero, min_hs_zero_total;
+       u32 min_hs_prepare_nui, min_hs_prepare, min_hs_prepare_total;
+       u32 max_hs_prepare_nui, max_hs_prepare, max_hs_prepare_total;
+       u32 ubound_hs_settle, lbound_hs_settle;
+       u32 val;
+
+       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_SGRBG10:
+               pfmt = RAW10;
+               break;
+
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       default:
+               pfmt = YUV;
+       }
+
+       /* Set receivers virtual channel before sensor setup starts.
+        * Only set the sensors virtual channel after all other setup
+        * for the sensor is complete.
+        */
+       isp_csi2_ctx_config_virtual_id(0, OV3640_CSI2_VIRTUAL_ID);
+       isp_csi2_ctx_update(0, false);
+
+       if (ov3640_find_size(pix->width, pix->height) == XGA)
+               isize = XGA;
+       else
+               isize = QXGA;
+
+       /* Reset */
+       ov3640_write_reg(client, OV3640_SYS, 0x80);
+       mdelay(5);
+
+       /* Common registers */
+       err = ov3640_write_regs(client, ov3640_common[isize]);
+
+       /* Configure image size and pixel format */
+       err = ov3640_write_regs(client, ov3640_reg_init[pfmt][isize]);
+
+       /* Setting of frame rate (OV suggested way) */
+       err = ov3640_set_framerate(client, &sensor->timeperframe, isize);
+#ifdef CONFIG_VIDEO_OV3640_CSI2
+       /* Set CSI2 common register settings */
+       err = ov3640_write_regs(client, ov3640_common_csi2);
+#endif
+
+       sensor->isize = isize;
+
+       /* Scale image if needed*/
+       if (((pix->width == ov3640_sizes[QXGA].width) &&
+               (pix->height == ov3640_sizes[QXGA].height) && (isize == QXGA))
+               || ((pix->width == ov3640_sizes[XGA].width) &&
+               (pix->height == ov3640_sizes[XGA].height) &&
+               (isize == XGA)) || (pfmt == RAW10)) {
+
+               /* if the image size correspond to one of the base image sizes
+                       then we don't need to scale the image */
+               sensor->hsize = pix->width;
+               sensor->vsize = pix->height;
+
+               if (isize == XGA)
+                       ov3640_write_regs(client, ov3640_out_xga);
+               else
+                       ov3640_write_regs(client, ov3640_out_qxga);
+
+       } else {
+       /* Default Ver and Hor sizes for QXGA and XGA*/
+               if (isize == QXGA) {
+                       vsize = 0x600;/* 0x60c; */
+                       hsize = 0x800;/* 0x818; */
+               } else {
+                       vsize = 0x304;
+                       hsize = 0x40c;
+               }
+               /* Scaling */
+               /* Adjust V and H sizes for image sizes not derived form VGA*/
+               ratio = (pix->width * 1000) / pix->height;
+
+               if  (((vsize * ratio + 500) / 1000) > hsize)
+                       vsize = (hsize * 1000) / ratio ;
+
+               else
+                       hsize = (vsize * ratio + 500) / 1000;
+
+               /* We need even numbers */
+               if (vsize & 1)
+                       vsize--;
+               if (hsize & 1)
+                       hsize--;
+
+               /* Adjusting numbers to set registers correctly */
+               hsize_l = (0xFF & hsize);
+               hsize_h = (0xF00 & hsize) >> 8;
+               vsize_l = (0xFF & vsize);
+               vsize_h = (0x700 & vsize) >> 4;
+
+               /* According to Software app notes we have to add 0x08 and 0x04
+                * in order to scale correctly
+                */
+               width_l = (0xFF & pix->width) + 0x08;
+               width_h = (0xF00 & pix->width) >> 8;
+               height_l = (0xFF & pix->height) + 0x04;
+               height_h = (0x700 & pix->height) >> 4;
+
+               err = ov3640_write_reg(client, OV3640_SIZE_IN_MISC,
+                                                       (vsize_h | hsize_h));
+               err = ov3640_write_reg(client, OV3640_HSIZE_IN_L, hsize_l);
+               err = ov3640_write_reg(client, OV3640_VSIZE_IN_L, vsize_l);
+               err = ov3640_write_reg(client, OV3640_SIZE_OUT_MISC,
+                                                       (height_h | width_h));
+               err = ov3640_write_reg(client, OV3640_HSIZE_OUT_L, width_l);
+               err = ov3640_write_reg(client, OV3640_VSIZE_OUT_L, height_l);
+               err = ov3640_write_reg(client, OV3640_ISP_PAD_CTR2, 0x42);
+               err = ov3640_write_reg(client, OV3640_ISP_XOUT_H, width_h);
+               err = ov3640_write_reg(client, OV3640_ISP_XOUT_L,
+                                                       (width_l  - 0x08));
+               err = ov3640_write_reg(client, OV3640_ISP_YOUT_H,
+                                                       (height_h >> 4));
+               err = ov3640_write_reg(client, OV3640_ISP_YOUT_L,
+                                                       (height_l - 0x04));
+
+               sensor->hsize = hsize;
+               sensor->vsize = vsize;
+
+               dev_dbg(&client->dev, "HSIZE_IN =%i  VSIZE_IN =%i\n", hsize,
+                                                                       vsize);
+               dev_dbg(&client->dev, "HSIZE_OUT=%u  VSIZE_OUT=%u\n",
+                                                       (pix->width + 8),
+                                                       (pix->height + 4));
+               dev_dbg(&client->dev, "ISP_XOUT =%u  ISP_YOUT =%u\n",
+                                                               pix->width,
+                                                               pix->height);
+       }
+
+       /* Setup the ISP VP based on image format */
+       if (pix->pixelformat == V4L2_PIX_FMT_SGRBG10) {
+               isp_csi2_ctrl_config_vp_out_ctrl(2);
+               isp_csi2_ctrl_update(false);
+       } else {
+               isp_csi2_ctrl_config_vp_out_ctrl(1);
+               isp_csi2_ctrl_update(false);
+       }
+
+       /* Store image size */
+       sensor->width = pix->width;
+       sensor->height = pix->height;
+
+       sensor->crop_rect.left = 0;
+       sensor->crop_rect.width = pix->width;
+       sensor->crop_rect.top = 0;
+       sensor->crop_rect.height = pix->height;
+
+#ifdef CONFIG_VIDEO_OV3640_CSI2
+       mipiclk = ov3640_calc_mipiclk(s);
+
+       /* Calculate Valid bounds for High speed settle timing in UIs */
+       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL22, &val);
+       min_hs_zero_nui = ((val & OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_MASK) >>
+                               OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_SHIFT);
+       min_hs_zero = ((val & OV3640_MIPI_CTRL22_MIN_HS_ZERO_H_MASK) << 8);
+       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL23, &val);
+       min_hs_zero |= (val & OV3640_MIPI_CTRL23_MIN_HS_ZERO_L_MASK);
+       min_hs_zero_total = ((min_hs_zero_nui * 1000000 * 1000) / mipiclk) +
+                                                               min_hs_zero;
+
+       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL32, &val);
+       min_hs_prepare_nui = ((val &
+                               OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_MASK) >>
+                               OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_SHIFT);
+       min_hs_prepare = ((val &
+                               OV3640_MIPI_CTRL32_MIN_HS_PREPARE_H_MASK) << 8);
+       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL33, &val);
+       min_hs_prepare |= (val & OV3640_MIPI_CTRL33_MIN_HS_PREPARE_L_MASK);
+       min_hs_prepare_total = ((min_hs_prepare_nui * 1000000 * 1000) /
+                                               mipiclk) + min_hs_prepare;
+
+       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL34, &val);
+       max_hs_prepare_nui = ((val &
+                               OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_MASK) >>
+                               OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_SHIFT);
+       max_hs_prepare = ((val &
+                               OV3640_MIPI_CTRL34_MAX_HS_PREPARE_H_MASK) << 8);
+       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL35, &val);
+       max_hs_prepare |= (val & OV3640_MIPI_CTRL35_MAX_HS_PREPARE_L_MASK);
+       max_hs_prepare_total = ((max_hs_prepare_nui * 1000000 * 1000) /
+                                               mipiclk) + max_hs_prepare;
+
+       ubound_hs_settle = ((min_hs_zero_total + min_hs_prepare_total) *
+                                       ((mipiclk >> 1) / 1000000)) / 1000;
+       lbound_hs_settle = (max_hs_prepare_total * ((mipiclk >> 1) /
+                                                       1000000)) / 1000;
+
+       /* Send settings to ISP-CSI2 Receiver PHY */
+       isp_csi2_calc_phy_cfg0(mipiclk, lbound_hs_settle, ubound_hs_settle);
+
+       /* Set sensors virtual channel*/
+       ov3640_set_virtual_id(client, OV3640_CSI2_VIRTUAL_ID);
+#endif
+       return err;
+}
+
+
+/* Detect if an ov3640 is present, returns a negative error number if no
+ * device is detected, or pidl as version number if a device is detected.
+ */
+static int ov3640_detect(struct i2c_client *client)
+{
+       u32 pidh, pidl;
+
+       if (!client)
+               return -ENODEV;
+
+       if (ov3640_read_reg(client, 1, OV3640_PIDH, &pidh))
+               return -ENODEV;
+
+       if (ov3640_read_reg(client, 1, OV3640_PIDL, &pidl))
+               return -ENODEV;
+
+       if ((pidh == OV3640_PIDH_MAGIC) && ((pidl == OV3640_PIDL_MAGIC1) ||
+                                               (pidl == OV3640_PIDL_MAGIC2))) {
+               dev_dbg(&client->dev, "Detect success (%02X,%02X)\n", pidh,
+                                                                       pidl);
+               return pidl;
+       }
+
+       return -ENODEV;
+}
+
+/* To get the cropping capabilities of ov3640 sensor
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ioctl_cropcap(struct v4l2_int_device *s,
+                                               struct v4l2_cropcap *cropcap)
+{
+       struct ov3640_sensor *sensor = s->priv;
+
+       cropcap->bounds.top = 0;
+       cropcap->bounds.left = 0;
+       cropcap->bounds.width = sensor->width;
+       cropcap->bounds.height = sensor->height;
+       cropcap->defrect = cropcap->bounds;
+       cropcap->pixelaspect.numerator = 1;
+       cropcap->pixelaspect.denominator = 1;
+       return 0;
+}
+
+/* To get the current crop window for of ov3640 sensor
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ioctl_g_crop(struct v4l2_int_device *s, struct  v4l2_crop *crop)
+{
+       struct ov3640_sensor *sensor = s->priv;
+
+       crop->c = sensor->crop_rect;
+       return 0;
+}
+
+/* To set the crop window for of ov3640 sensor
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ioctl_s_crop(struct v4l2_int_device *s, struct  v4l2_crop *crop)
+{
+       struct ov3640_sensor *sensor = s->priv;
+       /* FIXME: Temporary workaround for avoiding Zoom setting */
+       /* struct i2c_client *client = sensor->i2c_client; */
+       struct v4l2_rect *cur_rect;
+       unsigned long *cur_width, *cur_height;
+       int hstart, vstart, hsize, vsize, hsize_l, vsize_l, hsize_h, vsize_h;
+       int hratio, vratio, zoomfactor, err = 0;
+
+       cur_rect = &sensor->crop_rect;
+       cur_width = &sensor->width;
+       cur_height = &sensor->height;
+
+       if ((crop->c.left == cur_rect->left) &&
+           (crop->c.width == cur_rect->width) &&
+           (crop->c.top == cur_rect->top) &&
+           (crop->c.height == cur_rect->height))
+               return 0;
+
+       /* out of range? then return the current crop rectangle */
+       if ((crop->c.left + crop->c.width) > sensor->width ||
+           (crop->c.top + crop->c.height) > sensor->height) {
+               crop->c = *cur_rect;
+               return 0;
+       }
+
+       if (sensor->isize == QXGA)
+               zoomfactor = 1;
+       else
+               zoomfactor = 2;
+
+       hratio = (sensor->hsize * 1000) / sensor->width;
+       vratio = (sensor->vsize * 1000) / sensor->height;
+       hstart = (((crop->c.left * hratio + 500) / 1000) * zoomfactor) + 0x11d;
+       vstart = (((crop->c.top * vratio + 500) / 1000) + 0x0a);
+       hsize  = (crop->c.width * hratio + 500) / 1000;
+       vsize  = (crop->c.height * vratio + 500) / 1000;
+
+       if (vsize & 1)
+               vsize--;
+       if (hsize & 1)
+               hsize--;
+
+       /* Adjusting numbers to set register correctly */
+       hsize_l = (0xFF & hsize);
+       hsize_h = (0xF00 & hsize) >> 8;
+       vsize_l = (0xFF & vsize);
+       vsize_h = (0x700 & vsize) >> 4;
+
+       if ((sensor->height > vsize) || (sensor->width > hsize))
+               return -EINVAL;
+
+       hsize = hsize * zoomfactor;
+/*
+       err = ov3640_write_reg(client, OV3640_DSP_CTRL_2, 0xEF);
+       err = ov3640_write_reg(client, OV3640_SIZE_IN_MISC, (vsize_h |
+                                                               hsize_h));
+       err = ov3640_write_reg(client, OV3640_HSIZE_IN_L, hsize_l);
+       err = ov3640_write_reg(client, OV3640_VSIZE_IN_L, vsize_l);
+       err = ov3640_write_reg(client, OV3640_HS_H, (hstart >> 8) & 0xFF);
+       err = ov3640_write_reg(client, OV3640_HS_L, hstart & 0xFF);
+       err = ov3640_write_reg(client, OV3640_VS_H, (vstart >> 8) & 0xFF);
+       err = ov3640_write_reg(client, OV3640_VS_L, vstart & 0xFF);
+       err = ov3640_write_reg(client, OV3640_HW_H, ((hsize) >> 8) & 0xFF);
+       err = ov3640_write_reg(client, OV3640_HW_L, hsize & 0xFF);
+       err = ov3640_write_reg(client, OV3640_VH_H, ((vsize) >> 8) & 0xFF);
+       err = ov3640_write_reg(client, OV3640_VH_L, vsize & 0xFF);
+*/
+       if (err)
+               return err;
+
+       /* save back */
+       *cur_rect = crop->c;
+
+       /* Setting crop too fast can cause frame out-of-sync. */
+
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(msecs_to_jiffies(20));
+       return 0;
+}
+
+
+/*
+ * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control information
+ * from the video_control[] array.  Otherwise, returns -EINVAL if the
+ * control is not supported.
+ */
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+                                               struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       i = find_vctrl(qc->id);
+       if (i == -EINVAL)
+               qc->flags = V4L2_CTRL_FLAG_DISABLED;
+
+       if (i < 0)
+               return -EINVAL;
+
+       *qc = video_control[i].qc;
+       return 0;
+}
+
+/*
+ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the video_control[] array.  Otherwise, returns -EINVAL
+ * if the control is not supported.
+ */
+
+static int ioctl_g_ctrl(struct v4l2_int_device *s,
+                            struct v4l2_control *vc)
+{
+       struct vcontrol *lvc;
+       int i;
+
+       i = find_vctrl(vc->id);
+       if (i < 0)
+               return -EINVAL;
+       lvc = &video_control[i];
+
+       switch (vc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               vc->value = lvc->current_value;
+               break;
+       case V4L2_CID_CONTRAST:
+               vc->value = lvc->current_value;
+               break;
+       case V4L2_CID_PRIVATE_BASE:
+               vc->value = lvc->current_value;
+               break;
+       }
+       return 0;
+}
+
+/*
+ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the video_control[] array).  Otherwise,
+ * returns -EINVAL if the control is not supported.
+ */
+static int ioctl_s_ctrl(struct v4l2_int_device *s,
+                            struct v4l2_control *vc)
+{
+       int retval = -EINVAL;
+       int i;
+       struct ov3640_sensor *sensor = s->priv;
+       struct i2c_client *client = sensor->i2c_client;
+       struct vcontrol *lvc;
+
+       i = find_vctrl(vc->id);
+       if (i < 0)
+               return -EINVAL;
+
+       lvc = &video_control[i];
+
+       switch (vc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if (vc->value >= 0 && vc->value <= 6) {
+                       retval = ov3640_write_regs(client,
+                                                       brightness[vc->value]);
+               } else {
+                       dev_err(&client->dev, "BRIGHTNESS LEVEL NOT SUPPORTED");
+                       return -EINVAL;
+               }
+               break;
+       case V4L2_CID_CONTRAST:
+               if (vc->value >= 0 && vc->value <= 6)
+                       retval = ov3640_write_regs(client, contrast[vc->value]);
+               else {
+                       dev_err(&client->dev, "CONTRAST LEVEL NOT SUPPORTED");
+                       return -EINVAL;
+               }
+               break;
+       case V4L2_CID_PRIVATE_BASE:
+               if (vc->value >= 0 && vc->value <= 2)
+                       retval = ov3640_write_regs(client, colors[vc->value]);
+               else {
+                       dev_err(&client->dev, "COLOR LEVEL NOT SUPPORTED");
+                       return -EINVAL;
+               }
+               break;
+       }
+       if (!retval)
+               lvc->current_value = vc->value;
+       return retval;
+}
+
+/*
+ * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
+ *
+ * Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
+ */
+ static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+                                  struct v4l2_fmtdesc *fmt)
+{
+       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;
+       default:
+               return -EINVAL;
+       }
+
+       fmt->flags = ov3640_formats[index].flags;
+       strlcpy(fmt->description, ov3640_formats[index].description,
+                                       sizeof(fmt->description));
+       fmt->pixelformat = ov3640_formats[index].pixelformat;
+
+       return 0;
+}
+
+
+/*
+ * ioctl_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
+ *
+ * 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 ioctl_try_fmt_cap(struct v4l2_int_device *s,
+                            struct v4l2_format *f)
+{
+       int ifmt;
+       enum image_size_ov isize;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       if (pix->width > ov3640_sizes[QXGA].width)
+               pix->width = ov3640_sizes[QXGA].width;
+       if (pix->height > ov3640_sizes[QXGA].height)
+               pix->height = ov3640_sizes[QXGA].height;
+
+       isize = ov3640_find_size(pix->width, pix->height);
+       pix->width = ov3640_sizes[isize].width;
+       pix->height = ov3640_sizes[isize].height;
+
+       for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
+               if (pix->pixelformat == ov3640_formats[ifmt].pixelformat)
+                       break;
+       }
+       if (ifmt == NUM_CAPTURE_FORMATS)
+               ifmt = 0;
+       pix->pixelformat = ov3640_formats[ifmt].pixelformat;
+       pix->field = V4L2_FIELD_NONE;
+       pix->bytesperline = pix->width*2;
+       pix->sizeimage = pix->bytesperline*pix->height;
+       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_SGRBG10:
+       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;
+}
+
+
+/*
+ * ioctl_s_fmt_cap - V4L2 sensor interface handler for VIDIOC_S_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
+ *
+ * If the requested format is supported, configures the HW to use that
+ * format, returns error code if format not supported or HW can't be
+ * correctly configured.
+ */
+ static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+                               struct v4l2_format *f)
+{
+       struct ov3640_sensor *sensor = s->priv;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       int rval;
+
+       rval = ioctl_try_fmt_cap(s, f);
+       if (rval)
+               return rval;
+
+       sensor->pix = *pix;
+
+       return 0;
+}
+
+/*
+ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the sensor's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
+                               struct v4l2_format *f)
+{
+       struct ov3640_sensor *sensor = s->priv;
+       f->fmt.pix = sensor->pix;
+
+       return 0;
+}
+
+/*
+ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ioctl_g_parm(struct v4l2_int_device *s,
+                            struct v4l2_streamparm *a)
+{
+       struct ov3640_sensor *sensor = s->priv;
+       struct v4l2_captureparm *cparm = &a->parm.capture;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memset(a, 0, sizeof(*a));
+       a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       cparm->capability = V4L2_CAP_TIMEPERFRAME;
+       cparm->timeperframe = sensor->timeperframe;
+
+       return 0;
+}
+
+/*
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible.  If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_parm(struct v4l2_int_device *s,
+                            struct v4l2_streamparm *a)
+{
+       int rval = 0;
+       struct ov3640_sensor *sensor = s->priv;
+       struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+       struct v4l2_fract timeperframe_old;
+       int desired_fps;
+       timeperframe_old = sensor->timeperframe;
+       sensor->timeperframe = *timeperframe;
+
+       desired_fps = timeperframe->denominator / timeperframe->numerator;
+       if ((desired_fps < OV3640_MIN_FPS) || (desired_fps > OV3640_MAX_FPS))
+               rval = -EINVAL;
+
+       if (rval)
+               sensor->timeperframe = timeperframe_old;
+       else
+               *timeperframe = sensor->timeperframe;
+
+       return rval;
+}
+
+/*
+ * ioctl_g_priv - V4L2 sensor interface handler for vidioc_int_g_priv_num
+ * @s: pointer to standard V4L2 device structure
+ * @p: void pointer to hold sensor's private data address
+ *
+ * Returns device's (sensor's) private data area address in p parameter
+ */
+static int ioctl_g_priv(struct v4l2_int_device *s, void *p)
+{
+       struct ov3640_sensor *sensor = s->priv;
+
+       return sensor->pdata->priv_data_set(p);
+}
+
+/*
+ * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
+ * @s: pointer to standard V4L2 device structure
+ * @on: power state to which device is to be set
+ *
+ * Sets devices power state to requrested state, if possible.
+ */
+ static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
+{
+       struct ov3640_sensor *sensor = s->priv;
+       struct i2c_client *c = sensor->i2c_client;
+       struct omap34xxcam_hw_config hw_config;
+       int rval;
+
+       rval = ioctl_g_priv(s, &hw_config);
+       if (rval) {
+               dev_err(&c->dev, "Unable to get hw params\n");
+               return rval;
+       }
+
+       rval = sensor->pdata->power_set(on);
+       if (rval < 0) {
+               dev_err(&c->dev, "Unable to set the power state: "
+                       OV3640_DRIVER_NAME " sensor\n");
+               sensor->pdata->set_xclk(0);
+               return rval;
+       }
+
+       if (on == V4L2_POWER_ON)
+               sensor->pdata->set_xclk(xclk_current);
+       else
+               sensor->pdata->set_xclk(0);
+
+       if ((on == V4L2_POWER_ON) && (sensor->state == SENSOR_DETECTED))
+               ov3640_configure(s);
+
+       if ((on == V4L2_POWER_ON) && (sensor->state == SENSOR_NOT_DETECTED)) {
+               rval = ov3640_detect(c);
+               if (rval < 0) {
+                       dev_err(&c->dev, "Unable to detect "
+                                       OV3640_DRIVER_NAME " sensor\n");
+                       sensor->state = SENSOR_NOT_DETECTED;
+                       return rval;
+               }
+               sensor->state = SENSOR_DETECTED;
+               sensor->ver = rval;
+               pr_info(OV3640_DRIVER_NAME " Chip version 0x%02x detected\n",
+                                                               sensor->ver);
+       }
+       return 0;
+}
+
+/*
+ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialize the sensor device (call ov3640_configure())
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+       return 0;
+}
+
+/**
+ * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Delinitialise the dev. at slave detach.  The complement of ioctl_dev_init.
+ */
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+       return 0;
+}
+
+/**
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.  Returns 0 if
+ * ov3640 device could be found, otherwise returns appropriate error.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+       return 0;
+}
+
+/**
+ * ioctl_enum_framesizes - V4L2 sensor if handler for vidioc_int_enum_framesizes
+ * @s: pointer to standard V4L2 device structure
+ * @frms: pointer to standard V4L2 framesizes enumeration structure
+ *
+ * Returns possible framesizes depending on choosen pixel format
+ **/
+static int ioctl_enum_framesizes(struct v4l2_int_device *s,
+                                       struct v4l2_frmsizeenum *frms)
+{
+       int ifmt;
+
+       for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
+               if (frms->pixel_format == ov3640_formats[ifmt].pixelformat)
+                       break;
+       }
+       /* Is requested pixelformat not found on sensor? */
+       if (ifmt == NUM_CAPTURE_FORMATS)
+               return -EINVAL;
+
+       /* Do we already reached all discrete framesizes? */
+       if (frms->index >= 2)
+               return -EINVAL;
+
+       frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+       frms->discrete.width = ov3640_sizes[frms->index].width;
+       frms->discrete.height = ov3640_sizes[frms->index].height;
+
+       return 0;
+}
+
+const struct v4l2_fract ov3640_frameintervals[] = {
+       { .numerator = 2, .denominator = 15 },
+       { .numerator = 1, .denominator = 15 },
+       { .numerator = 1, .denominator = 30 },
+};
+
+static int ioctl_enum_frameintervals(struct v4l2_int_device *s,
+                                       struct v4l2_frmivalenum *frmi)
+{
+       int ifmt;
+
+       for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
+               if (frmi->pixel_format == ov3640_formats[ifmt].pixelformat)
+                       break;
+       }
+       /* Is requested pixelformat not found on sensor? */
+       if (ifmt == NUM_CAPTURE_FORMATS)
+               return -EINVAL;
+
+       /* Do we already reached all discrete framesizes? */
+
+       if ((frmi->width == ov3640_sizes[1].width) &&
+                               (frmi->height == ov3640_sizes[1].height)) {
+               /* FIXME: The only frameinterval supported by QXGA capture is
+                * 2/15 fps
+                */
+               if (frmi->index != 0)
+                       return -EINVAL;
+       } else {
+               if (frmi->index >= 3)
+                       return -EINVAL;
+       }
+
+       frmi->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+       frmi->discrete.numerator =
+                               ov3640_frameintervals[frmi->index].numerator;
+       frmi->discrete.denominator =
+                               ov3640_frameintervals[frmi->index].denominator;
+
+       return 0;
+}
+
+static struct v4l2_int_ioctl_desc ov3640_ioctl_desc[] = {
+       {vidioc_int_enum_framesizes_num,
+         (v4l2_int_ioctl_func *)ioctl_enum_framesizes},
+       {vidioc_int_enum_frameintervals_num,
+         (v4l2_int_ioctl_func *)ioctl_enum_frameintervals},
+       {vidioc_int_dev_init_num,
+         (v4l2_int_ioctl_func *)ioctl_dev_init},
+       {vidioc_int_dev_exit_num,
+         (v4l2_int_ioctl_func *)ioctl_dev_exit},
+       {vidioc_int_s_power_num,
+         (v4l2_int_ioctl_func *)ioctl_s_power},
+       {vidioc_int_g_priv_num,
+         (v4l2_int_ioctl_func *)ioctl_g_priv},
+       {vidioc_int_init_num,
+         (v4l2_int_ioctl_func *)ioctl_init},
+       {vidioc_int_enum_fmt_cap_num,
+         (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap},
+       {vidioc_int_try_fmt_cap_num,
+         (v4l2_int_ioctl_func *)ioctl_try_fmt_cap},
+       {vidioc_int_g_fmt_cap_num,
+         (v4l2_int_ioctl_func *)ioctl_g_fmt_cap},
+       {vidioc_int_s_fmt_cap_num,
+         (v4l2_int_ioctl_func *)ioctl_s_fmt_cap},
+       {vidioc_int_g_parm_num,
+         (v4l2_int_ioctl_func *)ioctl_g_parm},
+       {vidioc_int_s_parm_num,
+         (v4l2_int_ioctl_func *)ioctl_s_parm},
+       {vidioc_int_queryctrl_num,
+         (v4l2_int_ioctl_func *)ioctl_queryctrl},
+       {vidioc_int_g_ctrl_num,
+         (v4l2_int_ioctl_func *)ioctl_g_ctrl},
+       {vidioc_int_s_ctrl_num,
+         (v4l2_int_ioctl_func *)ioctl_s_ctrl},
+         { vidioc_int_g_crop_num,
+         (v4l2_int_ioctl_func *)ioctl_g_crop},
+       {vidioc_int_s_crop_num,
+         (v4l2_int_ioctl_func *)ioctl_s_crop},
+         { vidioc_int_cropcap_num,
+         (v4l2_int_ioctl_func *)ioctl_cropcap},
+};
+
+static struct v4l2_int_slave ov3640_slave = {
+       .ioctls         = ov3640_ioctl_desc,
+       .num_ioctls     = ARRAY_SIZE(ov3640_ioctl_desc),
+};
+
+static struct v4l2_int_device ov3640_int_device = {
+       .module = THIS_MODULE,
+       .name   = OV3640_DRIVER_NAME,
+       .priv   = &ov3640,
+       .type   = v4l2_int_type_slave,
+       .u      = {
+               .slave = &ov3640_slave,
+       },
+};
+
+/*
+ * ov3640_probe - sensor driver i2c probe handler
+ * @client: i2c driver client device structure
+ *
+ * Register sensor as an i2c client device and V4L2
+ * device.
+ */
+static int __init
+ov3640_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct ov3640_sensor *sensor = &ov3640;
+       int err;
+
+       if (i2c_get_clientdata(client))
+               return -EBUSY;
+
+       sensor->pdata = client->dev.platform_data;
+
+       if (!sensor->pdata) {
+               dev_err(&client->dev, "No platform data?\n");
+               return -ENODEV;
+       }
+
+       sensor->v4l2_int_device = &ov3640_int_device;
+       sensor->i2c_client = client;
+
+       i2c_set_clientdata(client, sensor);
+
+       /* Make the default capture format XGA RGB565 */
+       sensor->pix.width = ov3640_sizes[XGA].width;
+       sensor->pix.height = ov3640_sizes[XGA].height;
+       sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
+
+       err = v4l2_int_device_register(sensor->v4l2_int_device);
+       if (err)
+               i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+/*
+ * ov3640_remove - sensor driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister sensor as an i2c client device and V4L2
+ * device. Complement of ov3640_probe().
+ */
+static int __exit
+ov3640_remove(struct i2c_client *client)
+{
+       struct ov3640_sensor *sensor = i2c_get_clientdata(client);
+
+       if (!client->adapter)
+               return -ENODEV; /* our client isn't attached */
+
+       v4l2_int_device_unregister(sensor->v4l2_int_device);
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+static const struct i2c_device_id ov3640_id[] = {
+       { OV3640_DRIVER_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, ov3640_id);
+
+static struct i2c_driver ov3640sensor_i2c_driver = {
+       .driver = {
+               .name   = OV3640_DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe  = ov3640_probe,
+       .remove = __exit_p(ov3640_remove),
+       .id_table = ov3640_id,
+};
+
+static struct ov3640_sensor ov3640 = {
+       .timeperframe = {
+               .numerator = 1,
+               .denominator = 15,
+       },
+       .state = SENSOR_NOT_DETECTED,
+};
+
+/*
+ * ov3640sensor_init - sensor driver module_init handler
+ *
+ * Registers driver as an i2c client driver.  Returns 0 on success,
+ * error code otherwise.
+ */
+static int __init ov3640sensor_init(void)
+{
+       int err;
+
+       err = i2c_add_driver(&ov3640sensor_i2c_driver);
+       if (err) {
+               printk(KERN_ERR "Failed to register" OV3640_DRIVER_NAME ".\n");
+               return err;
+       }
+       return 0;
+}
+module_init(ov3640sensor_init);
+
+/*
+ * ov3640sensor_cleanup - sensor driver module_exit handler
+ *
+ * Unregisters/deletes driver as an i2c client driver.
+ * Complement of ov3640sensor_init.
+ */
+static void __exit ov3640sensor_cleanup(void)
+{
+       i2c_del_driver(&ov3640sensor_i2c_driver);
+}
+module_exit(ov3640sensor_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OV3640 camera sensor driver");
+
+
diff --git a/drivers/media/video/ov3640_regs.h b/drivers/media/video/ov3640_regs.h
new file mode 100644
index 0000000..735be86
--- /dev/null
+++ b/drivers/media/video/ov3640_regs.h
@@ -0,0 +1,600 @@
+/*
+ * drivers/media/video/ov3640_regs.h
+ *
+ * Register definitions for the OV3640 CameraChip.
+ *
+ * Contributors:
+ *   Pallavi Kulkarni <p-kulkarni@ti.com>
+ *   Sergio Aguirre <saaguirre@ti.com>
+ *
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef OV3640_REGS_H
+#define OV3640_REGS_H
+
+/*
+ * System Control Registers
+ */
+#define OV3640_AGC_H                           0x3000
+#define OV3640_AGC_L                           0x3001
+#define OV3640_AEC_H                           0x3002
+#define OV3640_AEC_L                           0x3003
+#define OV3640_AECL                            0x3004
+#define OV3640_RED                             0x3005
+#define OV3640_GREEN                           0x3006
+#define OV3640_BLUE                            0x3007
+#define OV3640_PIDH                            0x300A
+#define OV3640_PIDL                            0x300B
+#define OV3640_SCCB_ID                         0x300C
+#define OV3640_PCLK                            0x300D
+#define OV3640_PCLK_HREFQUAL_OUT               (1 << 5)
+#define OV3640_PCLK_REVERSE                    (1 << 4)
+#define OV3640_PCLK_DIVBY4                     (1 << 1)
+#define OV3640_PCLK_DIVBY2                     1
+
+#define OV3640_PLL_1                           0x300E
+#define OV3640_PLL_1_RXPLL_MASK                        0x3F
+
+#define OV3640_PLL_2                           0x300F
+#define OV3640_PLL_2_FREQDIV_MASK              (0x3 << 6)
+#define OV3640_PLL_2_FREQDIV_1                 (0x0 << 6)
+#define OV3640_PLL_2_FREQDIV_1_5               (0x1 << 6)
+#define OV3640_PLL_2_FREQDIV_2                 (0x2 << 6)
+#define OV3640_PLL_2_FREQDIV_3                 (0x3 << 6)
+
+#define OV3640_PLL_2_BIT8DIV_MASK              (0x3 << 4)
+#define OV3640_PLL_2_BIT8DIV_1                 (0x0 << 4)
+#define OV3640_PLL_2_BIT8DIV_1_2               (0x1 << 4)
+#define OV3640_PLL_2_BIT8DIV_4                 (0x2 << 4)
+#define OV3640_PLL_2_BIT8DIV_5                 (0x3 << 4)
+#define OV3640_PLL_2_BYPASS                    (1 << 3)
+
+#define OV3640_PLL_2_INDIV_MASK                        0x3
+#define OV3640_PLL_2_INDIV_1                   0x0
+#define OV3640_PLL_2_INDIV_1_5                 0x1
+#define OV3640_PLL_2_INDIV_2                   0x2
+#define OV3640_PLL_2_INDIV_3                   0x3
+
+#define OV3640_PLL_3                           0x3010
+#define OV3640_PLL_3_DVPDIV_MASK               (0x3 << 6)
+#define OV3640_PLL_3_DVPDIV_1                  (0x0 << 6)
+#define OV3640_PLL_3_DVPDIV_2                  (0x1 << 6)
+#define OV3640_PLL_3_DVPDIV_8                  (0x2 << 6)
+#define OV3640_PLL_3_DVPDIV_16                 (0x3 << 6)
+
+#define OV3640_PLL_3_LANEDIV2LANES             (1 << 5)
+#define OV3640_PLL_3_SENSORDIV2                        (1 << 4)
+
+#define OV3640_PLL_3_SCALEDIV_MASK             0xF
+
+#define OV3640_CLK                             0x3011
+#define OV3640_CLK_DFREQDBL                    (1 << 7)
+#define OV3640_CLK_SLAVEMODE                   (1 << 6)
+#define OV3640_CLK_DIV_MASK                    0x3F
+
+#define OV3640_SYS                             0x3012
+#define OV3640_SYS_SRST                                (1 << 7)
+#define OV3640_SYS_BASERES_MASK                        (0x7 << 4)
+#define OV3640_SYS_BASERES_QXGA                        (0x0 << 4)
+#define OV3640_SYS_BASERES_XGA                 (0x1 << 4)
+#define OV3640_SYS_BASERES_SXGA                        (0x7 << 4)
+
+#define OV3640_AUTO_1                          0x3013
+#define OV3640_AUTO_1_FASTAEC                  (1 << 7)
+#define OV3640_AUTO_1_AECBIGSTEPS              (1 << 6)
+#define OV3640_AUTO_1_BANDINGFILTEREN          (1 << 5)
+#define OV3640_AUTO_1_AUTOBANDINGFILTER                (1 << 4)
+#define OV3640_AUTO_1_EXTRBRIGHTEXPEN          (1 << 3)
+#define OV3640_AUTO_1_AGCEN                    (1 << 2)
+#define OV3640_AUTO_1_AECEN                    1
+
+#define OV3640_AUTO_2                          0x3014
+#define OV3640_AUTO_2_MANBANDING50             (1 << 7)
+#define OV3640_AUTO_2_AUTOBANDINGDETEN         (1 << 6)
+#define OV3640_AUTO_2_AGCADDLT1F               (1 << 5)
+#define OV3640_AUTO_2_FREEZEAECAGC             (1 << 4)
+#define OV3640_AUTO_2_NIGHTMODEEN              (1 << 3)
+#define OV3640_AUTO_2_BANDINGSMOOTHSW          (1 << 2)
+#define OV3640_AUTO_2_MANEXTRBRIGHTEXPEN       (1 << 1)
+#define OV3640_AUTO_2_BANDINGFILTEREN          1
+
+#define OV3640_AUTO_3                          0x3015
+#define OV3640_AUTO_3_DUMMYFC_MASK             (0x7 << 4)
+#define OV3640_AUTO_3_DUMMYFC_NONE             (0x0 << 4)
+#define OV3640_AUTO_3_DUMMYFC_1FRAME           (0x1 << 4)
+#define OV3640_AUTO_3_DUMMYFC_2FRAME           (0x2 << 4)
+#define OV3640_AUTO_3_DUMMYFC_3FRAME           (0x3 << 4)
+#define OV3640_AUTO_3_DUMMYFC_7FRAME           (0x7 << 4)
+
+#define OV3640_AUTO_3_AGCGAINCEIL_MASK         0x7
+#define OV3640_AUTO_3_AGCGAINCEIL_2X           0x0
+#define OV3640_AUTO_3_AGCGAINCEIL_4X           0x1
+#define OV3640_AUTO_3_AGCGAINCEIL_8X           0x2
+#define OV3640_AUTO_3_AGCGAINCEIL_16X          0x3
+#define OV3640_AUTO_3_AGCGAINCEIL_32X          0x4
+#define OV3640_AUTO_3_AGCGAINCEIL_64X          0x5
+#define OV3640_AUTO_3_AGCGAINCEIL_128X         0x6
+#define OV3640_AUTO_3_AGCGAINCEIL_128X_2       0x7
+
+#define OV3640_AUTO_5                          0x3017
+#define OV3640_AUTO_5_MANBANDINGCNT_MASK       0x3F
+
+#define OV3640_WPT_HISH                                0x3018
+#define OV3640_BPT_HISL                                0x3019
+#define OV3640_VPT                             0x301A
+#define OV3640_YAVG                            0x301B
+#define OV3640_AECG_MAX50                      0x301C
+#define OV3640_AECG_MAX60                      0x301D
+#define OV3640_RZM_H                           0x301E
+#define OV3640_RZM_L                           0x301F
+
+#define OV3640_HS_H                            0x3020
+#define OV3640_HS_L                            0x3021
+#define OV3640_VS_H                            0x3022
+#define OV3640_VS_L                            0x3023
+#define OV3640_HW_H                            0x3024
+#define OV3640_HW_L                            0x3025
+#define OV3640_VH_H                            0x3026
+#define OV3640_VH_L                            0x3027
+#define OV3640_HTS_H                           0x3028
+#define OV3640_HTS_L                           0x3029
+#define OV3640_VTS_H                           0x302A
+#define OV3640_VTS_L                           0x302B
+#define OV3640_EXHTS                           0x302C
+#define OV3640_EXVTS_H                         0x302D
+#define OV3640_EXVTS_L                         0x302E
+
+#define OV3640_WEIGHT0                         0x3030
+#define OV3640_WEIGHT1                         0x3031
+#define OV3640_WEIGHT2                         0x3032
+#define OV3640_WEIGHT3                         0x3033
+#define OV3640_WEIGHT4                         0x3034
+#define OV3640_WEIGHT5                         0x3035
+#define OV3640_WEIGHT6                         0x3036
+#define OV3640_WEIGHT7                         0x3037
+#define OV3640_AHS_H                           0x3038
+#define OV3640_AHS_L                           0x3039
+#define OV3640_AVS_H                           0x303A
+#define OV3640_AVS_L                           0x303B
+#define OV3640_AHW_H                           0x303C
+#define OV3640_AHW_L                           0x303D
+#define OV3640_AVH_H                           0x303E
+#define OV3640_AVH_L                           0x303F
+
+#define OV3640_HISTO0                          0x3040
+#define OV3640_HISTO1                          0x3041
+#define OV3640_HISTO2                          0x3042
+#define OV3640_HISTO3                          0x3043
+#define OV3640_HISTO4                          0x3044
+#define OV3640_HISTO5                          0x3045
+#define OV3640_HISTO6                          0x3046
+#define OV3640_HISTO7                          0x3047
+#define OV3640_D56C1                           0x3048
+
+#define OV3640_BLC9                            0x3069
+
+#define OV3640_BD50_H                          0x3070
+#define OV3640_BD50_L                          0x3071
+#define OV3640_BD60_H                          0x3072
+#define OV3640_BD60_L                          0x3073
+#define OV3640_VSYNCOPT                                0x3075
+#define OV3640_TMC1                            0x3077
+#define OV3640_TMC1_CHSYNCSWAP                 (1 << 7)
+#define OV3640_TMC1_HREFSWAP                   (1 << 6)
+#define OV3640_TMC1_HREFPOL_NEG                        (1 << 3)
+#define OV3640_TMC1_VSYNCPOL_NEG               (1 << 1)
+#define OV3640_TMC1_HSYNCPOL_NEG               1
+
+#define OV3640_TMC2                            0x3078
+#define OV3640_TMC2_VSYNCDROP                  (1 << 1)
+#define OV3640_TMC2_FRAMEDATADROP              1
+
+#define OV3640_TMC3                            0x3079
+#define OV3640_TMC3_VSLATCH                    (1 << 7)
+
+#define OV3640_TMC4                            0x307A
+#define OV3640_TMC5                            0x307B
+#define OV3640_TMC5_AWB_GAINWRITE_DIS          (1 << 7)
+#define OV3640_TMC5_DCOLORBAREN                        (1 << 3)
+#define OV3640_TMC5_DCOLORBARPAT_MASK          0x7
+
+#define OV3640_TMC6                            0x307C
+#define OV3640_TMC6_DGAINEN                    (1 << 5)
+#define OV3640_TMC6_HMIRROR                    (1 << 1)
+#define OV3640_TMC6_VFLIP                      (1 << 0)
+
+#define OV3640_TMC7                            0x307D
+#define OV3640_TMC7_COLORBARTESTPATEN          (1 << 7)
+#define OV3640_TMC7_AVGHIST_SENSOR             (1 << 5)
+
+#define OV3640_TMC8                            0x307E
+
+#define OV3640_TMCA                            0x3080
+#define OV3640_TMCB                            0x3081
+#define OV3640_TMCB_MIRROROPTEN                        (1 << 7)
+#define OV3640_TMCB_OTPFASTMEMCLK              (1 << 6)
+#define OV3640_TMCB_SWAPBYTESOUT               1
+
+#define OV3640_TMCF                            0x3085
+#define OV3640_TMC10                           0x3086
+#define OV3640_TMC10_SYSRST                    (1 << 3)
+#define OV3640_TMC10_REGSLEEPOPT               (1 << 2)
+#define OV3640_TMC10_SLEEPOPT                  (1 << 1)
+#define OV3640_TMC10_SLEEPEN                   1
+
+#define OV3640_TMC11                           0x3087
+#define OV3640_ISP_XOUT_H                      0x3088
+#define OV3640_ISP_XOUT_L                      0x3089
+#define OV3640_ISP_YOUT_H                      0x308A
+#define OV3640_ISP_YOUT_L                      0x308B
+#define OV3640_TMC13                           0x308D
+#define OV3640_5060                            0x308E
+#define OV3640_OTP                             0x308F
+
+#define OV3640_IO_CTRL0                                0x30B0
+#define OV3640_IO_CTRL1                                0x30B1
+#define OV3640_IO_CTRL2                                0x30B2
+#define OV3640_DVP0                            0x30B4
+#define OV3640_DVP1                            0x30B5
+#define OV3640_DVP2                            0x30B6
+#define OV3640_DVP3                            0x30B7
+#define OV3640_DSPC0                           0x30B8
+#define OV3640_DSPC1                           0x30B9
+#define OV3640_DSPC2                           0x30BA
+#define OV3640_DSPC3                           0x30BB
+#define OV3640_DSPC7                           0x30BF
+/*
+ * END - System Control Registers
+ */
+
+/*
+ * SC Registers
+ */
+#define OV3640_SC_CTRL0                                0x3100
+#define OV3640_SC_CTRL2                                0x3102
+#define OV3640_SC_SYN_CTRL0                    0x3104
+#define OV3640_SC_SYN_CTRL1                    0x3105
+#define OV3640_SC_SYN_CTRL2                    0x3106
+#define OV3640_SC_SYN_CTRL3                    0x3107
+/*
+ * END - SC Registers
+ */
+
+/*
+ * CIF Registers
+ */
+#define OV3640_CIF_CTRL0                       0x3200
+#define OV3640_CIF_CTRL4                       0x3204
+/*
+ * END - CIF Registers
+ */
+
+/*
+ * DSP Registers
+ */
+#define OV3640_DSP_CTRL_0                      0x3300
+#define OV3640_DSP_CTRL_1                      0x3301
+#define OV3640_DSP_CTRL_2                      0x3302
+#define OV3640_DSP_CTRL_4                      0x3304
+#define OV3640_AWB_CTRL_3                      0x3308
+
+#define OV3640_YST1                            0x331B
+#define OV3640_YST2                            0x331C
+#define OV3640_YST3                            0x331D
+#define OV3640_YST4                            0x331E
+#define OV3640_YST5                            0x331F
+
+#define OV3640_YST6                            0x3320
+#define OV3640_YST7                            0x3321
+#define OV3640_YST8                            0x3322
+#define OV3640_YST9                            0x3323
+#define OV3640_YST10                           0x3324
+#define OV3640_YST11                           0x3325
+#define OV3640_YST12                           0x3326
+#define OV3640_YST13                           0x3327
+#define OV3640_YST14                           0x3328
+#define OV3640_YST15                           0x3329
+#define OV3640_YSLP15                          0x332A
+#define OV3640_MISC_CTRL                       0x332B
+#define OV3640_DNS_TH                          0x332C
+#define OV3640_Y_EDGE_MT                       0x332D
+#define OV3640_Y_EDGE_TH_TM                    0x332E
+#define OV3640_BASE1                           0x332F
+
+#define OV3640_BASE2                           0x3330
+#define OV3640_OFFSET                          0x3331
+#define OV3640_CMXSIGN_MISC                    0x333F
+
+#define OV3640_CMX_1                           0x3340
+#define OV3640_CMX_2                           0x3341
+#define OV3640_CMX_3                           0x3342
+#define OV3640_CMX_4                           0x3343
+#define OV3640_CMX_5                           0x3344
+#define OV3640_CMX_6                           0x3345
+#define OV3640_CMX_7                           0x3346
+#define OV3640_CMX_8                           0x3347
+#define OV3640_CMX_9                           0x3348
+#define OV3640_CMXSIGN                         0x3349
+
+#define OV3640_SGNSET                          0x3354
+#define OV3640_SDE_CTRL                                0x3355
+#define OV3640_HUE_COS                         0x3356
+#define OV3640_HUE_SIN                         0x3357
+#define OV3640_SAT_U                           0x3358
+#define OV3640_SAT_V                           0x3359
+#define OV3640_UREG                            0x335A
+#define OV3640_VREG                            0x335B
+#define OV3640_YOFFSET                         0x335C
+#define OV3640_YGAIN                           0x335D
+#define OV3640_YBRIGHT                         0x335E
+#define OV3640_SIZE_IN_MISC                    0x335F
+
+#define OV3640_HSIZE_IN_L                      0x3360
+#define OV3640_VSIZE_IN_L                      0x3361
+#define OV3640_SIZE_OUT_MISC                   0x3362
+#define OV3640_HSIZE_OUT_L                     0x3363
+#define OV3640_VSIZE_OUT_L                     0x3364
+
+#define OV3640_R_XY0                           0x3367
+#define OV3640_R_X0                            0x3368
+#define OV3640_R_Y0                            0x3369
+#define OV3640_R_A1                            0x336A
+#define OV3640_R_A2_B2                         0x336B
+#define OV3640_R_B1                            0x336C
+#define OV3640_G_XY0                           0x336D
+#define OV3640_G_X0                            0x336E
+#define OV3640_G_Y0                            0x336F
+
+#define OV3640_G_A1                            0x3370
+#define OV3640_G_A2_B2                         0x3371
+#define OV3640_G_B1                            0x3372
+#define OV3640_B_XY0                           0x3373
+#define OV3640_B_X0                            0x3374
+#define OV3640_B_Y0                            0x3375
+#define OV3640_B_A1                            0x3376
+#define OV3640_B_A2_B2                         0x3377
+#define OV3640_B_B1                            0x3378
+
+#define OV3640_MISC_DCW_SIZE                   0x33A4
+#define OV3640_DCW_OH                          0x33A5
+#define OV3640_DCW_OV                          0x33A6
+#define OV3640_R_GAIN_M                                0x33A7
+#define OV3640_G_GAIN_M                                0x33A8
+#define OV3640_B_GAIN_M                                0x33A9
+#define OV3640_OVLY_MISC1                      0x33AA
+#define OV3640_OVLY_LEFT                       0x33AB
+#define OV3640_OVLY_TOP                                0x33AC
+#define OV3640_OVLY_MISC2                      0x33AD
+#define OV3640_OVLY_RIGHT                      0x33AE
+#define OV3640_OVLY_BOTTEM                     0x33AF
+
+#define OV3640_OVLY_MISC3                      0x33B0
+#define OV3640_OVLY_EXT_WIDTH_H                        0x33B1
+#define OV3640_OVLY_EXT_WIDTH_L                        0x33B2
+#define OV3640_OVLY_Y                          0x33B3
+#define OV3640_OVLY_U                          0x33B4
+#define OV3640_OVLY_V                          0x33B5
+/*
+ * END - DSP Registers
+ */
+
+/*
+ * FMT MUX Registers
+ */
+#define OV3640_FMT_MUX_CTRL0                   0x3400
+#define OV3640_ISP_PAD_CTR2                    0x3403
+#define OV3640_FMT_CTRL00                      0x3404
+#define OV3640_FMT_CTRL00_UV_sel_SHIFT         7
+#define OV3640_FMT_CTRL00_UV_sel_MASK          (0x1 << \
+                                               OV3640_FMT_CTRL00_UV_sel_SHIFT)
+#define OV3640_FMT_CTRL00_UV_sel_USE_UV_avg_Y  (0x0 << \
+                                               OV3640_FMT_CTRL00_UV_sel_SHIFT)
+#define OV3640_FMT_CTRL00_UV_sel_USE_U0Y0_V0Y1 (0x1 << \
+                                               OV3640_FMT_CTRL00_UV_sel_SHIFT)
+
+#define OV3640_FMT_CTRL00_YUV422_in_SHIFT      6
+#define OV3640_FMT_CTRL00_YUV422_in_MASK       (0x1 << \
+                                       OV3640_FMT_CTRL00_YUV422_in_SHIFT)
+#define OV3640_FMT_CTRL00_YUV422_in_DISABLE    (0x0 << \
+                                       OV3640_FMT_CTRL00_YUV422_in_SHIFT)
+#define OV3640_FMT_CTRL00_YUV422_in_ENABLE     (0x1 << \
+                                       OV3640_FMT_CTRL00_YUV422_in_SHIFT)
+
+#define OV3640_FMT_CTRL00_FMT_SHIFT            0
+#define OV3640_FMT_CTRL00_FMT_MASK             (0x3F << \
+                                               OV3640_FMT_CTRL00_FMT_SHIFT)
+#define OV3640_DITHER_CTRL0                    0x3405
+/*
+ * END - FMT MUX Registers
+ */
+
+/*
+ * OUT_TOP Registers
+ */
+#define OV3640_OUT_CTRL00                      0x3600
+#define OV3640_OUT_CTRL00_VSYNCSEL2            (1 << 7)
+#define OV3640_OUT_CTRL00_VSYNCGATE            (1 << 6)
+#define OV3640_OUT_CTRL00_PCLKPOL_NEG          (1 << 4)
+#define OV3640_OUT_CTRL00_HREFPOL_NEG          (1 << 3)
+#define OV3640_OUT_CTRL00_VSYNCPOL_NEG         (1 << 2)
+#define OV3640_OUT_CTRL00_VSYNCSEL             (1 << 1)
+#define OV3640_OUT_CTRL00_DVPOUTDATAORDERINV   1
+
+#define OV3640_OUT_CTRL01                      0x3601
+#define OV3640_OUT_CTRL01_PCLKGATEEN           (1 << 7)
+#define OV3640_OUT_CTRL01_CCIR656EN            (1 << 4)
+#define OV3640_OUT_CTRL01_MIPIBIT8             1
+
+#define OV3640_MIPI_CTRL02                     0x3602
+#define OV3640_MIPI_CTRL02_DVPDISABLE          (1 << 4)
+#define OV3640_MIPI_CTRL02_MIPILINESYNCEN      (1 << 2)
+#define OV3640_MIPI_CTRL02_MIPIGATESCEN                (1 << 1)
+
+#define OV3640_MIPI_CTRL03                     0x3603
+#define OV3640_MIPI_CTRL03_ECC_PHBYTEORDER     (1 << 2)
+#define OV3640_MIPI_CTRL03_ECC_PHBITORDER      (1 << 1)
+
+#define OV3640_OUT_CTRL08                      0x3608
+#define OV3640_OUT_CTRL08_HREF_DLY_SHIFT       4
+#define OV3640_OUT_CTRL08_HREF_DLY_MASK                (0xF << \
+                                       OV3640_OUT_CTRL08_HREF_DLY_SHIFT)
+
+
+#define OV3640_OUT_CTRL09                      0x3609
+#define OV3640_OUT_CTRL0A                      0x360A
+#define OV3640_OUT_CTRL0B                      0x360B
+#define OV3640_MIPI_CTRL0C                     0x360C
+#define OV3640_MIPI_CTRL0C_VIRTUALCH_ID_MASK   (0x3 << 6)
+
+#define OV3640_OUT_CTRL0D                      0x360D
+#define OV3640_MIPI_CTRL0E                     0x360E
+#define OV3640_MIPI_CTRL0E_WKUPDELAY_MASK      0x3F
+
+
+#define OV3640_MIPI_CTRL10                     0x3610
+#define OV3640_MIPI_CTRL10_WIDTH_MAN_L_MASK    0xFF
+
+#define OV3640_MIPI_CTRL11                     0x3611
+#define OV3640_MIPI_CTRL11_WIDTH_MAN_H_MASK    (0x7 << 5)
+
+#define OV3640_CLIP_MIN                                0x3614
+#define OV3640_CLIP_MAX                                0x3615
+#define OV3640_OUT_CTRL16                      0x3616
+#define OV3640_OUT_CTRL1D                      0x361D
+#define OV3640_OUT_CTRL1E                      0x361E
+#define OV3640_MIPI_CTRL1F                     0x361F
+#define OV3640_MIPI_CTRL1F_PCLK_PERIOD_MASK    0xFF
+
+#define OV3640_MIPI_CTRL22                     0x3622
+#define OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_SHIFT       2
+#define OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_MASK                (0x3F << \
+                               OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_SHIFT)
+#define OV3640_MIPI_CTRL22_MIN_HS_ZERO_H_MASK  0x3
+
+#define OV3640_MIPI_CTRL23                     0x3623
+#define OV3640_MIPI_CTRL23_MIN_HS_ZERO_L_MASK  0xFF
+
+#define OV3640_MIPI_CTRL24                     0x3624
+#define OV3640_MIPI_CTRL24_MIN_HS_TRAIL_NUI_SHIFT      2
+#define OV3640_MIPI_CTRL24_MIN_HS_TRAIL_NUI_MASK       (0x3F << \
+                               OV3640_MIPI_CTRL24_MIN_HS_TRAIL_NUI_SHIFT)
+#define OV3640_MIPI_CTRL24_MIN_HS_TRAIL_H_MASK 0x3
+
+#define OV3640_MIPI_CTRL25                     0x3625
+#define OV3640_MIPI_CTRL25_MIN_HS_TRAIL_L_MASK 0xFF
+
+#define OV3640_MIPI_CTRL26                     0x3626
+#define OV3640_MIPI_CTRL26_MIN_CLK_ZERO_NUI_SHIFT      2
+#define OV3640_MIPI_CTRL26_MIN_CLK_ZERO_NUI_MASK       (0x3F << \
+                               OV3640_MIPI_CTRL26_MIN_CLK_ZERO_NUI_SHIFT)
+#define OV3640_MIPI_CTRL26_MIN_CLK_ZERO_H_MASK 0x3
+
+#define OV3640_MIPI_CTRL27                     0x3627
+#define OV3640_MIPI_CTRL27_MIN_CLK_ZERO_L_MASK 0xFF
+
+#define OV3640_MIPI_CTRL28                     0x3628
+#define OV3640_MIPI_CTRL28_MIN_CLK_PREPARE_NUI_SHIFT   2
+#define OV3640_MIPI_CTRL28_MIN_CLK_PREPARE_NUI_MASK            (0x3F << \
+                               OV3640_MIPI_CTRL28_MIN_CLK_PREPARE_NUI_SHIFT)
+#define OV3640_MIPI_CTRL28_MIN_CLK_PREPARE_H_MASK      0x3
+
+#define OV3640_MIPI_CTRL29                     0x3629
+#define OV3640_MIPI_CTRL29_MIN_CLK_PREPARE_L_MASK      0xFF
+
+#define OV3640_MIPI_CTRL2A                     0x362A
+#define OV3640_MIPI_CTRL2A_MAX_CLK_PREPARE_NUI_SHIFT   2
+#define OV3640_MIPI_CTRL2A_MAX_CLK_PREPARE_NUI_MASK            (0x3F << \
+                               OV3640_MIPI_CTRL2A_MAX_CLK_PREPARE_NUI_SHIFT)
+#define OV3640_MIPI_CTRL2A_MAX_CLK_PREPARE_H_MASK      0x3
+
+#define OV3640_MIPI_CTRL2B                     0x362B
+#define OV3640_MIPI_CTRL2B_MAX_CLK_PREPARE_L_MASK      0xFF
+
+#define OV3640_MIPI_CTRL2C                     0x362C
+#define OV3640_MIPI_CTRL2C_MIN_CLK_POST_NUI_SHIFT      2
+#define OV3640_MIPI_CTRL2C_MIN_CLK_POST_NUI_MASK       (0x3F << \
+                               OV3640_MIPI_CTRL2C_MIN_CLK_POST_NUI_SHIFT)
+#define OV3640_MIPI_CTRL2C_MIN_CLK_POST_H_MASK 0x3
+
+#define OV3640_MIPI_CTRL2D                     0x362D
+#define OV3640_MIPI_CTRL2D_MIN_CLK_POST_L_MASK 0xFF
+
+#define OV3640_MIPI_CTRL2E                     0x362E
+#define OV3640_MIPI_CTRL2E_MIN_CLK_TRAIL_NUI_SHIFT     2
+#define OV3640_MIPI_CTRL2E_MIN_CLK_TRAIL_NUI_MASK      (0x3F << \
+                               OV3640_MIPI_CTRL2E_MIN_CLK_TRAIL_NUI_SHIFT)
+#define OV3640_MIPI_CTRL2E_MIN_CLK_TRAIL_H_MASK        0x3
+
+#define OV3640_MIPI_CTRL2F                     0x362F
+#define OV3640_MIPI_CTRL2F_MIN_CLK_TRAIL_L_MASK        0xFF
+
+#define OV3640_MIPI_CTRL30                     0x3630
+#define OV3640_MIPI_CTRL30_MIN_LPX_P_NUI_SHIFT 2
+#define OV3640_MIPI_CTRL30_MIN_LPX_P_NUI_MASK  (0x3F << \
+                                       OV3640_MIPI_CTRL30_MIN_LPX_P_NUI_SHIFT)
+#define OV3640_MIPI_CTRL30_MIN_LPX_P_H_MASK    0x3
+
+#define OV3640_MIPI_CTRL31                     0x3631
+#define OV3640_MIPI_CTRL31_MIN_LPX_P_L_MASK    0xFF
+
+#define OV3640_MIPI_CTRL32                     0x3632
+#define OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_SHIFT    2
+#define OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_MASK     (0x3F << \
+                               OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_SHIFT)
+#define OV3640_MIPI_CTRL32_MIN_HS_PREPARE_H_MASK       0x3
+
+#define OV3640_MIPI_CTRL33                     0x3633
+#define OV3640_MIPI_CTRL33_MIN_HS_PREPARE_L_MASK       0xFF
+
+#define OV3640_MIPI_CTRL34                     0x3634
+#define OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_SHIFT    2
+#define OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_MASK     (0x3F << \
+                               OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_SHIFT)
+#define OV3640_MIPI_CTRL34_MAX_HS_PREPARE_H_MASK       0x3
+
+#define OV3640_MIPI_CTRL35                     0x3635
+#define OV3640_MIPI_CTRL35_MAX_HS_PREPARE_L_MASK       0xFF
+
+#define OV3640_MIPI_CTRL36                     0x3636
+#define OV3640_MIPI_CTRL36_MIN_HS_EXIT_NUI_SHIFT       2
+#define OV3640_MIPI_CTRL36_MIN_HS_EXIT_NUI_MASK        (0x3F << \
+                               OV3640_MIPI_CTRL36_MIN_HS_EXIT_NUI_SHIFT)
+#define OV3640_MIPI_CTRL36_MIN_HS_EXIT_H_MASK  0x3
+
+#define OV3640_MIPI_CTRL37                     0x3637
+#define OV3640_MIPI_CTRL37_MIN_HS_EXIT_L_MASK  0xFF
+
+#define OV3640_OUT_CTRL3C                      0x363C
+#define OV3640_MIPI_CTRL3D                     0x363D
+#define OV3640_MIPI_CTRL3D_JPGPADEN            (1 << 6)
+#define OV3640_OUT_CTRL3E                      0x363E
+#define OV3640_OUT_CTRL3F                      0x363F
+
+#define OV3640_OUT_CTRL40                      0x3640
+#define OV3640_OUT_CTRL43                      0x3643
+#define OV3640_OUT_CTRL44                      0x3644
+#define OV3640_OUT_CTRL46                      0x3646
+#define OV3640_MIPI_CTRL4C                     0x364C
+#define OV3640_MIPI_CTRL4C_ECC_PHBYTEORDER2    (1 << 2)
+/*
+ * END - OUT_TOP Registers
+ */
+/*
+ * MC Registers
+ */
+#define OV3640_INTR_MASK0                      0x3700
+#define OV3640_INTR_MASK1                      0x3701
+#define OV3640_INTR0                           0x3708
+#define OV3640_INTR1                           0x3709
+/*
+ * END - MC Registers
+ */
+
+#endif /* ifndef OV3640_REGS_H */
+
+
diff --git a/include/media/ov3640.h b/include/media/ov3640.h
new file mode 100644
index 0000000..a26009e
--- /dev/null
+++ b/include/media/ov3640.h
@@ -0,0 +1,31 @@
+/*
+ * include/media/ov3640.h
+ *
+ * Shared settings for the OV3640 CameraChip.
+ *
+ * Contributors:
+ *   Pallavi Kulkarni <p-kulkarni@ti.com>
+ *   Sergio Aguirre <saaguirre@ti.com>
+ *
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef OV3640_H
+#define OV3640_H
+
+#define OV3640_I2C_ADDR                (0x78 >> 1)
+
+struct ov3640_platform_data {
+       /* Set power state, zero is off, non-zero is on. */
+       int (*power_set)(enum v4l2_power power);
+       u32 (*set_xclk)(u32 xclkfreq);
+       int (*priv_data_set)(void *);
+};
+
+#endif /* ifndef OV3640_H */
+
+
--
1.5.6.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/5] OV3640: Add driver
  2009-03-03 20:44 [PATCH 3/5] OV3640: Add driver Aguirre Rodriguez, Sergio Alberto
@ 2009-03-05  0:23 ` Alexey Klimov
  2009-03-09 20:58   ` Aguirre Rodriguez, Sergio Alberto
  2009-03-05  1:42 ` Trent Piepho
  1 sibling, 1 reply; 8+ messages in thread
From: Alexey Klimov @ 2009-03-05  0:23 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: linux-media, linux-omap, Sakari Ailus, Tuukka.O Toivonen,
	Hiroshi DOYU, DongSoo(Nathaniel) Kim, MiaoStanley, Nagalla, Hari,
	Hiremath, Vaibhav, Lakhani, Amish, Menon, Nishanth

On Tue, 2009-03-03 at 14:44 -0600, Aguirre Rodriguez, Sergio Alberto
wrote:
> This driver has been currently being tested with:
>  - OMAP3430SDP platform, working in Parallel and CSI2 modes.
>  - OMAPZOOM (LDP) platform, working in CSI2 mode.
> 
> Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
> ---
>  drivers/media/video/Kconfig       |   15 +
>  drivers/media/video/Makefile      |    1 +
>  drivers/media/video/ov3640.c      | 2202 +++++++++++++++++++++++++++++++++++++
>  drivers/media/video/ov3640_regs.h |  600 ++++++++++
>  include/media/ov3640.h            |   31 +
>  5 files changed, 2849 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/video/ov3640.c
>  create mode 100644 drivers/media/video/ov3640_regs.h
>  create mode 100644 include/media/ov3640.h
> 
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index 225d9cf..e99c93f 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -321,6 +321,21 @@ config VIDEO_DW9710
>           DW9710 coil.  It is currently working with the TI OMAP3
>           camera controller and micron MT9P012 sensor.
> 
> +config VIDEO_OV3640
> +       tristate "OmniVision ov3640 smart sensor driver (3MP)"
> +       depends on I2C && VIDEO_V4L2
> +       ---help---
> +         This is a Video4Linux2 sensor-level driver for the OmniVision
> +         OV3640 camera.  It is currently working with the TI OMAP3
> +          camera controller.
> +
> +config VIDEO_OV3640_CSI2
> +       bool "CSI2 bus support for OmniVision ov3640 sensor"
> +       depends on I2C && VIDEO_V4L2 && VIDEO_OV3640
> +       ---help---
> +         This enables the use of the CSI2 serial bus for the ov3640
> +         camera.
> +
>  config VIDEO_SAA7110
>         tristate "Philips SAA7110 video decoder"
>         depends on VIDEO_V4L1 && I2C
> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
> index 52a34d9..33b3976 100644
> --- a/drivers/media/video/Makefile
> +++ b/drivers/media/video/Makefile
> @@ -113,6 +113,7 @@ obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o
>  obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
>  obj-$(CONFIG_VIDEO_MT9P012)     += mt9p012.o
>  obj-$(CONFIG_VIDEO_DW9710)     += dw9710.o
> +obj-$(CONFIG_VIDEO_OV3640)     += ov3640.o
> 
>  obj-$(CONFIG_USB_DABUSB)        += dabusb.o
>  obj-$(CONFIG_USB_OV511)         += ov511.o
> diff --git a/drivers/media/video/ov3640.c b/drivers/media/video/ov3640.c
> new file mode 100644
> index 0000000..9f5cb13
> --- /dev/null
> +++ b/drivers/media/video/ov3640.c
> @@ -0,0 +1,2202 @@
> +/*
> + * drivers/media/video/ov3640.c
> + *
> + * ov3640 sensor driver
> + *
> + *
> + * Copyright (C) 2008 Texas Instruments.

2009 ?

> + *
> + * Leverage ov3640.c
> + *
> + * 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/i2c.h>
> +#include <linux/delay.h>
> +#include <media/v4l2-int-device.h>
> +#include <media/ov3640.h>
> +#include "ov3640_regs.h"
> +#include "omap34xxcam.h"
> +#include "isp/ispcsi2.h"
> +
> +#define OV3640_DRIVER_NAME  "ov3640"
> +#define MOD_NAME "OV3640: "
> +
> +#define I2C_M_WR 0
> +
> +/* Register initialization tables for ov3640 */
> +/* Terminating list entry for reg */
> +#define OV3640_REG_TERM                0xFFFF
> +/* Terminating list entry for val */
> +#define OV3640_VAL_TERM                0xFF
> +
> +#define OV3640_USE_XCLKA       0
> +#define OV3640_USE_XCLKB       1
> +
> +#define OV3640_CSI2_VIRTUAL_ID 0x1
> +
> +/* FPS Capabilities */
> +#define OV3640_MIN_FPS                 5
> +#define OV3640_DEF_FPS                 15
> +#define OV3640_MAX_FPS                 30
> +
> +#define OV3640_MIN_BRIGHT              0
> +#define OV3640_MAX_BRIGHT              6
> +#define OV3640_DEF_BRIGHT              0
> +#define OV3640_BRIGHT_STEP             1
> +
> +#define OV3640_DEF_CONTRAST            0
> +#define OV3640_MIN_CONTRAST            0
> +#define OV3640_MAX_CONTRAST            6
> +#define OV3640_CONTRAST_STEP           1
> +
> +#define OV3640_DEF_COLOR               0
> +#define OV3640_MIN_COLOR               0
> +#define OV3640_MAX_COLOR               2
> +#define OV3640_COLOR_STEP              1
> +
> +#define SENSOR_DETECTED                1
> +#define SENSOR_NOT_DETECTED    0
> +
> +/* NOTE: Set this as 0 for enabling SoC mode */
> +#define OV3640_RAW_MODE        1
> +
> +/* XCLK Frequency in Hz*/
> +#define OV3640_XCLK_MIN                24000000
> +#define OV3640_XCLK_MAX                24000000
> +
> +
> +/* High byte of product ID */
> +#define OV3640_PIDH_MAGIC      0x36
> +/* Low byte of product ID  */
> +#define OV3640_PIDL_MAGIC1     0x41
> +#define OV3640_PIDL_MAGIC2     0x4C
> +
> +/* define a structure for ov3640 register initialization values */
> +struct ov3640_reg {
> +       unsigned int reg;
> +       unsigned char val;
> +};
> +
> +enum image_size_ov {
> +       XGA,
> +       QXGA
> +};
> +enum pixel_format_ov {
> +       YUV,
> +       RGB565,
> +       RGB555,
> +       RAW10
> +};
> +
> +#define OV_NUM_IMAGE_SIZES             2
> +#define OV_NUM_PIXEL_FORMATS           4
> +#define OV_NUM_FPS                     3
> +
> +struct capture_size_ov {
> +       unsigned long width;
> +       unsigned long height;
> +};
> +
> +const static struct ov3640_reg ov3640_common[2][100] = {
> +       /* XGA_Default settings */
> +       {
> +               {OV3640_AEC_H, 0x03},
> +               {OV3640_AEC_L, 0x0F},
> +               {OV3640_AGC_L, 0x07},
> +               {0x304d, 0x45},
> +               {0x30aa, 0x45},
> +               {OV3640_IO_CTRL1, 0xff},
> +               {OV3640_IO_CTRL2, 0x10},
> +               {OV3640_WPT_HISH, 0x38},
> +               {OV3640_BPT_HISL, 0x30},
> +               {OV3640_VPT, 0x61},
> +               {0x3082, 0x20},
> +               {OV3640_AUTO_3, OV3640_AUTO_3_DUMMYFC_1FRAME |
> +                                               OV3640_AUTO_3_AGCGAINCEIL_32X},
> +               {OV3640_AUTO_1, OV3640_AUTO_1_FASTAEC |
> +                                       OV3640_AUTO_1_AECBIGSTEPS |
> +                                       OV3640_AUTO_1_BANDINGFILTEREN |
> +                                       OV3640_AUTO_1_AUTOBANDINGFILTER |
> +                                       OV3640_AUTO_1_EXTRBRIGHTEXPEN
> +#if (OV3640_RAW_MODE == 0)
> +                                       | OV3640_AUTO_1_AGCEN
> +                                       | OV3640_AUTO_1_AECEN
> +#endif
> +                                       },
> +               {OV3640_AHW_H, 0x08},
> +               {OV3640_AHW_L, 0x18},
> +               {OV3640_AVH_H, 0x06},
> +               {OV3640_AVH_L, 0x0c},
> +               {OV3640_WEIGHT0, 0x62},
> +               {OV3640_WEIGHT1, 0x26},
> +               {OV3640_WEIGHT2, 0xe6},
> +               {OV3640_WEIGHT3, 0x6e},
> +               {OV3640_WEIGHT4, 0xea},
> +               {OV3640_WEIGHT5, 0xae},
> +               {OV3640_WEIGHT6, 0xa6},
> +               {OV3640_WEIGHT7, 0x6a},
> +               {OV3640_SC_SYN_CTRL0, 0x02},
> +               {OV3640_SC_SYN_CTRL1, 0xfd},
> +               {OV3640_SC_SYN_CTRL2, 0x00},
> +               {OV3640_SC_SYN_CTRL3, 0xff},
> +               {OV3640_DSP_CTRL_0, 0x13},
> +               {OV3640_DSP_CTRL_1, 0xde},
> +               {OV3640_DSP_CTRL_2, 0xef},
> +               {0x3316, 0xff},
> +               {0x3317, 0x00},
> +               {0x3312, 0x26},
> +               {0x3314, 0x42},
> +               {0x3313, 0x2b},
> +               {0x3315, 0x42},
> +               {0x3310, 0xd0},
> +               {0x3311, 0xbd},
> +               {0x330c, 0x18},
> +               {0x330d, 0x18},
> +               {0x330e, 0x56},
> +               {0x330f, 0x5c},
> +               {0x330b, 0x1c},
> +               {0x3306, 0x5c},
> +               {0x3307, 0x11},
> +               {OV3640_R_A1, 0x52},
> +               {OV3640_G_A1, 0x46},
> +               {OV3640_B_A1, 0x38},
> +               {OV3640_DSPC0, 0x20},
> +               {OV3640_DSPC1, 0x17},
> +               {OV3640_DSPC2, 0x04},
> +               {OV3640_DSPC3, 0x08},
> +               {0x3507, 0x06},
> +               {0x350a, 0x4f},
> +               {OV3640_SC_CTRL0, 0x02},
> +               {OV3640_DSP_CTRL_1, 0xde},
> +               {OV3640_DSP_CTRL_4, 0xfc},
> +               {OV3640_SYS, OV3640_SYS_BASERES_XGA},
> +               {OV3640_VS_L, 0x06 + 1},
> +               {OV3640_VH_H, 0x03},
> +               {OV3640_VH_L, 0x04},
> +               {OV3640_VSYNCOPT, 0x24},
> +               {OV3640_PCLK, OV3640_PCLK_DIVBY2},
> +               {0x30d7, 0x90},
> +               {OV3640_SIZE_IN_MISC, 0x34},
> +               {OV3640_HSIZE_IN_L, 0x0c},
> +               {OV3640_VSIZE_IN_L, 0x04},
> +               {OV3640_SIZE_OUT_MISC, 0x34},
> +               {OV3640_HSIZE_OUT_L, 0x08},
> +               {OV3640_VSIZE_OUT_L, 0x04},
> +               {OV3640_ISP_PAD_CTR2, 0x42},
> +               {OV3640_ISP_XOUT_H, 0x04},
> +               {OV3640_ISP_XOUT_L, 0x00},
> +               {OV3640_ISP_YOUT_H, 0x03},
> +               {OV3640_ISP_YOUT_L, 0x00},
> +               {OV3640_TMC13, 0x04},
> +               {OV3640_OUT_CTRL00, OV3640_OUT_CTRL00_VSYNCSEL2 |
> +                                       OV3640_OUT_CTRL00_VSYNCGATE |
> +                                       OV3640_OUT_CTRL00_VSYNCPOL_NEG},
> +               {OV3640_MISC_CTRL, 0x00},
> +               {OV3640_Y_EDGE_MT, 0x60},
> +               {OV3640_BASE1, 0x03},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* QXGA Default settings */
> +       {
> +               {OV3640_AEC_H, 0x06},
> +               {OV3640_AEC_L, 0x1F},
> +               {OV3640_AGC_L, 0x12},
> +               {0x304d, 0x45},
> +               {0x30aa, 0x45},
> +               {OV3640_IO_CTRL0, 0xff},
> +               {OV3640_IO_CTRL1, 0xff},
> +               {OV3640_IO_CTRL2, 0x10},
> +               {0x30d7, 0x10},
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x60},
> +               {OV3640_BPT_HISL, 0x58},
> +               {OV3640_VPT, 0xa1},
> +               {OV3640_TMC11, 0x02},
> +               {0x3082, 0x20},
> +               {OV3640_AHW_H, 0x08},
> +               {OV3640_AHW_L, 0x18},
> +               {OV3640_AVH_H, 0x06},
> +               {OV3640_AVH_L, 0x0c},
> +               {OV3640_WEIGHT0, 0x62},
> +               {OV3640_WEIGHT1, 0x26},
> +               {OV3640_WEIGHT2, 0xe6},
> +               {OV3640_WEIGHT3, 0x6e},
> +               {OV3640_WEIGHT4, 0xea},
> +               {OV3640_WEIGHT5, 0xae},
> +               {OV3640_WEIGHT6, 0xa6},
> +               {OV3640_WEIGHT7, 0x6a},
> +               {OV3640_AUTO_3, OV3640_AUTO_3_DUMMYFC_1FRAME |
> +                                               OV3640_AUTO_3_AGCGAINCEIL_8X},
> +               {OV3640_AUTO_1, OV3640_AUTO_1_FASTAEC |
> +                                       OV3640_AUTO_1_AECBIGSTEPS |
> +                                       OV3640_AUTO_1_BANDINGFILTEREN |
> +                                       OV3640_AUTO_1_AUTOBANDINGFILTER |
> +                                       OV3640_AUTO_1_EXTRBRIGHTEXPEN
> +#if (OV3640_RAW_MODE == 0)
> +                                       | OV3640_AUTO_1_AGCEN
> +                                       | OV3640_AUTO_1_AECEN
> +#endif
> +                                       },
> +               {OV3640_SC_SYN_CTRL0, 0x02},
> +               {OV3640_SC_SYN_CTRL1, 0xfd},
> +               {OV3640_SC_SYN_CTRL2, 0x00},
> +               {OV3640_SC_SYN_CTRL3, 0xff},
> +               {OV3640_AWB_CTRL_3, 0xa5},
> +               {0x3316, 0xff},
> +               {0x3317, 0x00},
> +               {OV3640_TMC11, 0x02},
> +               {0x3082, 0x20},
> +               {OV3640_DSP_CTRL_0, 0x13},
> +               {OV3640_DSP_CTRL_1, 0xd6},
> +               {OV3640_DSP_CTRL_2, 0xef},
> +               {OV3640_DSPC0, 0x20},
> +               {OV3640_DSPC1, 0x17},
> +               {OV3640_DSPC2, 0x04},
> +               {OV3640_DSPC3, 0x08},
> +               {OV3640_HS_H, 0x01},
> +               {OV3640_HS_L, 0x1d},
> +               {OV3640_VS_H, 0x00},
> +               {OV3640_VS_L, 0x0a + 1},
> +               {OV3640_HW_H, 0x08},
> +               {OV3640_HW_L, 0x18},
> +               {OV3640_VH_H, 0x06},
> +               {OV3640_VH_L, 0x0c},
> +               {OV3640_SIZE_IN_MISC, 0x68},
> +               {OV3640_HSIZE_IN_L, 0x18},
> +               {OV3640_VSIZE_IN_L, 0x0c},
> +               {OV3640_SIZE_OUT_MISC, 0x68},
> +               {OV3640_HSIZE_OUT_L, 0x08},
> +               {OV3640_VSIZE_OUT_L, 0x04},
> +               {OV3640_ISP_PAD_CTR2, 0x42},
> +               {OV3640_ISP_XOUT_H, 0x08},
> +               {OV3640_ISP_XOUT_L, 0x00},
> +               {OV3640_ISP_YOUT_H, 0x06},
> +               {OV3640_ISP_YOUT_L, 0x00},
> +               {0x3507, 0x06},
> +               {0x350a, 0x4f},
> +               {OV3640_OUT_CTRL00, 0xc4},
> +               /* Light Mode - Auto */
> +               {OV3640_MISC_CTRL, 0x00},
> +               /* Sharpness - Level 5 */
> +               {OV3640_Y_EDGE_MT, 0x45},
> +               /* Sharpness - Auto */
> +               {OV3640_Y_EDGE_MT, 0x60},
> +               {OV3640_BASE1, 0x03},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +};
> +
> +const static struct ov3640_reg ov3640_common_csi2[] = {
> +       /* NM OUT_CONTROL2 SOL/EOL off */
> +       {OV3640_MIPI_CTRL02, 0x22},
> +       /* NM OUT_CONTROL1E h_sel? */
> +       {OV3640_OUT_CTRL1E, 0x00},
> +       /* min_hs_zero: 6UI + 105ns */
> +       {OV3640_MIPI_CTRL22, ((6 & 0x3F) << 2) | ((105 & 0x300) >> 8)},
> +       {OV3640_MIPI_CTRL23, (105 & 0xFF)},
> +       /* min_clk_zero: 240ns */
> +       {OV3640_MIPI_CTRL26, ((0 & 0x3F) << 2) | ((240 & 0x300) >> 8)},
> +       {OV3640_MIPI_CTRL27, (240 & 0xFF)},
> +       /* min_clk_prepare: 38ns */
> +       {OV3640_MIPI_CTRL28, ((0 & 0x3F) << 2) | ((38 & 0x300) >> 8)},
> +       {OV3640_MIPI_CTRL29, (38 & 0xFF)},
> +       /* max_clk_prepare: 95ns */
> +       {OV3640_MIPI_CTRL2A, ((0 & 0x3F) << 2) | ((95 & 0x300) >> 8)},
> +       {OV3640_MIPI_CTRL2B, (95 & 0xFF)},
> +       /* min_clk_post: 52UI + 60ns */
> +       {OV3640_MIPI_CTRL2C, ((52 & 0x3F) << 2) | ((60 & 0x300) >> 8)},
> +       {OV3640_MIPI_CTRL2D, (60 & 0xFF)},
> +       /* min_hs_prepare: 4UI + 40ns */
> +       {OV3640_MIPI_CTRL32, ((4 & 0x3F) << 2) | ((40 & 0x300) >> 8)},
> +       {OV3640_MIPI_CTRL33, (40 & 0xFF)},
> +       /* ph_byte_order {DI,WC_h,WC_l} */
> +       {OV3640_MIPI_CTRL03, 0x49 | OV3640_MIPI_CTRL03_ECC_PHBYTEORDER},
> +       /* ph_byte_order2 ph={WC,DI} */
> +       {OV3640_MIPI_CTRL4C, OV3640_MIPI_CTRL4C_ECC_PHBYTEORDER2},
> +       {0x309e, 0x00},
> +       {OV3640_REG_TERM, OV3640_VAL_TERM},
> +};
> +
> +/* Array of image sizes supported by OV3640.  These must be ordered from
> + * smallest image size to largest.
> + */
> +const static struct capture_size_ov ov3640_sizes[] = {
> +       /* XGA */
> +       { 1024, 768 },
> +       /* QXGA */
> +       { 2048, 1536 },
> +};
> +
> +/**
> + * struct ov3640_sensor - main structure for storage of sensor information
> + * @pdata: access functions and data for platform level information
> + * @v4l2_int_device: V4L2 device structure structure
> + * @i2c_client: iic client device structure
> + * @pix: V4L2 pixel format information structure
> + * @timeperframe: time per frame expressed as V4L fraction
> + * @isize: base image size
> + * @ver: ov3640 chip version
> + * @width: configured width
> + * @height: configuredheight
> + * @vsize: vertical size for the image
> + * @hsize: horizontal size for the image
> + * @crop_rect: crop rectangle specifying the left,top and width and height
> + */
> +struct ov3640_sensor {
> +       const struct ov3640_platform_data *pdata;
> +       struct v4l2_int_device *v4l2_int_device;
> +       struct i2c_client *i2c_client;
> +       struct v4l2_pix_format pix;
> +       struct v4l2_fract timeperframe;
> +       int isize;
> +       int ver;
> +       int fps;
> +       unsigned long width;
> +       unsigned long height;
> +       unsigned long vsize;
> +       unsigned long hsize;
> +       struct v4l2_rect crop_rect;
> +       int state;
> +};
> +
> +static struct ov3640_sensor ov3640;
> +static struct i2c_driver ov3640sensor_i2c_driver;
> +static unsigned long xclk_current = OV3640_XCLK_MIN;
> +
> +/* List of image formats supported by OV3640 sensor */
> +const static struct v4l2_fmtdesc ov3640_formats[] = {
> +#if OV3640_RAW_MODE
> +       {
> +               .description    = "RAW10",
> +               .pixelformat    = V4L2_PIX_FMT_SGRBG10,
> +       },
> +#else
> +       {
> +               /* 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,
> +       },
> +#endif
> +};
> +
> +#define NUM_CAPTURE_FORMATS (sizeof(ov3640_formats) / sizeof(ov3640_formats[0]))
> +
> +/* register initialization tables for ov3640 */
> +#define OV3640_REG_TERM 0xFFFF /* terminating list entry for reg */
> +#define OV3640_VAL_TERM 0xFF   /* terminating list entry for val */
> +
> +const static struct ov3640_reg ov3640_out_xga[] = {
> +       {OV3640_ISP_XOUT_H, 0x04},  /* ISP_XOUT */
> +       {OV3640_ISP_XOUT_L, 0x00},  /* ISP_XOUT */
> +       {OV3640_ISP_YOUT_H, 0x03},  /* ISP_YOUT */
> +       {OV3640_ISP_YOUT_L, 0x00},  /* ISP_YOUT */
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +const static struct ov3640_reg ov3640_out_qxga[] = {
> +       {OV3640_ISP_XOUT_H, 0x08},  /* ISP_XOUT */
> +       {OV3640_ISP_XOUT_L, 0x00},  /* ISP_XOUT */
> +       {OV3640_ISP_YOUT_H, 0x06},  /* ISP_YOUT */
> +       {OV3640_ISP_YOUT_L, 0x00},  /* ISP_YOUT */
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +/* Brightness Settings - 7 levels */
> +const static struct ov3640_reg brightness[7][5] = {
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_SGNSET, 0x09},
> +               {OV3640_YBRIGHT, 0x30},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_SGNSET, 0x09},
> +               {OV3640_YBRIGHT, 0x20},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_SGNSET, 0x09},
> +               {OV3640_YBRIGHT, 0x10},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_SGNSET, 0x01},
> +               {OV3640_YBRIGHT, 0x00},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_SGNSET, 0x01},
> +               {OV3640_YBRIGHT, 0x10},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_SGNSET, 0x01},
> +               {OV3640_YBRIGHT, 0x20},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_SGNSET, 0x01},
> +               {OV3640_YBRIGHT, 0x30},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +};
> +
> +/* Contrast Settings - 7 levels */
> +const static struct ov3640_reg contrast[7][5] = {
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_YOFFSET, 0x14},
> +               {OV3640_YGAIN, 0x14},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_YOFFSET, 0x18},
> +               {OV3640_YGAIN, 0x18},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_YOFFSET, 0x1c},
> +               {OV3640_YGAIN, 0x1c},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_YOFFSET, 0x20},
> +               {OV3640_YGAIN, 0x20},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_YOFFSET, 0x24},
> +               {OV3640_YGAIN, 0x24},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_YOFFSET, 0x28},
> +               {OV3640_YGAIN, 0x28},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x04},
> +               {OV3640_YOFFSET, 0x2c},
> +               {OV3640_YGAIN, 0x2c},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +};
> +
> +/* Color Settings - 3 colors */
> +const static struct ov3640_reg colors[3][5] = {
> +       {
> +               {OV3640_SDE_CTRL, 0x00},
> +               {OV3640_UREG, 0x80},
> +               {OV3640_VREG, 0x80},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x18},
> +               {OV3640_UREG, 0x40},
> +               {OV3640_VREG, 0xa6},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       {
> +               {OV3640_SDE_CTRL, 0x18},
> +               {OV3640_UREG, 0x80},
> +               {OV3640_VREG, 0x80},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +};
> +
> +/* Average Based Algorithm - Based on target Luminance */
> +const static struct ov3640_reg exposure_avg[11][5] = {
> +       /* -1.7EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x10},
> +               {OV3640_BPT_HISL, 0x08},
> +               {OV3640_VPT, 0x21},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* -1.3EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x18},
> +               {OV3640_BPT_HISL, 0x10},
> +               {OV3640_VPT, 0x31},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* -1.0EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x20},
> +               {OV3640_BPT_HISL, 0x18},
> +               {OV3640_VPT, 0x41},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* -0.7EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x28},
> +               {OV3640_BPT_HISL, 0x20},
> +               {OV3640_VPT, 0x51},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* -0.3EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x30},
> +               {OV3640_BPT_HISL, 0x28},
> +               {OV3640_VPT, 0x61},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* default */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x38},
> +               {OV3640_BPT_HISL, 0x30},
> +               {OV3640_VPT, 0x61},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 0.3EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x40},
> +               {OV3640_BPT_HISL, 0x38},
> +               {OV3640_VPT, 0x71},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 0.7EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x48},
> +               {OV3640_BPT_HISL, 0x40},
> +               {OV3640_VPT, 0x81},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 1.0EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x50},
> +               {OV3640_BPT_HISL, 0x48},
> +               {OV3640_VPT, 0x91},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 1.3EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x58},
> +               {OV3640_BPT_HISL, 0x50},
> +               {OV3640_VPT, 0x91},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 1.7EV */
> +       {
> +               {OV3640_HISTO7, 0x00},
> +               {OV3640_WPT_HISH, 0x60},
> +               {OV3640_BPT_HISL, 0x58},
> +               {OV3640_VPT, 0xa1},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +};
> +
> +/* Histogram Based Algorithm - Based on histogram and probability */
> +const static struct ov3640_reg exposure_hist[11][5] = {
> +       /* -1.7EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0x58},
> +               {OV3640_BPT_HISL, 0x38},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* -1.3EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0x60},
> +               {OV3640_BPT_HISL, 0x40},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* -1.0EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0x68},
> +               {OV3640_BPT_HISL, 0x48},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* -0.7EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0x70},
> +               {OV3640_BPT_HISL, 0x50},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* -0.3EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0x78},
> +               {OV3640_BPT_HISL, 0x58},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* default */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0x80},
> +               {OV3640_BPT_HISL, 0x60},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 0.3EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0x88},
> +               {OV3640_BPT_HISL, 0x68},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 0.7EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0x90},
> +               {OV3640_BPT_HISL, 0x70},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 1.0EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0x98},
> +               {OV3640_BPT_HISL, 0x78},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 1.3EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0xa0},
> +               {OV3640_BPT_HISL, 0x80},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +       /* 1.7EV */
> +       {
> +               {OV3640_HISTO7, 0x80},
> +               {OV3640_WPT_HISH, 0xa8},
> +               {OV3640_BPT_HISL, 0x88},
> +               {OV3640_REG_TERM, OV3640_VAL_TERM}
> +       },
> +};
> +
> +/* ov3640 register configuration for combinations of pixel format and
> + * image size
> + */
> +
> +const static struct ov3640_reg qxga_yuv[] = {
> +       {OV3640_SC_CTRL0, 0x02},
> +       {OV3640_DSP_CTRL_4, 0xFC},
> +       {OV3640_FMT_MUX_CTRL0, 0x00},
> +       {OV3640_FMT_CTRL00, 0x00},
> +       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
> +       {OV3640_VTS_H, 0x06},
> +       {OV3640_VTS_L, 0x20},
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +const static struct ov3640_reg qxga_565[] = {
> +       {OV3640_SC_CTRL0, 0x02},
> +       {OV3640_DSP_CTRL_4, 0xFC},
> +       {OV3640_FMT_MUX_CTRL0, 0x01},
> +       {OV3640_FMT_CTRL00, 0x11},
> +       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
> +       {OV3640_VTS_H, 0x06},
> +       {OV3640_VTS_L, 0x20},
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +const static struct ov3640_reg qxga_555[] = {
> +       {OV3640_SC_CTRL0, 0x02},
> +       {OV3640_DSP_CTRL_4, 0xFC},
> +       {OV3640_FMT_MUX_CTRL0, 0x01},
> +       {OV3640_FMT_CTRL00, 0x13},
> +       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
> +       {OV3640_VTS_H, 0x06},
> +       {OV3640_VTS_L, 0x20},
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +const static struct ov3640_reg qxga_raw10[] = {
> +       {OV3640_SC_CTRL0, 0x22},
> +       {OV3640_DSP_CTRL_4, 0x01},
> +       {OV3640_FMT_MUX_CTRL0, 0x04},
> +       {OV3640_FMT_CTRL00, 0x18},
> +       {OV3640_OUT_CTRL01, 0x00},
> +       {OV3640_VTS_H, 0x06},
> +       {OV3640_VTS_L, 0x20},
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +const static struct ov3640_reg xga_yuv[] = {
> +       {OV3640_SC_CTRL0, 0x02},
> +       {OV3640_DSP_CTRL_4, 0xFC},
> +       {OV3640_FMT_MUX_CTRL0, 0x00},
> +       {OV3640_FMT_CTRL00, 0x00},
> +       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
> +       {OV3640_VTS_H, 0x03},
> +       {OV3640_VTS_L, 0x10},
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +const static struct ov3640_reg xga_565[] = {
> +       {OV3640_SC_CTRL0, 0x02},
> +       {OV3640_DSP_CTRL_4, 0xFC},
> +       {OV3640_FMT_MUX_CTRL0, 0x01},
> +       {OV3640_FMT_CTRL00, 0x11},
> +       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
> +       {OV3640_VTS_H, 0x03},
> +       {OV3640_VTS_L, 0x10},
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +const static struct ov3640_reg xga_555[] = {
> +       {OV3640_SC_CTRL0, 0x02},
> +       {OV3640_DSP_CTRL_4, 0xFC},
> +       {OV3640_FMT_MUX_CTRL0, 0x01},
> +       {OV3640_FMT_CTRL00, 0x13},
> +       {OV3640_OUT_CTRL01, OV3640_OUT_CTRL01_MIPIBIT8},
> +       {OV3640_VTS_H, 0x03},
> +       {OV3640_VTS_L, 0x10},
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +const static struct ov3640_reg xga_raw10[] = {
> +       {OV3640_SC_CTRL0, 0x22},
> +       {OV3640_DSP_CTRL_4, 0x01},
> +       {OV3640_FMT_MUX_CTRL0, 0x04},
> +       {OV3640_FMT_CTRL00, 0x18},
> +       {OV3640_OUT_CTRL01, 0x00},
> +       {OV3640_VTS_H, 0x03},
> +       {OV3640_VTS_L, 0x10},
> +       {OV3640_REG_TERM, OV3640_VAL_TERM}
> +};
> +
> +const static struct ov3640_reg
> +       *ov3640_reg_init[OV_NUM_PIXEL_FORMATS][OV_NUM_IMAGE_SIZES] = {
> +       {xga_yuv, qxga_yuv},
> +       {xga_565, qxga_565},
> +       {xga_555, qxga_555},
> +       {xga_raw10, qxga_raw10}
> +};
> +
> +/*
> + * struct vcontrol - Video controls
> + * @v4l2_queryctrl: V4L2 VIDIOC_QUERYCTRL ioctl structure
> + * @current_value: current value of this control
> + */
> +static struct vcontrol {
> +       struct v4l2_queryctrl qc;
> +       int current_value;
> +} video_control[] = {
> +#if (OV3640_RAW_MODE == 0)
> +       {
> +               {
> +               .id = V4L2_CID_BRIGHTNESS,
> +               .type = V4L2_CTRL_TYPE_INTEGER,
> +               .name = "Brightness",
> +               .minimum = OV3640_MIN_BRIGHT,
> +               .maximum = OV3640_MAX_BRIGHT,
> +               .step = OV3640_BRIGHT_STEP,
> +               .default_value = OV3640_DEF_BRIGHT,
> +               },
> +       .current_value = OV3640_DEF_BRIGHT,
> +       },
> +       {
> +               {
> +               .id = V4L2_CID_CONTRAST,
> +               .type = V4L2_CTRL_TYPE_INTEGER,
> +               .name = "Contrast",
> +               .minimum = OV3640_MIN_CONTRAST,
> +               .maximum = OV3640_MAX_CONTRAST,
> +               .step = OV3640_CONTRAST_STEP,
> +               .default_value = OV3640_DEF_CONTRAST,
> +               },
> +       .current_value = OV3640_DEF_CONTRAST,
> +       },
> +       {
> +               {
> +               .id = V4L2_CID_PRIVATE_BASE,
> +               .type = V4L2_CTRL_TYPE_INTEGER,
> +               .name = "Color Effects",
> +               .minimum = OV3640_MIN_COLOR,
> +               .maximum = OV3640_MAX_COLOR,
> +               .step = OV3640_COLOR_STEP,
> +               .default_value = OV3640_DEF_COLOR,
> +               },
> +       .current_value = OV3640_DEF_COLOR,
> +       }
> +#endif
> +};
> +
> +/*
> + * find_vctrl - Finds the requested ID in the video control structure array
> + * @id: ID of control to search the video control array.
> + *
> + * Returns the index of the requested ID from the control structure array
> + */
> +static int find_vctrl(int id)
> +{
> +       int i = 0;
> +
> +       if (id < V4L2_CID_BASE)
> +               return -EDOM;
> +
> +       for (i = (ARRAY_SIZE(video_control) - 1); i >= 0; i--)
> +               if (video_control[i].qc.id == id)
> +                       break;
> +       if (i < 0)
> +               i = -EINVAL;
> +       return i;
> +}
> +
> +/*
> + * Read a value from a register in ov3640 sensor device.
> + * The value is returned in 'val'.
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int ov3640_read_reg(struct i2c_client *client, u16 data_length, u16 reg,
> +                                                               u32 *val)
> +{
> +       int err = 0;
> +       struct i2c_msg msg[1];
> +       unsigned char data[4];
> +
> +       if (!client->adapter)
> +               return -ENODEV;
> +
> +       msg->addr = client->addr;
> +       msg->flags = I2C_M_WR;
> +       msg->len = 2;
> +       msg->buf = data;
> +
> +       /* High byte goes out first */
> +       data[0] = (u8) (reg >> 8);
> +       data[1] = (u8) (reg & 0xff);
> +
> +       err = i2c_transfer(client->adapter, msg, 1);

Please, let me understand.. You call i2c_transfer() and ask it to
transfer one message(third parameter), right ?
So, the returned value is negative errno or the number of messages
executed. Logic says that you should check somethin like this:
	if (err = 1) {
		good;
	} else {
		i2c_transfer failed;
		we should deal with it(printk, try again, etc)
	}

Or even:
	if (unlikely(err != 1)) {
		i2c_transfer failed;
	}
	Good code continue;

Right or wrong ?

> +       if (err >= 0) {
> +               mdelay(3);
> +               msg->flags = I2C_M_RD;
> +               msg->len = data_length;
> +               err = i2c_transfer(client->adapter, msg, 1);
> +       }
> +       if (err >= 0) {
> +               *val = 0;
> +               /* High byte comes first */
> +               if (data_length == 1)
> +                       *val = data[0];
> +               else if (data_length == 2)
> +                       *val = data[1] + (data[0] << 8);
> +               else
> +                       *val = data[3] + (data[2] << 8) +
> +                               (data[1] << 16) + (data[0] << 24);
> +               return 0;
> +       }
> +       dev_err(&client->dev, "read from offset 0x%x error %d", reg, err);

"\n" should be in dev_err.

> +       return err;
> +}
> +
> +/* Write a value to a register in ov3640 sensor device.
> + * @client: i2c driver client structure.
> + * @reg: Address of the register to read value from.
> + * @val: Value to be written to a specific register.
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int ov3640_write_reg(struct i2c_client *client, u16 reg, u8 val)
> +{
> +       int err = 0;
> +       struct i2c_msg msg[1];
> +       unsigned char data[3];
> +       int retries = 0;
> +
> +       if (!client->adapter)
> +               return -ENODEV;
> +retry:
> +       msg->addr = client->addr;
> +       msg->flags = I2C_M_WR;
> +       msg->len = 3;
> +       msg->buf = data;
> +
> +       /* high byte goes out first */
> +       data[0] = (u8) (reg >> 8);
> +       data[1] = (u8) (reg & 0xff);
> +       data[2] = val;
> +
> +       err = i2c_transfer(client->adapter, msg, 1);
> +       udelay(50);
> +
> +       if (err >= 0)

Well, probably all checks of returned values after i2c_transfer should
be reformatted in right way.


> +               return 0;
> +
> +       if (retries <= 5) {
> +               dev_dbg(&client->dev, "Retrying I2C... %d", retries);

"\n"

> +               retries++;
> +               set_current_state(TASK_UNINTERRUPTIBLE);
> +               schedule_timeout(msecs_to_jiffies(20));
> +               goto retry;
> +       }
> +
> +       return err;
> +}
> +
> +/*
> + * Initialize a list of ov3640 registers.
> + * The list of registers is terminated by the pair of values
> + * {OV3640_REG_TERM, OV3640_VAL_TERM}.
> + * @client: i2c driver client structure.
> + * @reglist[]: List of address of the registers to write data.
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int ov3640_write_regs(struct i2c_client *client,
> +                                       const struct ov3640_reg reglist[])
> +{
> +       int err = 0;
> +       const struct ov3640_reg *next = reglist;
> +
> +       while (!((next->reg == OV3640_REG_TERM)
> +               && (next->val == OV3640_VAL_TERM))) {
> +               err = ov3640_write_reg(client, next->reg, next->val);
> +               udelay(100);
> +               if (err)
> +                       return err;
> +               next++;
> +       }
> +       return 0;
> +}
> +
> +/* 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_ov
> +ov3640_find_size(unsigned int width, unsigned int height)
> +{
> +       if ((width > ov3640_sizes[XGA].width) ||
> +               (height > ov3640_sizes[XGA].height))
> +               return QXGA;
> +       return XGA;
> +}
> +
> +/*
> + * Set CSI2 Virtual ID.
> + */
> +static int ov3640_set_virtual_id(struct i2c_client *client, u32 id)
> +{
> +       return ov3640_write_reg(client, OV3640_MIPI_CTRL0C, (0x3 & id) << 6 |
> +                                                                       0x02);
> +}
> +
> +
> +/*
> + * Calculates the MIPIClk.
> + * 1) Calculate fclk
> + *     fclk = (64 - OV3640_PLL_1[5:0]) * N * Bit8Div * MCLK / M
> + *    where N = 1/1.5/2/3 for OV3640_PLL_2[7:6]=0~3
> + *          M = 1/1.5/2/3 for OV3640_PLL_2[1:0]=0~3
> + *    Bit8Div = 1/1/4/5 for OV3640_PLL_2[5:4]
> + * 2) Calculate MIPIClk
> + *     MIPIClk = fclk / ScaleDiv / MIPIDiv
> + *             = fclk * (1/ScaleDiv) / MIPIDiv
> + *    where 1/ScaleDiv = 0x3010[3:0]*2
> + *          MIPIDiv = 0x3010[5] + 1
> + * NOTE:
> + *  - The lookup table 'lut1' has been multiplied by 2 so all its values
> + *    are integers. Since both N & M use the same table, and they are
> + *    used as a ratio then the factor of 2 is already take into account.
> + *    i.e.  2N/2M = N/M
> + */
> +static u32 ov3640_calc_mipiclk(struct v4l2_int_device *s)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +       struct i2c_client *client = sensor->i2c_client;
> +       u32 rxpll, val, n, m, bit8div;
> +       u32 sdiv_inv, mipidiv;
> +       u32 fclk, mipiclk, mclk = 24000000;
> +       u8 lut1[4] = {2, 3, 4, 6};
> +       u8 lut2[4] = {1, 1, 4, 5};
> +
> +       /* Calculate fclk */
> +       ov3640_read_reg(client, 1, OV3640_PLL_1, &val);
> +       rxpll = val & 0x3F;
> +
> +       ov3640_read_reg(client, 1, OV3640_PLL_2, &val);
> +       n = lut1[(val >> 6) & 0x3];
> +       m = lut1[val & 0x3];
> +       bit8div = lut2[(val >> 4) & 0x3];
> +       fclk = (64 - rxpll) * n * bit8div * mclk / m;
> +
> +       ov3640_read_reg(client, 1, OV3640_PLL_3, &val);
> +       mipidiv = ((val >> 5) & 1) + 1;
> +       sdiv_inv = (val & 0xF) * 2;
> +
> +       if ((val & 0xF) >= 1)
> +               mipiclk = fclk / sdiv_inv / mipidiv;
> +       else
> +               mipiclk = fclk / mipidiv;
> +       dev_dbg(&client->dev, "mipiclk=%u  fclk=%u  val&0xF=%u  sdiv_inv=%u  "
> +                                                       "mipidiv=%u\n",
> +                                                       mipiclk, fclk, val&0xF,
> +                                                       sdiv_inv, mipidiv);
> +       return mipiclk;
> +}
> +
> +/**
> + * ov3640_set_framerate
> + **/
> +static int ov3640_set_framerate(struct i2c_client *client,
> +                                               struct v4l2_fract *fper,
> +                                               enum image_size_ov isize)
> +{
> +       u32 tempfps1, tempfps2;
> +       u8 clkval;
> +/*
> +       u32 origvts, newvts, templineperiod;
> +       u32 origvts_h, origvts_l, newvts_h, newvts_l;
> +*/
> +       int err = 0;
> +
> +       /* FIXME: QXGA framerate setting forced to 15 FPS */
> +       if (isize == QXGA) {
> +               err = ov3640_write_reg(client, OV3640_PLL_1, 0x32);
> +               err = ov3640_write_reg(client, OV3640_PLL_2, 0x21);
> +               err = ov3640_write_reg(client, OV3640_PLL_3, 0x21);
> +               err = ov3640_write_reg(client, OV3640_CLK, 0x01);
> +               err = ov3640_write_reg(client, 0x304c, 0x81);

I see no checking of returned values. For example, if first function
failed, rest functions will keep going.


> +               return err;
> +       }
> +
> +       tempfps1 = fper->denominator * 10000;
> +       tempfps1 /= fper->numerator;
> +       tempfps2 = fper->denominator / fper->numerator;
> +       if ((tempfps1 % 10000) != 0)
> +               tempfps2++;
> +       clkval = (u8)((30 / tempfps2) - 1);
> +
> +       err = ov3640_write_reg(client, OV3640_CLK, clkval);
> +       /* RxPLL = 50d = 32h */
> +       err = ov3640_write_reg(client, OV3640_PLL_1, 0x32);
> +       /* RxPLL = 50d = 32h */
> +       err = ov3640_write_reg(client, OV3640_PLL_2,
> +                                       OV3640_PLL_2_BIT8DIV_4 |
> +                                       OV3640_PLL_2_INDIV_1_5);
> +       /*
> +        * NOTE: Sergio's Fix for MIPI CLK timings, not suggested by OV
> +        */
> +       err = ov3640_write_reg(client, OV3640_PLL_3, 0x21 +
> +                                                       (clkval & 0xF));
> +       /* Setting DVP divisor value */
> +       err = ov3640_write_reg(client, 0x304c, 0x82);
> +/* FIXME: Time adjustment to add granularity to the available fps */
> +/*
> +       ov3640_read_reg(client, 1, OV3640_VTS_H, &origvts_h);
> +       ov3640_read_reg(client, 1, OV3640_VTS_L, &origvts_l);
> +       origvts = (u32)((origvts_h << 8) + origvts_l);
> +       templineperiod = 1000000 / (tempfps2 * origvts);
> +       newvts = 1000000 / (tempfps2 * templineperiod);
> +       newvts_h = (u8)((newvts & 0xFF00) >> 8);
> +       newvts_l = (u8)(newvts & 0xFF);
> +       err = ov3640_write_reg(client, OV3640_VTS_H, newvts_h);
> +       err = ov3640_write_reg(client, OV3640_VTS_L, newvts_l);
> +*/
> +       return err;
> +}
> +
> +/*
> + * Configure the ov3640 for a specified image size, pixel format, and frame
> + * period.  xclk is the frequency (in Hz) of the xclk input to the OV3640.
> + * 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 ov3640_configure(struct v4l2_int_device *s)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +       struct v4l2_pix_format *pix = &sensor->pix;
> +       struct i2c_client *client = sensor->i2c_client;
> +       enum image_size_ov isize = XGA;
> +       unsigned char hsize_l = 0, hsize_h = 0;
> +       unsigned char vsize_l = 0, vsize_h = 0;
> +       int vsize = 0, hsize = 0, height_l = 0, height_h = 0, width_l = 0;
> +       int width_h = 0, ratio = 0, err = 0;
> +       u32 mipiclk;
> +       enum pixel_format_ov pfmt = YUV;
> +       u32 min_hs_zero_nui, min_hs_zero, min_hs_zero_total;
> +       u32 min_hs_prepare_nui, min_hs_prepare, min_hs_prepare_total;
> +       u32 max_hs_prepare_nui, max_hs_prepare, max_hs_prepare_total;
> +       u32 ubound_hs_settle, lbound_hs_settle;
> +       u32 val;
> +
> +       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_SGRBG10:
> +               pfmt = RAW10;
> +               break;
> +
> +       case V4L2_PIX_FMT_YUYV:
> +       case V4L2_PIX_FMT_UYVY:
> +       default:
> +               pfmt = YUV;
> +       }
> +
> +       /* Set receivers virtual channel before sensor setup starts.
> +        * Only set the sensors virtual channel after all other setup
> +        * for the sensor is complete.
> +        */
> +       isp_csi2_ctx_config_virtual_id(0, OV3640_CSI2_VIRTUAL_ID);
> +       isp_csi2_ctx_update(0, false);
> +
> +       if (ov3640_find_size(pix->width, pix->height) == XGA)
> +               isize = XGA;
> +       else
> +               isize = QXGA;
> +
> +       /* Reset */
> +       ov3640_write_reg(client, OV3640_SYS, 0x80);
> +       mdelay(5);
> +
> +       /* Common registers */
> +       err = ov3640_write_regs(client, ov3640_common[isize]);
> +
> +       /* Configure image size and pixel format */
> +       err = ov3640_write_regs(client, ov3640_reg_init[pfmt][isize]);
> +
> +       /* Setting of frame rate (OV suggested way) */
> +       err = ov3640_set_framerate(client, &sensor->timeperframe, isize);
> +#ifdef CONFIG_VIDEO_OV3640_CSI2
> +       /* Set CSI2 common register settings */
> +       err = ov3640_write_regs(client, ov3640_common_csi2);
> +#endif

Again, no checking of err.

> +
> +       sensor->isize = isize;
> +
> +       /* Scale image if needed*/
> +       if (((pix->width == ov3640_sizes[QXGA].width) &&
> +               (pix->height == ov3640_sizes[QXGA].height) && (isize == QXGA))
> +               || ((pix->width == ov3640_sizes[XGA].width) &&
> +               (pix->height == ov3640_sizes[XGA].height) &&
> +               (isize == XGA)) || (pfmt == RAW10)) {
> +
> +               /* if the image size correspond to one of the base image sizes
> +                       then we don't need to scale the image */
> +               sensor->hsize = pix->width;
> +               sensor->vsize = pix->height;
> +
> +               if (isize == XGA)
> +                       ov3640_write_regs(client, ov3640_out_xga);
> +               else
> +                       ov3640_write_regs(client, ov3640_out_qxga);
> +
> +       } else {
> +       /* Default Ver and Hor sizes for QXGA and XGA*/
> +               if (isize == QXGA) {
> +                       vsize = 0x600;/* 0x60c; */
> +                       hsize = 0x800;/* 0x818; */
> +               } else {
> +                       vsize = 0x304;
> +                       hsize = 0x40c;
> +               }
> +               /* Scaling */
> +               /* Adjust V and H sizes for image sizes not derived form VGA*/
> +               ratio = (pix->width * 1000) / pix->height;
> +
> +               if  (((vsize * ratio + 500) / 1000) > hsize)
> +                       vsize = (hsize * 1000) / ratio ;
> +
> +               else
> +                       hsize = (vsize * ratio + 500) / 1000;
> +
> +               /* We need even numbers */
> +               if (vsize & 1)
> +                       vsize--;
> +               if (hsize & 1)
> +                       hsize--;
> +
> +               /* Adjusting numbers to set registers correctly */
> +               hsize_l = (0xFF & hsize);
> +               hsize_h = (0xF00 & hsize) >> 8;
> +               vsize_l = (0xFF & vsize);
> +               vsize_h = (0x700 & vsize) >> 4;
> +
> +               /* According to Software app notes we have to add 0x08 and 0x04
> +                * in order to scale correctly
> +                */
> +               width_l = (0xFF & pix->width) + 0x08;
> +               width_h = (0xF00 & pix->width) >> 8;
> +               height_l = (0xFF & pix->height) + 0x04;
> +               height_h = (0x700 & pix->height) >> 4;
> +
> +               err = ov3640_write_reg(client, OV3640_SIZE_IN_MISC,
> +                                                       (vsize_h | hsize_h));
> +               err = ov3640_write_reg(client, OV3640_HSIZE_IN_L, hsize_l);
> +               err = ov3640_write_reg(client, OV3640_VSIZE_IN_L, vsize_l);
> +               err = ov3640_write_reg(client, OV3640_SIZE_OUT_MISC,
> +                                                       (height_h | width_h));
> +               err = ov3640_write_reg(client, OV3640_HSIZE_OUT_L, width_l);
> +               err = ov3640_write_reg(client, OV3640_VSIZE_OUT_L, height_l);
> +               err = ov3640_write_reg(client, OV3640_ISP_PAD_CTR2, 0x42);
> +               err = ov3640_write_reg(client, OV3640_ISP_XOUT_H, width_h);
> +               err = ov3640_write_reg(client, OV3640_ISP_XOUT_L,
> +                                                       (width_l  - 0x08));
> +               err = ov3640_write_reg(client, OV3640_ISP_YOUT_H,
> +                                                       (height_h >> 4));
> +               err = ov3640_write_reg(client, OV3640_ISP_YOUT_L,
> +                                                       (height_l - 0x04));

The same thing here.

> +
> +               sensor->hsize = hsize;
> +               sensor->vsize = vsize;
> +
> +               dev_dbg(&client->dev, "HSIZE_IN =%i  VSIZE_IN =%i\n", hsize,
> +                                                                       vsize);
> +               dev_dbg(&client->dev, "HSIZE_OUT=%u  VSIZE_OUT=%u\n",
> +                                                       (pix->width + 8),
> +                                                       (pix->height + 4));
> +               dev_dbg(&client->dev, "ISP_XOUT =%u  ISP_YOUT =%u\n",
> +                                                               pix->width,
> +                                                               pix->height);
> +       }
> +
> +       /* Setup the ISP VP based on image format */
> +       if (pix->pixelformat == V4L2_PIX_FMT_SGRBG10) {
> +               isp_csi2_ctrl_config_vp_out_ctrl(2);
> +               isp_csi2_ctrl_update(false);
> +       } else {
> +               isp_csi2_ctrl_config_vp_out_ctrl(1);
> +               isp_csi2_ctrl_update(false);
> +       }
> +
> +       /* Store image size */
> +       sensor->width = pix->width;
> +       sensor->height = pix->height;
> +
> +       sensor->crop_rect.left = 0;
> +       sensor->crop_rect.width = pix->width;
> +       sensor->crop_rect.top = 0;
> +       sensor->crop_rect.height = pix->height;
> +
> +#ifdef CONFIG_VIDEO_OV3640_CSI2
> +       mipiclk = ov3640_calc_mipiclk(s);
> +
> +       /* Calculate Valid bounds for High speed settle timing in UIs */
> +       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL22, &val);
> +       min_hs_zero_nui = ((val & OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_MASK) >>
> +                               OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_SHIFT);
> +       min_hs_zero = ((val & OV3640_MIPI_CTRL22_MIN_HS_ZERO_H_MASK) << 8);
> +       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL23, &val);
> +       min_hs_zero |= (val & OV3640_MIPI_CTRL23_MIN_HS_ZERO_L_MASK);
> +       min_hs_zero_total = ((min_hs_zero_nui * 1000000 * 1000) / mipiclk) +
> +                                                               min_hs_zero;
> +
> +       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL32, &val);
> +       min_hs_prepare_nui = ((val &
> +                               OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_MASK) >>
> +                               OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_SHIFT);
> +       min_hs_prepare = ((val &
> +                               OV3640_MIPI_CTRL32_MIN_HS_PREPARE_H_MASK) << 8);
> +       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL33, &val);
> +       min_hs_prepare |= (val & OV3640_MIPI_CTRL33_MIN_HS_PREPARE_L_MASK);
> +       min_hs_prepare_total = ((min_hs_prepare_nui * 1000000 * 1000) /
> +                                               mipiclk) + min_hs_prepare;
> +
> +       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL34, &val);
> +       max_hs_prepare_nui = ((val &
> +                               OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_MASK) >>
> +                               OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_SHIFT);
> +       max_hs_prepare = ((val &
> +                               OV3640_MIPI_CTRL34_MAX_HS_PREPARE_H_MASK) << 8);
> +       ov3640_read_reg(client, 1, OV3640_MIPI_CTRL35, &val);
> +       max_hs_prepare |= (val & OV3640_MIPI_CTRL35_MAX_HS_PREPARE_L_MASK);
> +       max_hs_prepare_total = ((max_hs_prepare_nui * 1000000 * 1000) /
> +                                               mipiclk) + max_hs_prepare;
> +
> +       ubound_hs_settle = ((min_hs_zero_total + min_hs_prepare_total) *
> +                                       ((mipiclk >> 1) / 1000000)) / 1000;
> +       lbound_hs_settle = (max_hs_prepare_total * ((mipiclk >> 1) /
> +                                                       1000000)) / 1000;
> +
> +       /* Send settings to ISP-CSI2 Receiver PHY */
> +       isp_csi2_calc_phy_cfg0(mipiclk, lbound_hs_settle, ubound_hs_settle);
> +
> +       /* Set sensors virtual channel*/
> +       ov3640_set_virtual_id(client, OV3640_CSI2_VIRTUAL_ID);
> +#endif
> +       return err;
> +}
> +
> +
> +/* Detect if an ov3640 is present, returns a negative error number if no
> + * device is detected, or pidl as version number if a device is detected.
> + */
> +static int ov3640_detect(struct i2c_client *client)
> +{
> +       u32 pidh, pidl;
> +
> +       if (!client)
> +               return -ENODEV;
> +
> +       if (ov3640_read_reg(client, 1, OV3640_PIDH, &pidh))
> +               return -ENODEV;
> +
> +       if (ov3640_read_reg(client, 1, OV3640_PIDL, &pidl))
> +               return -ENODEV;
> +
> +       if ((pidh == OV3640_PIDH_MAGIC) && ((pidl == OV3640_PIDL_MAGIC1) ||
> +                                               (pidl == OV3640_PIDL_MAGIC2))) {
> +               dev_dbg(&client->dev, "Detect success (%02X,%02X)\n", pidh,
> +                                                                       pidl);
> +               return pidl;
> +       }
> +
> +       return -ENODEV;
> +}
> +
> +/* To get the cropping capabilities of ov3640 sensor
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int ioctl_cropcap(struct v4l2_int_device *s,
> +                                               struct v4l2_cropcap *cropcap)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +
> +       cropcap->bounds.top = 0;
> +       cropcap->bounds.left = 0;
> +       cropcap->bounds.width = sensor->width;
> +       cropcap->bounds.height = sensor->height;
> +       cropcap->defrect = cropcap->bounds;
> +       cropcap->pixelaspect.numerator = 1;
> +       cropcap->pixelaspect.denominator = 1;
> +       return 0;
> +}
> +
> +/* To get the current crop window for of ov3640 sensor
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int ioctl_g_crop(struct v4l2_int_device *s, struct  v4l2_crop *crop)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +
> +       crop->c = sensor->crop_rect;
> +       return 0;
> +}
> +
> +/* To set the crop window for of ov3640 sensor
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int ioctl_s_crop(struct v4l2_int_device *s, struct  v4l2_crop *crop)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +       /* FIXME: Temporary workaround for avoiding Zoom setting */
> +       /* struct i2c_client *client = sensor->i2c_client; */
> +       struct v4l2_rect *cur_rect;
> +       unsigned long *cur_width, *cur_height;
> +       int hstart, vstart, hsize, vsize, hsize_l, vsize_l, hsize_h, vsize_h;
> +       int hratio, vratio, zoomfactor, err = 0;
> +
> +       cur_rect = &sensor->crop_rect;
> +       cur_width = &sensor->width;
> +       cur_height = &sensor->height;
> +
> +       if ((crop->c.left == cur_rect->left) &&
> +           (crop->c.width == cur_rect->width) &&
> +           (crop->c.top == cur_rect->top) &&
> +           (crop->c.height == cur_rect->height))
> +               return 0;
> +
> +       /* out of range? then return the current crop rectangle */
> +       if ((crop->c.left + crop->c.width) > sensor->width ||
> +           (crop->c.top + crop->c.height) > sensor->height) {
> +               crop->c = *cur_rect;
> +               return 0;
> +       }
> +
> +       if (sensor->isize == QXGA)
> +               zoomfactor = 1;
> +       else
> +               zoomfactor = 2;
> +
> +       hratio = (sensor->hsize * 1000) / sensor->width;
> +       vratio = (sensor->vsize * 1000) / sensor->height;
> +       hstart = (((crop->c.left * hratio + 500) / 1000) * zoomfactor) + 0x11d;
> +       vstart = (((crop->c.top * vratio + 500) / 1000) + 0x0a);
> +       hsize  = (crop->c.width * hratio + 500) / 1000;
> +       vsize  = (crop->c.height * vratio + 500) / 1000;
> +
> +       if (vsize & 1)
> +               vsize--;
> +       if (hsize & 1)
> +               hsize--;
> +
> +       /* Adjusting numbers to set register correctly */
> +       hsize_l = (0xFF & hsize);
> +       hsize_h = (0xF00 & hsize) >> 8;
> +       vsize_l = (0xFF & vsize);
> +       vsize_h = (0x700 & vsize) >> 4;
> +
> +       if ((sensor->height > vsize) || (sensor->width > hsize))
> +               return -EINVAL;
> +
> +       hsize = hsize * zoomfactor;
> +/*
> +       err = ov3640_write_reg(client, OV3640_DSP_CTRL_2, 0xEF);
> +       err = ov3640_write_reg(client, OV3640_SIZE_IN_MISC, (vsize_h |
> +                                                               hsize_h));
> +       err = ov3640_write_reg(client, OV3640_HSIZE_IN_L, hsize_l);
> +       err = ov3640_write_reg(client, OV3640_VSIZE_IN_L, vsize_l);
> +       err = ov3640_write_reg(client, OV3640_HS_H, (hstart >> 8) & 0xFF);
> +       err = ov3640_write_reg(client, OV3640_HS_L, hstart & 0xFF);
> +       err = ov3640_write_reg(client, OV3640_VS_H, (vstart >> 8) & 0xFF);
> +       err = ov3640_write_reg(client, OV3640_VS_L, vstart & 0xFF);
> +       err = ov3640_write_reg(client, OV3640_HW_H, ((hsize) >> 8) & 0xFF);
> +       err = ov3640_write_reg(client, OV3640_HW_L, hsize & 0xFF);
> +       err = ov3640_write_reg(client, OV3640_VH_H, ((vsize) >> 8) & 0xFF);
> +       err = ov3640_write_reg(client, OV3640_VH_L, vsize & 0xFF);
> +*/
> +       if (err)
> +               return err;
> +
> +       /* save back */
> +       *cur_rect = crop->c;
> +
> +       /* Setting crop too fast can cause frame out-of-sync. */
> +
> +       set_current_state(TASK_UNINTERRUPTIBLE);
> +       schedule_timeout(msecs_to_jiffies(20));
> +       return 0;
> +}
> +
> +
> +/*
> + * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl
> + * @s: pointer to standard V4L2 device structure
> + * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure
> + *
> + * If the requested control is supported, returns the control information
> + * from the video_control[] array.  Otherwise, returns -EINVAL if the
> + * control is not supported.
> + */
> +static int ioctl_queryctrl(struct v4l2_int_device *s,
> +                                               struct v4l2_queryctrl *qc)
> +{
> +       int i;
> +
> +       i = find_vctrl(qc->id);
> +       if (i == -EINVAL)
> +               qc->flags = V4L2_CTRL_FLAG_DISABLED;
> +
> +       if (i < 0)
> +               return -EINVAL;
> +
> +       *qc = video_control[i].qc;
> +       return 0;
> +}
> +
> +/*
> + * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
> + * @s: pointer to standard V4L2 device structure
> + * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
> + *
> + * If the requested control is supported, returns the control's current
> + * value from the video_control[] array.  Otherwise, returns -EINVAL
> + * if the control is not supported.
> + */
> +
> +static int ioctl_g_ctrl(struct v4l2_int_device *s,
> +                            struct v4l2_control *vc)
> +{
> +       struct vcontrol *lvc;
> +       int i;
> +
> +       i = find_vctrl(vc->id);
> +       if (i < 0)
> +               return -EINVAL;
> +       lvc = &video_control[i];
> +
> +       switch (vc->id) {
> +       case V4L2_CID_BRIGHTNESS:
> +               vc->value = lvc->current_value;
> +               break;
> +       case V4L2_CID_CONTRAST:
> +               vc->value = lvc->current_value;
> +               break;
> +       case V4L2_CID_PRIVATE_BASE:
> +               vc->value = lvc->current_value;
> +               break;
> +       }
> +       return 0;
> +}
> +
> +/*
> + * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
> + * @s: pointer to standard V4L2 device structure
> + * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
> + *
> + * If the requested control is supported, sets the control's current
> + * value in HW (and updates the video_control[] array).  Otherwise,
> + * returns -EINVAL if the control is not supported.
> + */
> +static int ioctl_s_ctrl(struct v4l2_int_device *s,
> +                            struct v4l2_control *vc)
> +{
> +       int retval = -EINVAL;
> +       int i;
> +       struct ov3640_sensor *sensor = s->priv;
> +       struct i2c_client *client = sensor->i2c_client;
> +       struct vcontrol *lvc;
> +
> +       i = find_vctrl(vc->id);
> +       if (i < 0)
> +               return -EINVAL;
> +
> +       lvc = &video_control[i];
> +
> +       switch (vc->id) {
> +       case V4L2_CID_BRIGHTNESS:
> +               if (vc->value >= 0 && vc->value <= 6) {
> +                       retval = ov3640_write_regs(client,
> +                                                       brightness[vc->value]);
> +               } else {
> +                       dev_err(&client->dev, "BRIGHTNESS LEVEL NOT SUPPORTED");
> +                       return -EINVAL;
> +               }
> +               break;
> +       case V4L2_CID_CONTRAST:
> +               if (vc->value >= 0 && vc->value <= 6)
> +                       retval = ov3640_write_regs(client, contrast[vc->value]);
> +               else {
> +                       dev_err(&client->dev, "CONTRAST LEVEL NOT SUPPORTED");
> +                       return -EINVAL;
> +               }
> +               break;
> +       case V4L2_CID_PRIVATE_BASE:
> +               if (vc->value >= 0 && vc->value <= 2)
> +                       retval = ov3640_write_regs(client, colors[vc->value]);
> +               else {
> +                       dev_err(&client->dev, "COLOR LEVEL NOT SUPPORTED");
> +                       return -EINVAL;

I don't sure - may be you like big letters in logs..
Anyway, "\n" is absent in this 3 dev_err.


> +               }
> +               break;
> +       }
> +       if (!retval)
> +               lvc->current_value = vc->value;
> +       return retval;
> +}
> +
> +/*
> + * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
> + * @s: pointer to standard V4L2 device structure
> + * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
> + *
> + * Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
> + */
> + static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
> +                                  struct v4l2_fmtdesc *fmt)
> +{
> +       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;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       fmt->flags = ov3640_formats[index].flags;
> +       strlcpy(fmt->description, ov3640_formats[index].description,
> +                                       sizeof(fmt->description));
> +       fmt->pixelformat = ov3640_formats[index].pixelformat;
> +
> +       return 0;
> +}
> +
> +
> +/*
> + * ioctl_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
> + * @s: pointer to standard V4L2 device structure
> + * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
> + *
> + * 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 ioctl_try_fmt_cap(struct v4l2_int_device *s,
> +                            struct v4l2_format *f)
> +{
> +       int ifmt;
> +       enum image_size_ov isize;
> +       struct v4l2_pix_format *pix = &f->fmt.pix;
> +
> +       if (pix->width > ov3640_sizes[QXGA].width)
> +               pix->width = ov3640_sizes[QXGA].width;
> +       if (pix->height > ov3640_sizes[QXGA].height)
> +               pix->height = ov3640_sizes[QXGA].height;
> +
> +       isize = ov3640_find_size(pix->width, pix->height);
> +       pix->width = ov3640_sizes[isize].width;
> +       pix->height = ov3640_sizes[isize].height;
> +
> +       for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
> +               if (pix->pixelformat == ov3640_formats[ifmt].pixelformat)
> +                       break;
> +       }
> +       if (ifmt == NUM_CAPTURE_FORMATS)
> +               ifmt = 0;
> +       pix->pixelformat = ov3640_formats[ifmt].pixelformat;
> +       pix->field = V4L2_FIELD_NONE;
> +       pix->bytesperline = pix->width*2;
> +       pix->sizeimage = pix->bytesperline*pix->height;
> +       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_SGRBG10:
> +       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;
> +}
> +
> +
> +/*
> + * ioctl_s_fmt_cap - V4L2 sensor interface handler for VIDIOC_S_FMT ioctl
> + * @s: pointer to standard V4L2 device structure
> + * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
> + *
> + * If the requested format is supported, configures the HW to use that
> + * format, returns error code if format not supported or HW can't be
> + * correctly configured.
> + */
> + static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
> +                               struct v4l2_format *f)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +       struct v4l2_pix_format *pix = &f->fmt.pix;
> +       int rval;
> +
> +       rval = ioctl_try_fmt_cap(s, f);
> +       if (rval)
> +               return rval;
> +
> +       sensor->pix = *pix;
> +
> +       return 0;
> +}
> +
> +/*
> + * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
> + * @s: pointer to standard V4L2 device structure
> + * @f: pointer to standard V4L2 v4l2_format structure
> + *
> + * Returns the sensor's current pixel format in the v4l2_format
> + * parameter.
> + */
> +static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
> +                               struct v4l2_format *f)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +       f->fmt.pix = sensor->pix;
> +
> +       return 0;
> +}
> +
> +/*
> + * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
> + * @s: pointer to standard V4L2 device structure
> + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
> + *
> + * Returns the sensor's video CAPTURE parameters.
> + */
> +static int ioctl_g_parm(struct v4l2_int_device *s,
> +                            struct v4l2_streamparm *a)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +       struct v4l2_captureparm *cparm = &a->parm.capture;
> +
> +       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +               return -EINVAL;
> +
> +       memset(a, 0, sizeof(*a));
> +       a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +
> +       cparm->capability = V4L2_CAP_TIMEPERFRAME;
> +       cparm->timeperframe = sensor->timeperframe;
> +
> +       return 0;
> +}
> +
> +/*
> + * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
> + * @s: pointer to standard V4L2 device structure
> + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
> + *
> + * Configures the sensor to use the input parameters, if possible.  If
> + * not possible, reverts to the old parameters and returns the
> + * appropriate error code.
> + */
> +static int ioctl_s_parm(struct v4l2_int_device *s,
> +                            struct v4l2_streamparm *a)
> +{
> +       int rval = 0;
> +       struct ov3640_sensor *sensor = s->priv;
> +       struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
> +       struct v4l2_fract timeperframe_old;
> +       int desired_fps;
> +       timeperframe_old = sensor->timeperframe;
> +       sensor->timeperframe = *timeperframe;
> +
> +       desired_fps = timeperframe->denominator / timeperframe->numerator;
> +       if ((desired_fps < OV3640_MIN_FPS) || (desired_fps > OV3640_MAX_FPS))
> +               rval = -EINVAL;
> +
> +       if (rval)
> +               sensor->timeperframe = timeperframe_old;
> +       else
> +               *timeperframe = sensor->timeperframe;
> +
> +       return rval;
> +}
> +
> +/*
> + * ioctl_g_priv - V4L2 sensor interface handler for vidioc_int_g_priv_num
> + * @s: pointer to standard V4L2 device structure
> + * @p: void pointer to hold sensor's private data address
> + *
> + * Returns device's (sensor's) private data area address in p parameter
> + */
> +static int ioctl_g_priv(struct v4l2_int_device *s, void *p)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +
> +       return sensor->pdata->priv_data_set(p);
> +}
> +
> +/*
> + * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
> + * @s: pointer to standard V4L2 device structure
> + * @on: power state to which device is to be set
> + *
> + * Sets devices power state to requrested state, if possible.
> + */
> + static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
> +{
> +       struct ov3640_sensor *sensor = s->priv;
> +       struct i2c_client *c = sensor->i2c_client;
> +       struct omap34xxcam_hw_config hw_config;
> +       int rval;
> +
> +       rval = ioctl_g_priv(s, &hw_config);
> +       if (rval) {
> +               dev_err(&c->dev, "Unable to get hw params\n");
> +               return rval;
> +       }
> +
> +       rval = sensor->pdata->power_set(on);
> +       if (rval < 0) {
> +               dev_err(&c->dev, "Unable to set the power state: "
> +                       OV3640_DRIVER_NAME " sensor\n");
> +               sensor->pdata->set_xclk(0);
> +               return rval;
> +       }
> +
> +       if (on == V4L2_POWER_ON)
> +               sensor->pdata->set_xclk(xclk_current);
> +       else
> +               sensor->pdata->set_xclk(0);
> +
> +       if ((on == V4L2_POWER_ON) && (sensor->state == SENSOR_DETECTED))
> +               ov3640_configure(s);
> +
> +       if ((on == V4L2_POWER_ON) && (sensor->state == SENSOR_NOT_DETECTED)) {
> +               rval = ov3640_detect(c);
> +               if (rval < 0) {
> +                       dev_err(&c->dev, "Unable to detect "
> +                                       OV3640_DRIVER_NAME " sensor\n");
> +                       sensor->state = SENSOR_NOT_DETECTED;
> +                       return rval;
> +               }
> +               sensor->state = SENSOR_DETECTED;
> +               sensor->ver = rval;
> +               pr_info(OV3640_DRIVER_NAME " Chip version 0x%02x detected\n",
> +                                                               sensor->ver);
> +       }
> +       return 0;
> +}
> +
> +/*
> + * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
> + * @s: pointer to standard V4L2 device structure
> + *
> + * Initialize the sensor device (call ov3640_configure())
> + */
> +static int ioctl_init(struct v4l2_int_device *s)
> +{
> +       return 0;
> +}
> +
> +/**
> + * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num
> + * @s: pointer to standard V4L2 device structure
> + *
> + * Delinitialise the dev. at slave detach.  The complement of ioctl_dev_init.
> + */
> +static int ioctl_dev_exit(struct v4l2_int_device *s)
> +{
> +       return 0;
> +}
> +
> +/**
> + * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
> + * @s: pointer to standard V4L2 device structure
> + *
> + * Initialise the device when slave attaches to the master.  Returns 0 if
> + * ov3640 device could be found, otherwise returns appropriate error.
> + */
> +static int ioctl_dev_init(struct v4l2_int_device *s)
> +{
> +       return 0;
> +}
> +
> +/**
> + * ioctl_enum_framesizes - V4L2 sensor if handler for vidioc_int_enum_framesizes
> + * @s: pointer to standard V4L2 device structure
> + * @frms: pointer to standard V4L2 framesizes enumeration structure
> + *
> + * Returns possible framesizes depending on choosen pixel format
> + **/
> +static int ioctl_enum_framesizes(struct v4l2_int_device *s,
> +                                       struct v4l2_frmsizeenum *frms)
> +{
> +       int ifmt;
> +
> +       for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
> +               if (frms->pixel_format == ov3640_formats[ifmt].pixelformat)
> +                       break;
> +       }
> +       /* Is requested pixelformat not found on sensor? */
> +       if (ifmt == NUM_CAPTURE_FORMATS)
> +               return -EINVAL;
> +
> +       /* Do we already reached all discrete framesizes? */
> +       if (frms->index >= 2)
> +               return -EINVAL;
> +
> +       frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;
> +       frms->discrete.width = ov3640_sizes[frms->index].width;
> +       frms->discrete.height = ov3640_sizes[frms->index].height;
> +
> +       return 0;
> +}
> +
> +const struct v4l2_fract ov3640_frameintervals[] = {
> +       { .numerator = 2, .denominator = 15 },
> +       { .numerator = 1, .denominator = 15 },
> +       { .numerator = 1, .denominator = 30 },
> +};
> +
> +static int ioctl_enum_frameintervals(struct v4l2_int_device *s,
> +                                       struct v4l2_frmivalenum *frmi)
> +{
> +       int ifmt;
> +
> +       for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
> +               if (frmi->pixel_format == ov3640_formats[ifmt].pixelformat)
> +                       break;
> +       }
> +       /* Is requested pixelformat not found on sensor? */
> +       if (ifmt == NUM_CAPTURE_FORMATS)
> +               return -EINVAL;
> +
> +       /* Do we already reached all discrete framesizes? */
> +
> +       if ((frmi->width == ov3640_sizes[1].width) &&
> +                               (frmi->height == ov3640_sizes[1].height)) {
> +               /* FIXME: The only frameinterval supported by QXGA capture is
> +                * 2/15 fps
> +                */
> +               if (frmi->index != 0)
> +                       return -EINVAL;
> +       } else {
> +               if (frmi->index >= 3)
> +                       return -EINVAL;
> +       }
> +
> +       frmi->type = V4L2_FRMIVAL_TYPE_DISCRETE;
> +       frmi->discrete.numerator =
> +                               ov3640_frameintervals[frmi->index].numerator;
> +       frmi->discrete.denominator =
> +                               ov3640_frameintervals[frmi->index].denominator;
> +
> +       return 0;
> +}
> +
> +static struct v4l2_int_ioctl_desc ov3640_ioctl_desc[] = {
> +       {vidioc_int_enum_framesizes_num,
> +         (v4l2_int_ioctl_func *)ioctl_enum_framesizes},
> +       {vidioc_int_enum_frameintervals_num,
> +         (v4l2_int_ioctl_func *)ioctl_enum_frameintervals},
> +       {vidioc_int_dev_init_num,
> +         (v4l2_int_ioctl_func *)ioctl_dev_init},
> +       {vidioc_int_dev_exit_num,
> +         (v4l2_int_ioctl_func *)ioctl_dev_exit},
> +       {vidioc_int_s_power_num,
> +         (v4l2_int_ioctl_func *)ioctl_s_power},
> +       {vidioc_int_g_priv_num,
> +         (v4l2_int_ioctl_func *)ioctl_g_priv},
> +       {vidioc_int_init_num,
> +         (v4l2_int_ioctl_func *)ioctl_init},
> +       {vidioc_int_enum_fmt_cap_num,
> +         (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap},
> +       {vidioc_int_try_fmt_cap_num,
> +         (v4l2_int_ioctl_func *)ioctl_try_fmt_cap},
> +       {vidioc_int_g_fmt_cap_num,
> +         (v4l2_int_ioctl_func *)ioctl_g_fmt_cap},
> +       {vidioc_int_s_fmt_cap_num,
> +         (v4l2_int_ioctl_func *)ioctl_s_fmt_cap},
> +       {vidioc_int_g_parm_num,
> +         (v4l2_int_ioctl_func *)ioctl_g_parm},
> +       {vidioc_int_s_parm_num,
> +         (v4l2_int_ioctl_func *)ioctl_s_parm},
> +       {vidioc_int_queryctrl_num,
> +         (v4l2_int_ioctl_func *)ioctl_queryctrl},
> +       {vidioc_int_g_ctrl_num,
> +         (v4l2_int_ioctl_func *)ioctl_g_ctrl},
> +       {vidioc_int_s_ctrl_num,
> +         (v4l2_int_ioctl_func *)ioctl_s_ctrl},
> +         { vidioc_int_g_crop_num,
> +         (v4l2_int_ioctl_func *)ioctl_g_crop},
> +       {vidioc_int_s_crop_num,
> +         (v4l2_int_ioctl_func *)ioctl_s_crop},
> +         { vidioc_int_cropcap_num,
> +         (v4l2_int_ioctl_func *)ioctl_cropcap},
> +};
> +
> +static struct v4l2_int_slave ov3640_slave = {
> +       .ioctls         = ov3640_ioctl_desc,
> +       .num_ioctls     = ARRAY_SIZE(ov3640_ioctl_desc),
> +};
> +
> +static struct v4l2_int_device ov3640_int_device = {
> +       .module = THIS_MODULE,
> +       .name   = OV3640_DRIVER_NAME,
> +       .priv   = &ov3640,
> +       .type   = v4l2_int_type_slave,
> +       .u      = {
> +               .slave = &ov3640_slave,
> +       },
> +};
> +
> +/*
> + * ov3640_probe - sensor driver i2c probe handler
> + * @client: i2c driver client device structure
> + *
> + * Register sensor as an i2c client device and V4L2
> + * device.
> + */
> +static int __init
> +ov3640_probe(struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +       struct ov3640_sensor *sensor = &ov3640;
> +       int err;
> +
> +       if (i2c_get_clientdata(client))
> +               return -EBUSY;
> +
> +       sensor->pdata = client->dev.platform_data;
> +
> +       if (!sensor->pdata) {
> +               dev_err(&client->dev, "No platform data?\n");
> +               return -ENODEV;
> +       }
> +
> +       sensor->v4l2_int_device = &ov3640_int_device;
> +       sensor->i2c_client = client;
> +
> +       i2c_set_clientdata(client, sensor);
> +
> +       /* Make the default capture format XGA RGB565 */
> +       sensor->pix.width = ov3640_sizes[XGA].width;
> +       sensor->pix.height = ov3640_sizes[XGA].height;
> +       sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
> +
> +       err = v4l2_int_device_register(sensor->v4l2_int_device);
> +       if (err)
> +               i2c_set_clientdata(client, NULL);
> +
> +       return 0;
> +}
> +
> +/*
> + * ov3640_remove - sensor driver i2c remove handler
> + * @client: i2c driver client device structure
> + *
> + * Unregister sensor as an i2c client device and V4L2
> + * device. Complement of ov3640_probe().
> + */
> +static int __exit
> +ov3640_remove(struct i2c_client *client)
> +{
> +       struct ov3640_sensor *sensor = i2c_get_clientdata(client);
> +
> +       if (!client->adapter)
> +               return -ENODEV; /* our client isn't attached */
> +
> +       v4l2_int_device_unregister(sensor->v4l2_int_device);
> +       i2c_set_clientdata(client, NULL);
> +
> +       return 0;
> +}
> +
> +static const struct i2c_device_id ov3640_id[] = {
> +       { OV3640_DRIVER_NAME, 0 },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(i2c, ov3640_id);
> +
> +static struct i2c_driver ov3640sensor_i2c_driver = {
> +       .driver = {
> +               .name   = OV3640_DRIVER_NAME,
> +               .owner = THIS_MODULE,
> +       },
> +       .probe  = ov3640_probe,
> +       .remove = __exit_p(ov3640_remove),
> +       .id_table = ov3640_id,
> +};
> +
> +static struct ov3640_sensor ov3640 = {
> +       .timeperframe = {
> +               .numerator = 1,
> +               .denominator = 15,
> +       },
> +       .state = SENSOR_NOT_DETECTED,
> +};
> +
> +/*
> + * ov3640sensor_init - sensor driver module_init handler
> + *
> + * Registers driver as an i2c client driver.  Returns 0 on success,
> + * error code otherwise.
> + */
> +static int __init ov3640sensor_init(void)
> +{
> +       int err;
> +
> +       err = i2c_add_driver(&ov3640sensor_i2c_driver);
> +       if (err) {
> +               printk(KERN_ERR "Failed to register" OV3640_DRIVER_NAME ".\n");
> +               return err;
> +       }
> +       return 0;
> +}
> +module_init(ov3640sensor_init);
> +
> +/*
> + * ov3640sensor_cleanup - sensor driver module_exit handler
> + *
> + * Unregisters/deletes driver as an i2c client driver.
> + * Complement of ov3640sensor_init.
> + */
> +static void __exit ov3640sensor_cleanup(void)
> +{
> +       i2c_del_driver(&ov3640sensor_i2c_driver);
> +}
> +module_exit(ov3640sensor_cleanup);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("OV3640 camera sensor driver");
> +
> +
> diff --git a/drivers/media/video/ov3640_regs.h b/drivers/media/video/ov3640_regs.h
> new file mode 100644
> index 0000000..735be86
> --- /dev/null
> +++ b/drivers/media/video/ov3640_regs.h
> @@ -0,0 +1,600 @@
> +/*
> + * drivers/media/video/ov3640_regs.h
> + *
> + * Register definitions for the OV3640 CameraChip.
> + *
> + * Contributors:
> + *   Pallavi Kulkarni <p-kulkarni@ti.com>
> + *   Sergio Aguirre <saaguirre@ti.com>
> + *
> + * Copyright (C) 2009 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.
> + */
> +
> +#ifndef OV3640_REGS_H
> +#define OV3640_REGS_H
> +
> +/*
> + * System Control Registers
> + */
> +#define OV3640_AGC_H                           0x3000
> +#define OV3640_AGC_L                           0x3001
> +#define OV3640_AEC_H                           0x3002
> +#define OV3640_AEC_L                           0x3003
> +#define OV3640_AECL                            0x3004
> +#define OV3640_RED                             0x3005
> +#define OV3640_GREEN                           0x3006
> +#define OV3640_BLUE                            0x3007
> +#define OV3640_PIDH                            0x300A
> +#define OV3640_PIDL                            0x300B
> +#define OV3640_SCCB_ID                         0x300C
> +#define OV3640_PCLK                            0x300D
> +#define OV3640_PCLK_HREFQUAL_OUT               (1 << 5)
> +#define OV3640_PCLK_REVERSE                    (1 << 4)
> +#define OV3640_PCLK_DIVBY4                     (1 << 1)
> +#define OV3640_PCLK_DIVBY2                     1
> +
> +#define OV3640_PLL_1                           0x300E
> +#define OV3640_PLL_1_RXPLL_MASK                        0x3F
> +
> +#define OV3640_PLL_2                           0x300F
> +#define OV3640_PLL_2_FREQDIV_MASK              (0x3 << 6)
> +#define OV3640_PLL_2_FREQDIV_1                 (0x0 << 6)
> +#define OV3640_PLL_2_FREQDIV_1_5               (0x1 << 6)
> +#define OV3640_PLL_2_FREQDIV_2                 (0x2 << 6)
> +#define OV3640_PLL_2_FREQDIV_3                 (0x3 << 6)
> +
> +#define OV3640_PLL_2_BIT8DIV_MASK              (0x3 << 4)
> +#define OV3640_PLL_2_BIT8DIV_1                 (0x0 << 4)
> +#define OV3640_PLL_2_BIT8DIV_1_2               (0x1 << 4)
> +#define OV3640_PLL_2_BIT8DIV_4                 (0x2 << 4)
> +#define OV3640_PLL_2_BIT8DIV_5                 (0x3 << 4)
> +#define OV3640_PLL_2_BYPASS                    (1 << 3)
> +
> +#define OV3640_PLL_2_INDIV_MASK                        0x3
> +#define OV3640_PLL_2_INDIV_1                   0x0
> +#define OV3640_PLL_2_INDIV_1_5                 0x1
> +#define OV3640_PLL_2_INDIV_2                   0x2
> +#define OV3640_PLL_2_INDIV_3                   0x3
> +
> +#define OV3640_PLL_3                           0x3010
> +#define OV3640_PLL_3_DVPDIV_MASK               (0x3 << 6)
> +#define OV3640_PLL_3_DVPDIV_1                  (0x0 << 6)
> +#define OV3640_PLL_3_DVPDIV_2                  (0x1 << 6)
> +#define OV3640_PLL_3_DVPDIV_8                  (0x2 << 6)
> +#define OV3640_PLL_3_DVPDIV_16                 (0x3 << 6)
> +
> +#define OV3640_PLL_3_LANEDIV2LANES             (1 << 5)
> +#define OV3640_PLL_3_SENSORDIV2                        (1 << 4)
> +
> +#define OV3640_PLL_3_SCALEDIV_MASK             0xF
> +
> +#define OV3640_CLK                             0x3011
> +#define OV3640_CLK_DFREQDBL                    (1 << 7)
> +#define OV3640_CLK_SLAVEMODE                   (1 << 6)
> +#define OV3640_CLK_DIV_MASK                    0x3F
> +
> +#define OV3640_SYS                             0x3012
> +#define OV3640_SYS_SRST                                (1 << 7)
> +#define OV3640_SYS_BASERES_MASK                        (0x7 << 4)
> +#define OV3640_SYS_BASERES_QXGA                        (0x0 << 4)
> +#define OV3640_SYS_BASERES_XGA                 (0x1 << 4)
> +#define OV3640_SYS_BASERES_SXGA                        (0x7 << 4)
> +
> +#define OV3640_AUTO_1                          0x3013
> +#define OV3640_AUTO_1_FASTAEC                  (1 << 7)
> +#define OV3640_AUTO_1_AECBIGSTEPS              (1 << 6)
> +#define OV3640_AUTO_1_BANDINGFILTEREN          (1 << 5)
> +#define OV3640_AUTO_1_AUTOBANDINGFILTER                (1 << 4)
> +#define OV3640_AUTO_1_EXTRBRIGHTEXPEN          (1 << 3)
> +#define OV3640_AUTO_1_AGCEN                    (1 << 2)
> +#define OV3640_AUTO_1_AECEN                    1
> +
> +#define OV3640_AUTO_2                          0x3014
> +#define OV3640_AUTO_2_MANBANDING50             (1 << 7)
> +#define OV3640_AUTO_2_AUTOBANDINGDETEN         (1 << 6)
> +#define OV3640_AUTO_2_AGCADDLT1F               (1 << 5)
> +#define OV3640_AUTO_2_FREEZEAECAGC             (1 << 4)
> +#define OV3640_AUTO_2_NIGHTMODEEN              (1 << 3)
> +#define OV3640_AUTO_2_BANDINGSMOOTHSW          (1 << 2)
> +#define OV3640_AUTO_2_MANEXTRBRIGHTEXPEN       (1 << 1)
> +#define OV3640_AUTO_2_BANDINGFILTEREN          1
> +
> +#define OV3640_AUTO_3                          0x3015
> +#define OV3640_AUTO_3_DUMMYFC_MASK             (0x7 << 4)
> +#define OV3640_AUTO_3_DUMMYFC_NONE             (0x0 << 4)
> +#define OV3640_AUTO_3_DUMMYFC_1FRAME           (0x1 << 4)
> +#define OV3640_AUTO_3_DUMMYFC_2FRAME           (0x2 << 4)
> +#define OV3640_AUTO_3_DUMMYFC_3FRAME           (0x3 << 4)
> +#define OV3640_AUTO_3_DUMMYFC_7FRAME           (0x7 << 4)
> +
> +#define OV3640_AUTO_3_AGCGAINCEIL_MASK         0x7
> +#define OV3640_AUTO_3_AGCGAINCEIL_2X           0x0
> +#define OV3640_AUTO_3_AGCGAINCEIL_4X           0x1
> +#define OV3640_AUTO_3_AGCGAINCEIL_8X           0x2
> +#define OV3640_AUTO_3_AGCGAINCEIL_16X          0x3
> +#define OV3640_AUTO_3_AGCGAINCEIL_32X          0x4
> +#define OV3640_AUTO_3_AGCGAINCEIL_64X          0x5
> +#define OV3640_AUTO_3_AGCGAINCEIL_128X         0x6
> +#define OV3640_AUTO_3_AGCGAINCEIL_128X_2       0x7
> +
> +#define OV3640_AUTO_5                          0x3017
> +#define OV3640_AUTO_5_MANBANDINGCNT_MASK       0x3F
> +
> +#define OV3640_WPT_HISH                                0x3018
> +#define OV3640_BPT_HISL                                0x3019
> +#define OV3640_VPT                             0x301A
> +#define OV3640_YAVG                            0x301B
> +#define OV3640_AECG_MAX50                      0x301C
> +#define OV3640_AECG_MAX60                      0x301D
> +#define OV3640_RZM_H                           0x301E
> +#define OV3640_RZM_L                           0x301F
> +
> +#define OV3640_HS_H                            0x3020
> +#define OV3640_HS_L                            0x3021
> +#define OV3640_VS_H                            0x3022
> +#define OV3640_VS_L                            0x3023
> +#define OV3640_HW_H                            0x3024
> +#define OV3640_HW_L                            0x3025
> +#define OV3640_VH_H                            0x3026
> +#define OV3640_VH_L                            0x3027
> +#define OV3640_HTS_H                           0x3028
> +#define OV3640_HTS_L                           0x3029
> +#define OV3640_VTS_H                           0x302A
> +#define OV3640_VTS_L                           0x302B
> +#define OV3640_EXHTS                           0x302C
> +#define OV3640_EXVTS_H                         0x302D
> +#define OV3640_EXVTS_L                         0x302E
> +
> +#define OV3640_WEIGHT0                         0x3030
> +#define OV3640_WEIGHT1                         0x3031
> +#define OV3640_WEIGHT2                         0x3032
> +#define OV3640_WEIGHT3                         0x3033
> +#define OV3640_WEIGHT4                         0x3034
> +#define OV3640_WEIGHT5                         0x3035
> +#define OV3640_WEIGHT6                         0x3036
> +#define OV3640_WEIGHT7                         0x3037
> +#define OV3640_AHS_H                           0x3038
> +#define OV3640_AHS_L                           0x3039
> +#define OV3640_AVS_H                           0x303A
> +#define OV3640_AVS_L                           0x303B
> +#define OV3640_AHW_H                           0x303C
> +#define OV3640_AHW_L                           0x303D
> +#define OV3640_AVH_H                           0x303E
> +#define OV3640_AVH_L                           0x303F
> +
> +#define OV3640_HISTO0                          0x3040
> +#define OV3640_HISTO1                          0x3041
> +#define OV3640_HISTO2                          0x3042
> +#define OV3640_HISTO3                          0x3043
> +#define OV3640_HISTO4                          0x3044
> +#define OV3640_HISTO5                          0x3045
> +#define OV3640_HISTO6                          0x3046
> +#define OV3640_HISTO7                          0x3047
> +#define OV3640_D56C1                           0x3048
> +
> +#define OV3640_BLC9                            0x3069
> +
> +#define OV3640_BD50_H                          0x3070
> +#define OV3640_BD50_L                          0x3071
> +#define OV3640_BD60_H                          0x3072
> +#define OV3640_BD60_L                          0x3073
> +#define OV3640_VSYNCOPT                                0x3075
> +#define OV3640_TMC1                            0x3077
> +#define OV3640_TMC1_CHSYNCSWAP                 (1 << 7)
> +#define OV3640_TMC1_HREFSWAP                   (1 << 6)
> +#define OV3640_TMC1_HREFPOL_NEG                        (1 << 3)
> +#define OV3640_TMC1_VSYNCPOL_NEG               (1 << 1)
> +#define OV3640_TMC1_HSYNCPOL_NEG               1
> +
> +#define OV3640_TMC2                            0x3078
> +#define OV3640_TMC2_VSYNCDROP                  (1 << 1)
> +#define OV3640_TMC2_FRAMEDATADROP              1
> +
> +#define OV3640_TMC3                            0x3079
> +#define OV3640_TMC3_VSLATCH                    (1 << 7)
> +
> +#define OV3640_TMC4                            0x307A
> +#define OV3640_TMC5                            0x307B
> +#define OV3640_TMC5_AWB_GAINWRITE_DIS          (1 << 7)
> +#define OV3640_TMC5_DCOLORBAREN                        (1 << 3)
> +#define OV3640_TMC5_DCOLORBARPAT_MASK          0x7
> +
> +#define OV3640_TMC6                            0x307C
> +#define OV3640_TMC6_DGAINEN                    (1 << 5)
> +#define OV3640_TMC6_HMIRROR                    (1 << 1)
> +#define OV3640_TMC6_VFLIP                      (1 << 0)
> +
> +#define OV3640_TMC7                            0x307D
> +#define OV3640_TMC7_COLORBARTESTPATEN          (1 << 7)
> +#define OV3640_TMC7_AVGHIST_SENSOR             (1 << 5)
> +
> +#define OV3640_TMC8                            0x307E
> +
> +#define OV3640_TMCA                            0x3080
> +#define OV3640_TMCB                            0x3081
> +#define OV3640_TMCB_MIRROROPTEN                        (1 << 7)
> +#define OV3640_TMCB_OTPFASTMEMCLK              (1 << 6)
> +#define OV3640_TMCB_SWAPBYTESOUT               1
> +
> +#define OV3640_TMCF                            0x3085
> +#define OV3640_TMC10                           0x3086
> +#define OV3640_TMC10_SYSRST                    (1 << 3)
> +#define OV3640_TMC10_REGSLEEPOPT               (1 << 2)
> +#define OV3640_TMC10_SLEEPOPT                  (1 << 1)
> +#define OV3640_TMC10_SLEEPEN                   1
> +
> +#define OV3640_TMC11                           0x3087
> +#define OV3640_ISP_XOUT_H                      0x3088
> +#define OV3640_ISP_XOUT_L                      0x3089
> +#define OV3640_ISP_YOUT_H                      0x308A
> +#define OV3640_ISP_YOUT_L                      0x308B
> +#define OV3640_TMC13                           0x308D
> +#define OV3640_5060                            0x308E
> +#define OV3640_OTP                             0x308F
> +
> +#define OV3640_IO_CTRL0                                0x30B0
> +#define OV3640_IO_CTRL1                                0x30B1
> +#define OV3640_IO_CTRL2                                0x30B2
> +#define OV3640_DVP0                            0x30B4
> +#define OV3640_DVP1                            0x30B5
> +#define OV3640_DVP2                            0x30B6
> +#define OV3640_DVP3                            0x30B7
> +#define OV3640_DSPC0                           0x30B8
> +#define OV3640_DSPC1                           0x30B9
> +#define OV3640_DSPC2                           0x30BA
> +#define OV3640_DSPC3                           0x30BB
> +#define OV3640_DSPC7                           0x30BF
> +/*
> + * END - System Control Registers
> + */
> +
> +/*
> + * SC Registers
> + */
> +#define OV3640_SC_CTRL0                                0x3100
> +#define OV3640_SC_CTRL2                                0x3102
> +#define OV3640_SC_SYN_CTRL0                    0x3104
> +#define OV3640_SC_SYN_CTRL1                    0x3105
> +#define OV3640_SC_SYN_CTRL2                    0x3106
> +#define OV3640_SC_SYN_CTRL3                    0x3107
> +/*
> + * END - SC Registers
> + */
> +
> +/*
> + * CIF Registers
> + */
> +#define OV3640_CIF_CTRL0                       0x3200
> +#define OV3640_CIF_CTRL4                       0x3204
> +/*
> + * END - CIF Registers
> + */
> +
> +/*
> + * DSP Registers
> + */
> +#define OV3640_DSP_CTRL_0                      0x3300
> +#define OV3640_DSP_CTRL_1                      0x3301
> +#define OV3640_DSP_CTRL_2                      0x3302
> +#define OV3640_DSP_CTRL_4                      0x3304
> +#define OV3640_AWB_CTRL_3                      0x3308
> +
> +#define OV3640_YST1                            0x331B
> +#define OV3640_YST2                            0x331C
> +#define OV3640_YST3                            0x331D
> +#define OV3640_YST4                            0x331E
> +#define OV3640_YST5                            0x331F
> +
> +#define OV3640_YST6                            0x3320
> +#define OV3640_YST7                            0x3321
> +#define OV3640_YST8                            0x3322
> +#define OV3640_YST9                            0x3323
> +#define OV3640_YST10                           0x3324
> +#define OV3640_YST11                           0x3325
> +#define OV3640_YST12                           0x3326
> +#define OV3640_YST13                           0x3327
> +#define OV3640_YST14                           0x3328
> +#define OV3640_YST15                           0x3329
> +#define OV3640_YSLP15                          0x332A
> +#define OV3640_MISC_CTRL                       0x332B
> +#define OV3640_DNS_TH                          0x332C
> +#define OV3640_Y_EDGE_MT                       0x332D
> +#define OV3640_Y_EDGE_TH_TM                    0x332E
> +#define OV3640_BASE1                           0x332F
> +
> +#define OV3640_BASE2                           0x3330
> +#define OV3640_OFFSET                          0x3331
> +#define OV3640_CMXSIGN_MISC                    0x333F
> +
> +#define OV3640_CMX_1                           0x3340
> +#define OV3640_CMX_2                           0x3341
> +#define OV3640_CMX_3                           0x3342
> +#define OV3640_CMX_4                           0x3343
> +#define OV3640_CMX_5                           0x3344
> +#define OV3640_CMX_6                           0x3345
> +#define OV3640_CMX_7                           0x3346
> +#define OV3640_CMX_8                           0x3347
> +#define OV3640_CMX_9                           0x3348
> +#define OV3640_CMXSIGN                         0x3349
> +
> +#define OV3640_SGNSET                          0x3354
> +#define OV3640_SDE_CTRL                                0x3355
> +#define OV3640_HUE_COS                         0x3356
> +#define OV3640_HUE_SIN                         0x3357
> +#define OV3640_SAT_U                           0x3358
> +#define OV3640_SAT_V                           0x3359
> +#define OV3640_UREG                            0x335A
> +#define OV3640_VREG                            0x335B
> +#define OV3640_YOFFSET                         0x335C
> +#define OV3640_YGAIN                           0x335D
> +#define OV3640_YBRIGHT                         0x335E
> +#define OV3640_SIZE_IN_MISC                    0x335F
> +
> +#define OV3640_HSIZE_IN_L                      0x3360
> +#define OV3640_VSIZE_IN_L                      0x3361
> +#define OV3640_SIZE_OUT_MISC                   0x3362
> +#define OV3640_HSIZE_OUT_L                     0x3363
> +#define OV3640_VSIZE_OUT_L                     0x3364
> +
> +#define OV3640_R_XY0                           0x3367
> +#define OV3640_R_X0                            0x3368
> +#define OV3640_R_Y0                            0x3369
> +#define OV3640_R_A1                            0x336A
> +#define OV3640_R_A2_B2                         0x336B
> +#define OV3640_R_B1                            0x336C
> +#define OV3640_G_XY0                           0x336D
> +#define OV3640_G_X0                            0x336E
> +#define OV3640_G_Y0                            0x336F
> +
> +#define OV3640_G_A1                            0x3370
> +#define OV3640_G_A2_B2                         0x3371
> +#define OV3640_G_B1                            0x3372
> +#define OV3640_B_XY0                           0x3373
> +#define OV3640_B_X0                            0x3374
> +#define OV3640_B_Y0                            0x3375
> +#define OV3640_B_A1                            0x3376
> +#define OV3640_B_A2_B2                         0x3377
> +#define OV3640_B_B1                            0x3378
> +
> +#define OV3640_MISC_DCW_SIZE                   0x33A4
> +#define OV3640_DCW_OH                          0x33A5
> +#define OV3640_DCW_OV                          0x33A6
> +#define OV3640_R_GAIN_M                                0x33A7
> +#define OV3640_G_GAIN_M                                0x33A8
> +#define OV3640_B_GAIN_M                                0x33A9
> +#define OV3640_OVLY_MISC1                      0x33AA
> +#define OV3640_OVLY_LEFT                       0x33AB
> +#define OV3640_OVLY_TOP                                0x33AC
> +#define OV3640_OVLY_MISC2                      0x33AD
> +#define OV3640_OVLY_RIGHT                      0x33AE
> +#define OV3640_OVLY_BOTTEM                     0x33AF
> +
> +#define OV3640_OVLY_MISC3                      0x33B0
> +#define OV3640_OVLY_EXT_WIDTH_H                        0x33B1
> +#define OV3640_OVLY_EXT_WIDTH_L                        0x33B2
> +#define OV3640_OVLY_Y                          0x33B3
> +#define OV3640_OVLY_U                          0x33B4
> +#define OV3640_OVLY_V                          0x33B5
> +/*
> + * END - DSP Registers
> + */
> +
> +/*
> + * FMT MUX Registers
> + */
> +#define OV3640_FMT_MUX_CTRL0                   0x3400
> +#define OV3640_ISP_PAD_CTR2                    0x3403
> +#define OV3640_FMT_CTRL00                      0x3404
> +#define OV3640_FMT_CTRL00_UV_sel_SHIFT         7
> +#define OV3640_FMT_CTRL00_UV_sel_MASK          (0x1 << \
> +                                               OV3640_FMT_CTRL00_UV_sel_SHIFT)
> +#define OV3640_FMT_CTRL00_UV_sel_USE_UV_avg_Y  (0x0 << \
> +                                               OV3640_FMT_CTRL00_UV_sel_SHIFT)
> +#define OV3640_FMT_CTRL00_UV_sel_USE_U0Y0_V0Y1 (0x1 << \
> +                                               OV3640_FMT_CTRL00_UV_sel_SHIFT)
> +
> +#define OV3640_FMT_CTRL00_YUV422_in_SHIFT      6
> +#define OV3640_FMT_CTRL00_YUV422_in_MASK       (0x1 << \
> +                                       OV3640_FMT_CTRL00_YUV422_in_SHIFT)
> +#define OV3640_FMT_CTRL00_YUV422_in_DISABLE    (0x0 << \
> +                                       OV3640_FMT_CTRL00_YUV422_in_SHIFT)
> +#define OV3640_FMT_CTRL00_YUV422_in_ENABLE     (0x1 << \
> +                                       OV3640_FMT_CTRL00_YUV422_in_SHIFT)
> +
> +#define OV3640_FMT_CTRL00_FMT_SHIFT            0
> +#define OV3640_FMT_CTRL00_FMT_MASK             (0x3F << \
> +                                               OV3640_FMT_CTRL00_FMT_SHIFT)
> +#define OV3640_DITHER_CTRL0                    0x3405
> +/*
> + * END - FMT MUX Registers
> + */
> +
> +/*
> + * OUT_TOP Registers
> + */
> +#define OV3640_OUT_CTRL00                      0x3600
> +#define OV3640_OUT_CTRL00_VSYNCSEL2            (1 << 7)
> +#define OV3640_OUT_CTRL00_VSYNCGATE            (1 << 6)
> +#define OV3640_OUT_CTRL00_PCLKPOL_NEG          (1 << 4)
> +#define OV3640_OUT_CTRL00_HREFPOL_NEG          (1 << 3)
> +#define OV3640_OUT_CTRL00_VSYNCPOL_NEG         (1 << 2)
> +#define OV3640_OUT_CTRL00_VSYNCSEL             (1 << 1)
> +#define OV3640_OUT_CTRL00_DVPOUTDATAORDERINV   1
> +
> +#define OV3640_OUT_CTRL01                      0x3601
> +#define OV3640_OUT_CTRL01_PCLKGATEEN           (1 << 7)
> +#define OV3640_OUT_CTRL01_CCIR656EN            (1 << 4)
> +#define OV3640_OUT_CTRL01_MIPIBIT8             1
> +
> +#define OV3640_MIPI_CTRL02                     0x3602
> +#define OV3640_MIPI_CTRL02_DVPDISABLE          (1 << 4)
> +#define OV3640_MIPI_CTRL02_MIPILINESYNCEN      (1 << 2)
> +#define OV3640_MIPI_CTRL02_MIPIGATESCEN                (1 << 1)
> +
> +#define OV3640_MIPI_CTRL03                     0x3603
> +#define OV3640_MIPI_CTRL03_ECC_PHBYTEORDER     (1 << 2)
> +#define OV3640_MIPI_CTRL03_ECC_PHBITORDER      (1 << 1)
> +
> +#define OV3640_OUT_CTRL08                      0x3608
> +#define OV3640_OUT_CTRL08_HREF_DLY_SHIFT       4
> +#define OV3640_OUT_CTRL08_HREF_DLY_MASK                (0xF << \
> +                                       OV3640_OUT_CTRL08_HREF_DLY_SHIFT)
> +
> +
> +#define OV3640_OUT_CTRL09                      0x3609
> +#define OV3640_OUT_CTRL0A                      0x360A
> +#define OV3640_OUT_CTRL0B                      0x360B
> +#define OV3640_MIPI_CTRL0C                     0x360C
> +#define OV3640_MIPI_CTRL0C_VIRTUALCH_ID_MASK   (0x3 << 6)
> +
> +#define OV3640_OUT_CTRL0D                      0x360D
> +#define OV3640_MIPI_CTRL0E                     0x360E
> +#define OV3640_MIPI_CTRL0E_WKUPDELAY_MASK      0x3F
> +
> +
> +#define OV3640_MIPI_CTRL10                     0x3610
> +#define OV3640_MIPI_CTRL10_WIDTH_MAN_L_MASK    0xFF
> +
> +#define OV3640_MIPI_CTRL11                     0x3611
> +#define OV3640_MIPI_CTRL11_WIDTH_MAN_H_MASK    (0x7 << 5)
> +
> +#define OV3640_CLIP_MIN                                0x3614
> +#define OV3640_CLIP_MAX                                0x3615
> +#define OV3640_OUT_CTRL16                      0x3616
> +#define OV3640_OUT_CTRL1D                      0x361D
> +#define OV3640_OUT_CTRL1E                      0x361E
> +#define OV3640_MIPI_CTRL1F                     0x361F
> +#define OV3640_MIPI_CTRL1F_PCLK_PERIOD_MASK    0xFF
> +
> +#define OV3640_MIPI_CTRL22                     0x3622
> +#define OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_SHIFT       2
> +#define OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_MASK                (0x3F << \
> +                               OV3640_MIPI_CTRL22_MIN_HS_ZERO_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL22_MIN_HS_ZERO_H_MASK  0x3
> +
> +#define OV3640_MIPI_CTRL23                     0x3623
> +#define OV3640_MIPI_CTRL23_MIN_HS_ZERO_L_MASK  0xFF
> +
> +#define OV3640_MIPI_CTRL24                     0x3624
> +#define OV3640_MIPI_CTRL24_MIN_HS_TRAIL_NUI_SHIFT      2
> +#define OV3640_MIPI_CTRL24_MIN_HS_TRAIL_NUI_MASK       (0x3F << \
> +                               OV3640_MIPI_CTRL24_MIN_HS_TRAIL_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL24_MIN_HS_TRAIL_H_MASK 0x3
> +
> +#define OV3640_MIPI_CTRL25                     0x3625
> +#define OV3640_MIPI_CTRL25_MIN_HS_TRAIL_L_MASK 0xFF
> +
> +#define OV3640_MIPI_CTRL26                     0x3626
> +#define OV3640_MIPI_CTRL26_MIN_CLK_ZERO_NUI_SHIFT      2
> +#define OV3640_MIPI_CTRL26_MIN_CLK_ZERO_NUI_MASK       (0x3F << \
> +                               OV3640_MIPI_CTRL26_MIN_CLK_ZERO_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL26_MIN_CLK_ZERO_H_MASK 0x3
> +
> +#define OV3640_MIPI_CTRL27                     0x3627
> +#define OV3640_MIPI_CTRL27_MIN_CLK_ZERO_L_MASK 0xFF
> +
> +#define OV3640_MIPI_CTRL28                     0x3628
> +#define OV3640_MIPI_CTRL28_MIN_CLK_PREPARE_NUI_SHIFT   2
> +#define OV3640_MIPI_CTRL28_MIN_CLK_PREPARE_NUI_MASK            (0x3F << \
> +                               OV3640_MIPI_CTRL28_MIN_CLK_PREPARE_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL28_MIN_CLK_PREPARE_H_MASK      0x3
> +
> +#define OV3640_MIPI_CTRL29                     0x3629
> +#define OV3640_MIPI_CTRL29_MIN_CLK_PREPARE_L_MASK      0xFF
> +
> +#define OV3640_MIPI_CTRL2A                     0x362A
> +#define OV3640_MIPI_CTRL2A_MAX_CLK_PREPARE_NUI_SHIFT   2
> +#define OV3640_MIPI_CTRL2A_MAX_CLK_PREPARE_NUI_MASK            (0x3F << \
> +                               OV3640_MIPI_CTRL2A_MAX_CLK_PREPARE_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL2A_MAX_CLK_PREPARE_H_MASK      0x3
> +
> +#define OV3640_MIPI_CTRL2B                     0x362B
> +#define OV3640_MIPI_CTRL2B_MAX_CLK_PREPARE_L_MASK      0xFF
> +
> +#define OV3640_MIPI_CTRL2C                     0x362C
> +#define OV3640_MIPI_CTRL2C_MIN_CLK_POST_NUI_SHIFT      2
> +#define OV3640_MIPI_CTRL2C_MIN_CLK_POST_NUI_MASK       (0x3F << \
> +                               OV3640_MIPI_CTRL2C_MIN_CLK_POST_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL2C_MIN_CLK_POST_H_MASK 0x3
> +
> +#define OV3640_MIPI_CTRL2D                     0x362D
> +#define OV3640_MIPI_CTRL2D_MIN_CLK_POST_L_MASK 0xFF
> +
> +#define OV3640_MIPI_CTRL2E                     0x362E
> +#define OV3640_MIPI_CTRL2E_MIN_CLK_TRAIL_NUI_SHIFT     2
> +#define OV3640_MIPI_CTRL2E_MIN_CLK_TRAIL_NUI_MASK      (0x3F << \
> +                               OV3640_MIPI_CTRL2E_MIN_CLK_TRAIL_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL2E_MIN_CLK_TRAIL_H_MASK        0x3
> +
> +#define OV3640_MIPI_CTRL2F                     0x362F
> +#define OV3640_MIPI_CTRL2F_MIN_CLK_TRAIL_L_MASK        0xFF
> +
> +#define OV3640_MIPI_CTRL30                     0x3630
> +#define OV3640_MIPI_CTRL30_MIN_LPX_P_NUI_SHIFT 2
> +#define OV3640_MIPI_CTRL30_MIN_LPX_P_NUI_MASK  (0x3F << \
> +                                       OV3640_MIPI_CTRL30_MIN_LPX_P_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL30_MIN_LPX_P_H_MASK    0x3
> +
> +#define OV3640_MIPI_CTRL31                     0x3631
> +#define OV3640_MIPI_CTRL31_MIN_LPX_P_L_MASK    0xFF
> +
> +#define OV3640_MIPI_CTRL32                     0x3632
> +#define OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_SHIFT    2
> +#define OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_MASK     (0x3F << \
> +                               OV3640_MIPI_CTRL32_MIN_HS_PREPARE_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL32_MIN_HS_PREPARE_H_MASK       0x3
> +
> +#define OV3640_MIPI_CTRL33                     0x3633
> +#define OV3640_MIPI_CTRL33_MIN_HS_PREPARE_L_MASK       0xFF
> +
> +#define OV3640_MIPI_CTRL34                     0x3634
> +#define OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_SHIFT    2
> +#define OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_MASK     (0x3F << \
> +                               OV3640_MIPI_CTRL34_MAX_HS_PREPARE_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL34_MAX_HS_PREPARE_H_MASK       0x3
> +
> +#define OV3640_MIPI_CTRL35                     0x3635
> +#define OV3640_MIPI_CTRL35_MAX_HS_PREPARE_L_MASK       0xFF
> +
> +#define OV3640_MIPI_CTRL36                     0x3636
> +#define OV3640_MIPI_CTRL36_MIN_HS_EXIT_NUI_SHIFT       2
> +#define OV3640_MIPI_CTRL36_MIN_HS_EXIT_NUI_MASK        (0x3F << \
> +                               OV3640_MIPI_CTRL36_MIN_HS_EXIT_NUI_SHIFT)
> +#define OV3640_MIPI_CTRL36_MIN_HS_EXIT_H_MASK  0x3
> +
> +#define OV3640_MIPI_CTRL37                     0x3637
> +#define OV3640_MIPI_CTRL37_MIN_HS_EXIT_L_MASK  0xFF
> +
> +#define OV3640_OUT_CTRL3C                      0x363C
> +#define OV3640_MIPI_CTRL3D                     0x363D
> +#define OV3640_MIPI_CTRL3D_JPGPADEN            (1 << 6)
> +#define OV3640_OUT_CTRL3E                      0x363E
> +#define OV3640_OUT_CTRL3F                      0x363F
> +
> +#define OV3640_OUT_CTRL40                      0x3640
> +#define OV3640_OUT_CTRL43                      0x3643
> +#define OV3640_OUT_CTRL44                      0x3644
> +#define OV3640_OUT_CTRL46                      0x3646
> +#define OV3640_MIPI_CTRL4C                     0x364C
> +#define OV3640_MIPI_CTRL4C_ECC_PHBYTEORDER2    (1 << 2)
> +/*
> + * END - OUT_TOP Registers
> + */
> +/*
> + * MC Registers
> + */
> +#define OV3640_INTR_MASK0                      0x3700
> +#define OV3640_INTR_MASK1                      0x3701
> +#define OV3640_INTR0                           0x3708
> +#define OV3640_INTR1                           0x3709
> +/*
> + * END - MC Registers
> + */
> +
> +#endif /* ifndef OV3640_REGS_H */
> +
> +
> diff --git a/include/media/ov3640.h b/include/media/ov3640.h
> new file mode 100644
> index 0000000..a26009e
> --- /dev/null
> +++ b/include/media/ov3640.h
> @@ -0,0 +1,31 @@
> +/*
> + * include/media/ov3640.h
> + *
> + * Shared settings for the OV3640 CameraChip.
> + *
> + * Contributors:
> + *   Pallavi Kulkarni <p-kulkarni@ti.com>
> + *   Sergio Aguirre <saaguirre@ti.com>
> + *
> + * Copyright (C) 2009 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.
> + */
> +
> +#ifndef OV3640_H
> +#define OV3640_H
> +
> +#define OV3640_I2C_ADDR                (0x78 >> 1)
> +
> +struct ov3640_platform_data {
> +       /* Set power state, zero is off, non-zero is on. */
> +       int (*power_set)(enum v4l2_power power);
> +       u32 (*set_xclk)(u32 xclkfreq);
> +       int (*priv_data_set)(void *);
> +};
> +
> +#endif /* ifndef OV3640_H */
> +
> +
> --
> 1.5.6.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
-- 
Best regards, Klimov Alexey


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/5] OV3640: Add driver
  2009-03-03 20:44 [PATCH 3/5] OV3640: Add driver Aguirre Rodriguez, Sergio Alberto
  2009-03-05  0:23 ` Alexey Klimov
@ 2009-03-05  1:42 ` Trent Piepho
  2009-03-09 21:00   ` Aguirre Rodriguez, Sergio Alberto
  1 sibling, 1 reply; 8+ messages in thread
From: Trent Piepho @ 2009-03-05  1:42 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: linux-media, linux-omap, Sakari Ailus, Tuukka.O Toivonen,
	Hiroshi DOYU, DongSoo(Nathaniel) Kim, MiaoStanley, Nagalla, Hari,
	Hiremath, Vaibhav, Lakhani, Amish, Menon, Nishanth

On Tue, 3 Mar 2009, Aguirre Rodriguez, Sergio Alberto wrote:
> +       {
> +               /* 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

The V4L2 spec was corrected to define the RGB565 the normal way.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH 3/5] OV3640: Add driver
  2009-03-05  0:23 ` Alexey Klimov
@ 2009-03-09 20:58   ` Aguirre Rodriguez, Sergio Alberto
  2009-03-09 21:29     ` Menon, Nishanth
  0 siblings, 1 reply; 8+ messages in thread
From: Aguirre Rodriguez, Sergio Alberto @ 2009-03-09 20:58 UTC (permalink / raw)
  To: Alexey Klimov
  Cc: linux-media, linux-omap, Sakari Ailus, Tuukka.O Toivonen,
	Hiroshi DOYU, DongSoo(Nathaniel) Kim, MiaoStanley, Nagalla, Hari,
	Hiremath, Vaibhav, Lakhani, Amish, Menon, Nishanth

Hi Alexey,

> -----Original Message-----
> From: Alexey Klimov [mailto:klimov.linux@gmail.com]

<snip>

> > --- /dev/null
> > +++ b/drivers/media/video/ov3640.c
> > @@ -0,0 +1,2202 @@
> > +/*
> > + * drivers/media/video/ov3640.c
> > + *
> > + * ov3640 sensor driver
> > + *
> > + *
> > + * Copyright (C) 2008 Texas Instruments.
> 
> 2009 ?

Fixed.

<snip>

> > +static int ov3640_read_reg(struct i2c_client *client, u16 data_length,
> u16 reg,
> > +                                                               u32
> *val)
> > +{
> > +       int err = 0;
> > +       struct i2c_msg msg[1];
> > +       unsigned char data[4];
> > +
> > +       if (!client->adapter)
> > +               return -ENODEV;
> > +
> > +       msg->addr = client->addr;
> > +       msg->flags = I2C_M_WR;
> > +       msg->len = 2;
> > +       msg->buf = data;
> > +
> > +       /* High byte goes out first */
> > +       data[0] = (u8) (reg >> 8);
> > +       data[1] = (u8) (reg & 0xff);
> > +
> > +       err = i2c_transfer(client->adapter, msg, 1);
> 
> Please, let me understand.. You call i2c_transfer() and ask it to
> transfer one message(third parameter), right ?
> So, the returned value is negative errno or the number of messages
> executed. Logic says that you should check somethin like this:
> 	if (err = 1) {
> 		good;
> 	} else {
> 		i2c_transfer failed;
> 		we should deal with it(printk, try again, etc)
> 	}
> 
> Or even:
> 	if (unlikely(err != 1)) {
> 		i2c_transfer failed;
> 	}
> 	Good code continue;
> 
> Right or wrong ?

The idea of this piece of code is to:

- First do a write transfer with nothing else than the register address to read.
- Then do a I2C read transfer to receive the value from register selected in previous write with the size of data_length variable.

I do agree that perhaps a cleanup for this piece of code needs to be done... I'll clean it up, test, and repost the resulting patch for your review. :)

> 
> > +       if (err >= 0) {
> > +               mdelay(3);
> > +               msg->flags = I2C_M_RD;
> > +               msg->len = data_length;
> > +               err = i2c_transfer(client->adapter, msg, 1);
> > +       }
> > +       if (err >= 0) {
> > +               *val = 0;
> > +               /* High byte comes first */
> > +               if (data_length == 1)
> > +                       *val = data[0];
> > +               else if (data_length == 2)
> > +                       *val = data[1] + (data[0] << 8);
> > +               else
> > +                       *val = data[3] + (data[2] << 8) +
> > +                               (data[1] << 16) + (data[0] << 24);
> > +               return 0;
> > +       }
> > +       dev_err(&client->dev, "read from offset 0x%x error %d", reg,
> err);
> 
> "\n" should be in dev_err.

Done

> 
> > +       return err;
> > +}
> > +
> > +/* Write a value to a register in ov3640 sensor device.
> > + * @client: i2c driver client structure.
> > + * @reg: Address of the register to read value from.
> > + * @val: Value to be written to a specific register.
> > + * Returns zero if successful, or non-zero otherwise.
> > + */
> > +static int ov3640_write_reg(struct i2c_client *client, u16 reg, u8 val)
> > +{
> > +       int err = 0;
> > +       struct i2c_msg msg[1];
> > +       unsigned char data[3];
> > +       int retries = 0;
> > +
> > +       if (!client->adapter)
> > +               return -ENODEV;
> > +retry:
> > +       msg->addr = client->addr;
> > +       msg->flags = I2C_M_WR;
> > +       msg->len = 3;
> > +       msg->buf = data;
> > +
> > +       /* high byte goes out first */
> > +       data[0] = (u8) (reg >> 8);
> > +       data[1] = (u8) (reg & 0xff);
> > +       data[2] = val;
> > +
> > +       err = i2c_transfer(client->adapter, msg, 1);
> > +       udelay(50);
> > +
> > +       if (err >= 0)
> 
> Well, probably all checks of returned values after i2c_transfer should
> be reformatted in right way.

I'll redesign this...

> 
> 
> > +               return 0;
> > +
> > +       if (retries <= 5) {
> > +               dev_dbg(&client->dev, "Retrying I2C... %d", retries);
> 
> "\n"

Done.

<snip>

> > +       /* FIXME: QXGA framerate setting forced to 15 FPS */
> > +       if (isize == QXGA) {
> > +               err = ov3640_write_reg(client, OV3640_PLL_1, 0x32);
> > +               err = ov3640_write_reg(client, OV3640_PLL_2, 0x21);
> > +               err = ov3640_write_reg(client, OV3640_PLL_3, 0x21);
> > +               err = ov3640_write_reg(client, OV3640_CLK, 0x01);
> > +               err = ov3640_write_reg(client, 0x304c, 0x81);
> 
> I see no checking of returned values. For example, if first function
> failed, rest functions will keep going.

Agreed.. I think I'll definitely redesign this to avoid this kind of trouble.

<snip>

> > +
> > +       /* Common registers */
> > +       err = ov3640_write_regs(client, ov3640_common[isize]);
> > +
> > +       /* Configure image size and pixel format */
> > +       err = ov3640_write_regs(client, ov3640_reg_init[pfmt][isize]);
> > +
> > +       /* Setting of frame rate (OV suggested way) */
> > +       err = ov3640_set_framerate(client, &sensor->timeperframe,
> isize);
> > +#ifdef CONFIG_VIDEO_OV3640_CSI2
> > +       /* Set CSI2 common register settings */
> > +       err = ov3640_write_regs(client, ov3640_common_csi2);
> > +#endif
> 
> Again, no checking of err.

Agree, will fix..

<snip>

> > +
> > +               err = ov3640_write_reg(client, OV3640_SIZE_IN_MISC,
> > +                                                       (vsize_h |
> hsize_h));
> > +               err = ov3640_write_reg(client, OV3640_HSIZE_IN_L,
> hsize_l);
> > +               err = ov3640_write_reg(client, OV3640_VSIZE_IN_L,
> vsize_l);
> > +               err = ov3640_write_reg(client, OV3640_SIZE_OUT_MISC,
> > +                                                       (height_h |
> width_h));
> > +               err = ov3640_write_reg(client, OV3640_HSIZE_OUT_L,
> width_l);
> > +               err = ov3640_write_reg(client, OV3640_VSIZE_OUT_L,
> height_l);
> > +               err = ov3640_write_reg(client, OV3640_ISP_PAD_CTR2,
> 0x42);
> > +               err = ov3640_write_reg(client, OV3640_ISP_XOUT_H,
> width_h);
> > +               err = ov3640_write_reg(client, OV3640_ISP_XOUT_L,
> > +                                                       (width_l  -
> 0x08));
> > +               err = ov3640_write_reg(client, OV3640_ISP_YOUT_H,
> > +                                                       (height_h >>
> 4));
> > +               err = ov3640_write_reg(client, OV3640_ISP_YOUT_L,
> > +                                                       (height_l -
> 0x04));
> 
> The same thing here.

Agree, will fix..

<snip> 

> > +static int ioctl_s_ctrl(struct v4l2_int_device *s,
> > +                            struct v4l2_control *vc)
> > +{
> > +       int retval = -EINVAL;
> > +       int i;
> > +       struct ov3640_sensor *sensor = s->priv;
> > +       struct i2c_client *client = sensor->i2c_client;
> > +       struct vcontrol *lvc;
> > +
> > +       i = find_vctrl(vc->id);
> > +       if (i < 0)
> > +               return -EINVAL;
> > +
> > +       lvc = &video_control[i];
> > +
> > +       switch (vc->id) {
> > +       case V4L2_CID_BRIGHTNESS:
> > +               if (vc->value >= 0 && vc->value <= 6) {
> > +                       retval = ov3640_write_regs(client,
> > +                                                       brightness[vc-
> >value]);
> > +               } else {
> > +                       dev_err(&client->dev, "BRIGHTNESS LEVEL NOT
> SUPPORTED");
> > +                       return -EINVAL;
> > +               }
> > +               break;
> > +       case V4L2_CID_CONTRAST:
> > +               if (vc->value >= 0 && vc->value <= 6)
> > +                       retval = ov3640_write_regs(client, contrast[vc-
> >value]);
> > +               else {
> > +                       dev_err(&client->dev, "CONTRAST LEVEL NOT
> SUPPORTED");
> > +                       return -EINVAL;
> > +               }
> > +               break;
> > +       case V4L2_CID_PRIVATE_BASE:
> > +               if (vc->value >= 0 && vc->value <= 2)
> > +                       retval = ov3640_write_regs(client, colors[vc-
> >value]);
> > +               else {
> > +                       dev_err(&client->dev, "COLOR LEVEL NOT
> SUPPORTED");
> > +                       return -EINVAL;
> 
> I don't sure - may be you like big letters in logs..
> Anyway, "\n" is absent in this 3 dev_err.

Ok, removed all caps, and added "\n".

Thanks,
Sergio

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH 3/5] OV3640: Add driver
  2009-03-05  1:42 ` Trent Piepho
@ 2009-03-09 21:00   ` Aguirre Rodriguez, Sergio Alberto
  0 siblings, 0 replies; 8+ messages in thread
From: Aguirre Rodriguez, Sergio Alberto @ 2009-03-09 21:00 UTC (permalink / raw)
  To: Trent Piepho
  Cc: linux-media, linux-omap, Sakari Ailus, Tuukka.O Toivonen,
	Hiroshi DOYU, DongSoo(Nathaniel) Kim, MiaoStanley, Nagalla, Hari,
	Hiremath, Vaibhav, Lakhani, Amish, Menon, Nishanth



> -----Original Message-----
> From: Trent Piepho [mailto:xyzzy@speakeasy.org]
> Sent: Wednesday, March 04, 2009 7:42 PM
> To: Aguirre Rodriguez, Sergio Alberto
> Cc: linux-media@vger.kernel.org; linux-omap@vger.kernel.org; Sakari Ailus;
> Tuukka.O Toivonen; Hiroshi DOYU; DongSoo(Nathaniel) Kim; MiaoStanley;
> Nagalla, Hari; Hiremath, Vaibhav; Lakhani, Amish; Menon, Nishanth
> Subject: Re: [PATCH 3/5] OV3640: Add driver
> 
> On Tue, 3 Mar 2009, Aguirre Rodriguez, Sergio Alberto wrote:
> > +       {
> > +               /* 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
> 
> The V4L2 spec was corrected to define the RGB565 the normal way.

Oh ok.. Didn't knew that..

Removed that note.

Thanks!

Sergio

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH 3/5] OV3640: Add driver
  2009-03-09 20:58   ` Aguirre Rodriguez, Sergio Alberto
@ 2009-03-09 21:29     ` Menon, Nishanth
  2009-03-10  7:29       ` Tuukka.O Toivonen
  0 siblings, 1 reply; 8+ messages in thread
From: Menon, Nishanth @ 2009-03-09 21:29 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto, Alexey Klimov
  Cc: linux-media, linux-omap, Sakari Ailus, Tuukka.O Toivonen,
	Hiroshi DOYU, DongSoo(Nathaniel) Kim, MiaoStanley, Nagalla, Hari,
	Hiremath, Vaibhav, Lakhani, Amish

> -----Original Message-----
> From: Aguirre Rodriguez, Sergio Alberto
> Sent: Monday, March 09, 2009 10:58 PM
> To: Alexey Klimov
> Cc: linux-media@vger.kernel.org; linux-omap@vger.kernel.org; Sakari Ailus;
> Tuukka.O Toivonen; Hiroshi DOYU; DongSoo(Nathaniel) Kim; MiaoStanley;
> Nagalla, Hari; Hiremath, Vaibhav; Lakhani, Amish; Menon, Nishanth
> Subject: RE: [PATCH 3/5] OV3640: Add driver
> 
> 
> > > +       /* FIXME: QXGA framerate setting forced to 15 FPS */
> > > +       if (isize == QXGA) {
<lots of i2c reg writes snip>
> > 4));
> > > +               err = ov3640_write_reg(client, OV3640_ISP_YOUT_L,
> > > +                                                       (height_l -
> > 0x04));
> >
> > The same thing here.
> 
> Agree, will fix..
I wonder if we cannot use an array and fill it up before pumping it out through i2c. something like:
struct configure_array{
	u16 reg;
	u16 val;
}
struct configure_array reg_config[]={
	{OV3640_ISP_YOUT_H, 0x0},
...
};
Then 

for (i=0;i< sizeof(reg_config)/sizeof(configure_array);i++) {
	err = reg_write(reg_config[i].reg, reg_config[i].val);
	if (err) {
		/* do something */
	}
}

Further, we have multiple sensors following CCI[1] - why not have a driver for the same, it will simplify the entire process - ov3640, mt9p012 both follow the spec at least.. dependency would be sensor -> cci dev->i2c framework.

Regards,
Nishanth Menon

Ref:
[1] MIPI CSI2 spec rev 1.0.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/5] OV3640: Add driver
  2009-03-09 21:29     ` Menon, Nishanth
@ 2009-03-10  7:29       ` Tuukka.O Toivonen
  2009-03-10  8:08         ` Menon, Nishanth
  0 siblings, 1 reply; 8+ messages in thread
From: Tuukka.O Toivonen @ 2009-03-10  7:29 UTC (permalink / raw)
  To: ext Menon, Nishanth
  Cc: Aguirre Rodriguez, Sergio Alberto, Alexey Klimov, linux-media,
	linux-omap, Sakari Ailus, Doyu Hiroshi (Nokia-D/Helsinki),
	DongSoo(Nathaniel) Kim, MiaoStanley, Nagalla, Hari, Hiremath,
	Vaibhav, Lakhani, Amish

On Monday 09 March 2009 23:29:27 ext Menon, Nishanth wrote:
> Further, we have multiple sensors following CCI[1] - why not have a driver
> for the same, it will simplify the entire process - ov3640, mt9p012 both
> follow the spec at least.. dependency would be sensor -> cci dev->i2c
> framework.   

Sakari has written smiaregs.c pretty much exactly for this
purpose. You should check it out.

- Tuukka

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH 3/5] OV3640: Add driver
  2009-03-10  7:29       ` Tuukka.O Toivonen
@ 2009-03-10  8:08         ` Menon, Nishanth
  0 siblings, 0 replies; 8+ messages in thread
From: Menon, Nishanth @ 2009-03-10  8:08 UTC (permalink / raw)
  To: Tuukka.O Toivonen
  Cc: Aguirre Rodriguez, Sergio Alberto, Alexey Klimov, linux-media,
	linux-omap, Sakari Ailus, Doyu Hiroshi (Nokia-D/Helsinki),
	DongSoo(Nathaniel) Kim, MiaoStanley, Nagalla, Hari, Hiremath,
	Vaibhav, Lakhani, Amish

> -----Original Message-----
> From: Tuukka.O Toivonen [mailto:tuukka.o.toivonen@nokia.com]
> Sent: Tuesday, March 10, 2009 9:30 AM
> To: Menon, Nishanth
> Cc: Aguirre Rodriguez, Sergio Alberto; Alexey Klimov; linux-
> media@vger.kernel.org; linux-omap@vger.kernel.org; Sakari Ailus; Doyu
> Hiroshi (Nokia-D/Helsinki); DongSoo(Nathaniel) Kim; MiaoStanley; Nagalla,
> Hari; Hiremath, Vaibhav; Lakhani, Amish
> Subject: Re: [PATCH 3/5] OV3640: Add driver
> 
> On Monday 09 March 2009 23:29:27 ext Menon, Nishanth wrote:
> > Further, we have multiple sensors following CCI[1] - why not have a
> driver
> > for the same, it will simplify the entire process - ov3640, mt9p012 both
> > follow the spec at least.. dependency would be sensor -> cci dev->i2c
> > framework.
> 
> Sakari has written smiaregs.c pretty much exactly for this
> purpose. You should check it out.
Yes, smiaregs probably has a few more functionality than pure reg access APIs. Comparing CCI as defined in CCP2 spec and CSI2 spec, CCP2 spec says - register addressing could be 8 or 16, but the data size is 8 bit. In the case of CSI2, the data size could be 8, 16, 32 or 64 bytes.. we could say that CSI2's CCI is kind of a superset of CCI as defined by CCP2 spec.
Might be a good idea to split the cci access out of smia_regs.c and make it a little more generic so that devices not caring for smia register set organization but using MIPI type access could also use it.

Regards,
Nishanth Menon
Ref:
[1] MIPI CSI2 revision 1.0
[2] SMIA CCP2 spec rev 1.0

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2009-03-10  8:08 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-03-03 20:44 [PATCH 3/5] OV3640: Add driver Aguirre Rodriguez, Sergio Alberto
2009-03-05  0:23 ` Alexey Klimov
2009-03-09 20:58   ` Aguirre Rodriguez, Sergio Alberto
2009-03-09 21:29     ` Menon, Nishanth
2009-03-10  7:29       ` Tuukka.O Toivonen
2009-03-10  8:08         ` Menon, Nishanth
2009-03-05  1:42 ` Trent Piepho
2009-03-09 21:00   ` Aguirre Rodriguez, Sergio Alberto

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.