Message ID | A24693684029E5489D1D202277BE89442E1D9222@dlee02.ent.ti.com (mailing list archive) |
---|---|
State | RFC |
Headers | show |
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
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. -- 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
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 -- 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
> -----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 -- 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
> -----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. -- 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
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 -- 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
> -----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 -- 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
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 */ + +
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 -- 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