From eefcf5de4689fbd00119d7a7df75244ca6ca1187 Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Sun, 1 May 2011 16:40:54 +0200
Subject: [PATCH 1/2] mt9p031: import driver from https://github.com/Aptina/BeagleBoard-xM/tree/master/Angstrom/MT9P031

Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
 drivers/media/video/Kconfig     |    6 +
 drivers/media/video/Makefile    |    1 +
 drivers/media/video/mt9p031.c   | 1445 +++++++++++++++++++++++++++++++++++++++
 include/media/mt9p031.h         |   30 +
 include/media/v4l2-chip-ident.h |    1 +
 5 files changed, 1483 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/mt9p031.c
 create mode 100644 include/media/mt9p031.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4c1fb0f..59f1133 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -832,6 +832,12 @@ config SOC_CAMERA_MT9M111
 	help
 	  This driver supports MT9M111 and MT9M112 cameras from Micron
 
+config SOC_CAMERA_MT9P031
+	tristate "mt9p031 support"
+	depends on SOC_CAMERA && I2C
+	help
+	  This driver supports MT9P031 cameras from Micron.
+
 config SOC_CAMERA_MT9T031
 	tristate "mt9t031 support"
 	depends on SOC_CAMERA && I2C
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index fb7e46c..f3110e7 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_VIDEO_MT9V113) += mt9v113.o
 
 obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
+obj-$(CONFIG_SOC_CAMERA_MT9P031)	+= mt9p031.o
 obj-$(CONFIG_SOC_CAMERA_MT9T031)	+= mt9t031.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
 obj-$(CONFIG_SOC_CAMERA_OV772X)		+= ov772x.o
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
new file mode 100644
index 0000000..3047e43
--- /dev/null
+++ b/drivers/media/video/mt9p031.c
@@ -0,0 +1,1445 @@
+/*
+ * drivers/media/video/mt9p031.c
+ *
+ * Aptina mt9p031 sensor driver
+ *
+ *
+ * Copyright (C) 2010 Aptina Imaging
+ * 
+ * 
+ * Leverage mt9p012.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <linux/sysfs.h>
+
+#include <media/mt9p031.h>
+#include <media/v4l2-int-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#define MT9P031_DEBUG
+
+#ifdef MT9P031_DEBUG
+#define DPRINTK_DRIVER(format, ...)				\
+	printk(KERN_INFO "_MT9P031_DRIVER: " format, ## __VA_ARGS__)
+#else
+#define DPRINTK_DRIVER(format, ...)
+#endif
+/************************************************************************
+			macro
+************************************************************************/
+// Macro to configure I2c level shifter. Use only for MT9P031 Headboards from Aptina; not required for Leopard Imaging or elsewise. 
+#define MT9P031_HEADBOARD
+
+#define MT9P031_CHIP_ID			0x1801
+#define MT9P031_MAX_HEIGHT		1944
+#define MT9P031_MAX_WIDTH		2592
+#define MT9P031_MIN_HEIGHT		2
+#define MT9P031_MIN_WIDTH		2
+
+#define VGA_HEIGHT		480
+#define VGA_WIDTH		640
+
+#define MT9P031_NORMAL_OPERATION_MODE		(0x1F82) //write
+#define MT9P031_OUTPUT_CTRL_CHIP_UNSELECT	(0x1F80)
+#define MT9P031_OUTPUT_CTRL_HALT		(0x1F83)
+
+/* FPS Capabilities */
+#define MT9P031_MIN_FPS		10
+#define MT9P031_DEF_FPS		30
+#define MT9P031_MAX_FPS		50
+
+#define MT9P031_XCLK_NOM_1 12000000
+#define MT9P031_XCLK_NOM_2 24000000
+
+/* Analog gain values */
+#define MT9P031_EV_MIN_GAIN		0
+#define MT9P031_EV_MAX_GAIN		47
+#define MT9P031_EV_DEF_GAIN		24
+#define MT9P031_EV_GAIN_STEP		1
+
+/* Exposure time values */
+#define MT9P031_MIN_EXPOSURE		15000
+#define MT9P031_MAX_EXPOSURE		128000
+#define MT9P031_DEF_EXPOSURE		33000
+#define MT9P031_EXPOSURE_STEP		100
+#define Q12		4096
+/************************************************************************
+			Register Address
+************************************************************************/
+
+#define REG_MT9P031_CHIP_VERSION		0x00
+#define REG_MT9P031_ROWSTART			0x01
+#define REG_MT9P031_COLSTART			0x02
+#define REG_MT9P031_HEIGHT			0x03
+#define REG_MT9P031_WIDTH			0x04
+#define REG_MT9P031_HBLANK			0x05
+#define REG_MT9P031_VBLANK			0x06
+#define REG_MT9P031_OUT_CTRL			0x07
+#define REG_MT9P031_SHUTTER_WIDTH_U		0x08
+#define REG_MT9P031_SHUTTER_WIDTH_L		0x09
+#define REG_MT9P031_PCLK_CTRL			0x0a
+#define REG_MT9P031_RESTART			0x0b
+#define REG_MT9P031_SHUTTER_DELAY		0x0c
+#define REG_MT9P031_RESET			0x0d
+
+#define REG_MT9P031_PLL_CTRL			0x10
+#define REG_MT9P031_PLL_CONF1			0x11
+#define REG_MT9P031_PLL_CONF2			0x12
+
+#define REG_MT9P031_READ_MODE1			0x1e
+#define REG_MT9P031_READ_MODE2			0x20
+#define REG_MT9P031_ROW_ADDR_MODE		0x22
+#define REG_MT9P031_COL_ADDR_MODE		0x23
+#define REG_MT9P031_GREEN_1_GAIN		0x2b
+#define REG_MT9P031_BLUE_GAIN			0x2c
+#define REG_MT9P031_RED_GAIN			0x2d
+#define REG_MT9P031_GREEN_2_GAIN		0x2e
+#define REG_MT9P031_GLOBAL_GAIN			0x35
+#define REG_MT9P031_CHIP_VERSION_ALT	        0x0FF
+
+/************************************************************************
+			struct
+************************************************************************/
+struct mt9p031_frame_size {
+	u16 width;
+	u16 height;
+};
+
+struct mt9p031_priv {
+	struct mt9p031_platform_data  *pdata;
+	struct v4l2_int_device  *v4l2_int_device;
+	struct i2c_client  *client;
+	struct v4l2_pix_format  pix;
+	struct v4l2_fract timeperframe;
+	unsigned long xclk_current;
+	int fps;
+	int scaler;
+	int ver;
+	int  model;
+	u32  flags;
+/* for flags */
+#define INIT_DONE  (1<<0)
+};
+
+struct mt9p031_priv sysPriv;
+
+static const struct v4l2_fmtdesc mt9p031_formats[] = {
+	{
+		.description = "Bayer (sRGB) 10 bit",
+		.pixelformat = V4L2_PIX_FMT_SRGGB10,
+	},
+};
+
+static const unsigned int mt9p031_num_formats = ARRAY_SIZE(mt9p031_formats);
+
+/***********************Minimum Horizontal blanking*********************/
+int hb_min[4][4] = { 
+	{ 450, 430, 0, 420 },
+	{ 796, 776, 0, 766 },
+	{ 0, 0, 0, 0 },
+	{ 1488, 1468, 0, 1458 }, 
+};
+
+/**************************supported sizes******************************/
+const static struct mt9p031_frame_size mt9p031_sizes[] = {
+	{  640, 480 },
+	{ 1280, 720 },
+	{ 1920, 1080 },
+	{ 2048, 1536 },	//3MP
+	{ 2592, 1944 },	//5MP
+};
+
+
+struct mt9p031_format_params {
+	int width;
+	int height;
+	int row_start;
+	int col_start;
+	int row_size;
+	int col_size;
+	int hblank;
+	int vblank;
+	int integ_time;
+	int row_addr_mode;
+	int col_addr_mode;
+	int read_mode_2_config;
+	int shutter_width_hi;
+	int shutter_delay;
+	int row_bin;
+	int col_bin;		
+};
+
+enum mt9p031_image_size {
+	VGA_BIN_30FPS,
+	HDV_720P_30FPS,
+	//HDV_720P_60FPS,
+	//HDV_720P_60FPS_LVB,
+	HDV_1080P_30FPS,
+	MT9P031_THREE_MP,
+	MT9P031_FIVE_MP,
+};
+
+enum mt9p031_image_size mt9p031_current_format;
+
+const struct mt9p031_format_params mt9p031_supported_formats[] = {
+	{ 640, 480, 64, 24, 1919, 2559, 0, 0, 0x0296,  0x0033, 0x0033, 0x0060, 0, 0, 3, 3 },  // VGA_BIN_30FPS
+	{ 1280, 720, 64, 24, 1439, 2559, 0, 0, 0x0296, 0x0011, 0x0011, 0x0060, 0, 0, 1, 1 },  // 720P_HD_30FPS
+	//{ 1280, 720, 0x0040, 0x0018, 0x059F, 0x09FF, 0, 0, 0x0296, 0x0011, 0x0011, 0x0060, 0, 0, 1, 1 },  // 720P_HD_60FPS
+	//{ 1280, 720, 0x0040, 0x0018, 0x059F, 0x09FF, 0, 0x02D0, 0x0296, 0x0011, 0x0011, 0x0060, 0, 0, 1, 1 },  // 720P_HD_60FPS_LVB
+	{ 1920, 1080, 431, 335, 1079, 1919, 0, 0x0037, 0x01AC, 0, 0, 0x0040, 0, 0, 0, 0 },	// 1080P_30FPS
+	{ 2048, 1536, 431, 335, 1535, 2047, 0, 0x0037, 0x01AC, 0, 0, 0x0040, 0, 0, 0, 0 },	// 3MP CAPTURE		
+	{ 2592, 1944, 431, 335, 1943, 2591, 0, 0x0037, 0x01AC, 0, 0, 0x0040, 0, 0, 0, 0 },	// 5MP CAPTURE	
+};
+
+
+const struct v4l2_fract mt9p031_frameintervals[] = {
+	{ .numerator = 1, .denominator = 10 },
+	{ .numerator = 1, .denominator = 20 },
+	{ .numerator = 1, .denominator = 30 },	
+	{ .numerator = 1, .denominator = 40 },	
+	{ .numerator = 1, .denominator = 50 },		
+};
+
+
+const u16 MT9P031_EV_GAIN_TBL[48] = {
+	/* Gain x1 */
+	8, 9, 10, 11, 12, 13, 14, 15, 
+	/* Gain x2 */
+	16, 17, 18, 19, 20, 21, 22, 23,
+	/* Gain x3 */
+	24, 25, 26, 27, 28, 29, 30, 31, 
+	/* Gain x4 */
+	32, 33, 34, 35,
+	/* Gain x5 */
+	81, 82, 83,
+	/* Gain x6 */
+	84, 85, 86, 87, 88, 89, 90, 91,
+	/* Gain x7 */
+	92, 93, 94, 95, 96, 97, 98, 99,
+	/* Gain x8 */
+	100,
+};
+
+#ifdef MT9P031_HEADBOARD
+/**
+ * mt9p031_config_PCA9543A - configure on-board I2c level-shifter PCA9543A of MT9P031 Headboards from Aptina
+ * @client: pointer to i2c client
+ * Configures the level shifter to enable channel 0 
+ */
+static int mt9p031_config_PCA9543A(const struct i2c_client *client)
+{
+	struct i2c_msg msg;
+	int ret;
+	u8 buf;
+	buf = 0x21;
+	
+	msg.addr  = (0xE6 >> 1);	//slave address of PCA9543A
+	msg.flags = 0;
+	msg.len   = 1;
+	msg.buf   = &buf;
+	
+	ret = i2c_transfer(client->adapter, &msg, 1);
+
+	return 0;
+		
+}
+#endif		//MT9P031_HEADBOARD
+
+/**
+ * mt9p031_reg_read - read resgiter value
+ * @client: pointer to i2c client
+ * @command: register address
+ */
+static int mt9p031_reg_read(const struct i2c_client *client, u16 command, u16 *val)
+{
+	struct i2c_msg msg[2];
+	u8 buf[2];
+	int ret;
+
+	// 8-bit/ byte addressable register
+	buf[0] = command & 0xff;
+
+	msg[0].addr  = client->addr;
+	msg[0].flags = 0;
+	msg[0].len   = 1;
+	msg[0].buf   = buf ;
+	ret = i2c_transfer(client->adapter, &msg[0], 1);
+	
+	if(ret >= 0) {
+		msg[1].addr  = client->addr;
+		msg[1].flags = I2C_M_RD; //1
+		msg[1].len   = 2;
+		msg[1].buf   = buf;
+		ret = i2c_transfer(client->adapter, &msg[1], 1);
+	}
+	/*
+	 * if return value of this function is < 0,
+	 * it mean error.
+	 * else, under 16bit is valid data.
+	 */
+	if(ret >= 0) {
+		*val = 0;
+		*val = buf[1] + (buf[0] << 8);
+		return 0;
+	}
+	
+	v4l_err(client, "read from offset 0x%x error %d", command, ret);
+	return ret;
+}
+
+/**
+ * mt9p031_reg_write - read resgiter value
+ * @client: pointer to i2c client
+ * @command: register address
+ * @data: value to be written 
+ */ 
+static int mt9p031_reg_write(const struct i2c_client *client,
+			       u16 command, u16 data)
+{
+	struct i2c_msg msg;
+	u8 buf[3];
+	int ret;
+
+	// 8-bit/ byte addressable register
+		
+	buf[0] = command & 0xff;
+	data = swab16(data);
+	memcpy(buf + 1, &data,    2);
+
+	msg.addr  = client->addr;
+	msg.flags = 0;
+	msg.len   = 3;
+	msg.buf   = buf;
+		
+	/*
+	 * i2c_transfer return message length,
+	 * but this function should return 0 if correct case
+	 */
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret >= 0)
+		ret = 0;
+
+	return ret;
+}
+
+/**
+ * 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;
+} mt9p031_video_control[] = {
+	{
+		{
+			.id = V4L2_CID_EXPOSURE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Exposure",
+			.minimum = MT9P031_MIN_EXPOSURE,
+			.maximum = MT9P031_MAX_EXPOSURE,
+			.step = MT9P031_EXPOSURE_STEP,
+			.default_value = MT9P031_DEF_EXPOSURE,
+		},
+		.current_value = MT9P031_DEF_EXPOSURE,
+	},
+	{
+		{
+			.id = V4L2_CID_GAIN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Analog Gain",
+			.minimum = MT9P031_EV_MIN_GAIN,
+			.maximum = MT9P031_EV_MAX_GAIN,
+			.step = MT9P031_EV_GAIN_STEP,
+			.default_value = MT9P031_EV_DEF_GAIN,
+		},
+		.current_value = MT9P031_EV_DEF_GAIN,
+	},
+};
+
+/**
+ * find_vctrl - Finds the requested ID in the video control structure array
+ * @id: ID of control to search the video control array for
+ *
+ * Returns the index of the requested ID from the control structure array
+ */
+static int
+find_vctrl(int id)
+{
+	int i;
+
+	if (id < V4L2_CID_BASE)
+		return -EDOM;
+
+	for (i = (ARRAY_SIZE(mt9p031_video_control) - 1); i >= 0; i--)
+		if (mt9p031_video_control[i].qc.id == id)
+			break;
+	if (i < 0)
+		i = -EINVAL;
+	return i;
+}
+
+/**
+ * mt9p031_calc_size - Find the best match for a requested image capture size
+ * @width: requested image width in pixels
+ * @height: requested image height in pixels
+ *
+ * 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 mt9p031_image_size mt9p031_calc_size(unsigned int width,
+						 unsigned int height)
+{
+	enum mt9p031_image_size isize;
+	unsigned long pixels = width * height;
+
+	for (isize = VGA_BIN_30FPS; isize <= MT9P031_FIVE_MP; isize++) {
+		if (mt9p031_sizes[isize].height *
+					mt9p031_sizes[isize].width >= pixels) {
+			
+			return isize;
+		}
+	}
+
+	return MT9P031_FIVE_MP;
+}
+
+/**
+ * mt9p031_find_isize - Find the best match for a requested image capture size
+ * @width: requested image width in pixels
+ * @height: requested image height in pixels
+ *
+ * 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 mt9p031_image_size mt9p031_find_isize(unsigned int width)
+{
+	enum mt9p031_image_size isize;
+
+	for (isize = VGA_BIN_30FPS; isize <= MT9P031_FIVE_MP; isize++) {
+		if (mt9p031_sizes[isize].width >= width)
+			break;
+	}
+
+	return isize;
+}
+
+/**
+ * mt9p031_calc_xclk - Calculate the required xclk frequency
+ * @c: i2c client driver structure
+ *
+ * Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate and return the required xclk frequency
+ */
+static unsigned long mt9p031_calc_xclk(struct i2c_client *c)
+{
+	struct mt9p031_priv *priv = i2c_get_clientdata(c);
+	struct v4l2_fract *timeperframe = &priv->timeperframe;
+
+	if (timeperframe->numerator == 0 ||
+	    timeperframe->denominator == 0) {
+		/* supply a default nominal_timeperframe */
+		timeperframe->numerator = 1;
+		timeperframe->denominator = MT9P031_DEF_FPS;
+	}
+
+	priv->fps = timeperframe->denominator / timeperframe->numerator;
+	if (priv->fps < MT9P031_MIN_FPS)
+		priv->fps = MT9P031_MIN_FPS;
+	else if (priv->fps > MT9P031_MAX_FPS)
+		priv->fps = MT9P031_MAX_FPS;
+
+	timeperframe->numerator = 1;
+	timeperframe->denominator = priv->fps;
+
+	return MT9P031_XCLK_NOM_1;
+}
+
+/**
+ * mt9p031_set_params - sets register settings according to resolution
+ * @client: pointer to standard i2c client
+ * @width: width as queried by ioctl
+ * @height: height as queried by ioctl
+ */
+static int mt9p031_set_params(struct i2c_client *client, u32 width, u32 height)
+{
+	struct mt9p031_priv *priv = i2c_get_clientdata(client);
+	struct v4l2_pix_format *pix = &priv->pix;
+	int ret;
+	enum mt9p031_image_size i;
+
+	i = mt9p031_find_isize(pix->width);
+	priv->pix.width = mt9p031_supported_formats[i].width;
+	priv->pix.height = mt9p031_supported_formats[i].height;
+	
+	ret = mt9p031_reg_write(client, REG_MT9P031_ROWSTART, mt9p031_supported_formats[i].row_start);		//ROW_WINDOW_START_REG
+	ret |= mt9p031_reg_write(client, REG_MT9P031_COLSTART, mt9p031_supported_formats[i].col_start);		//COL_WINDOW_START_REG
+	ret |= mt9p031_reg_write(client, REG_MT9P031_HEIGHT, mt9p031_supported_formats[i].row_size);		//ROW_WINDOW_SIZE_REG=1439
+	ret |= mt9p031_reg_write(client, REG_MT9P031_WIDTH, mt9p031_supported_formats[i].col_size);		//COL_WINDOW_SIZE_REG=2559
+	ret |= mt9p031_reg_write(client, REG_MT9P031_HBLANK, mt9p031_supported_formats[i].hblank);		//HORZ_BLANK=0
+	ret |= mt9p031_reg_write(client, REG_MT9P031_VBLANK, mt9p031_supported_formats[i].vblank);		//VERT_BLANK_REG=720
+	ret |= mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_L, 0x0400);		//SHUTTER_WIDTH_LOW (INTEG_TIME_REG = 1024)
+	ret |= mt9p031_reg_write(client, REG_MT9P031_ROW_ADDR_MODE, mt9p031_supported_formats[i].row_addr_mode);		//ROW_MODE, ROW_SKIP=1, ROW_BIN=1	
+	ret |= mt9p031_reg_write(client, REG_MT9P031_COL_ADDR_MODE, mt9p031_supported_formats[i].col_addr_mode);		//COL_MODE, COL_SKIP=1, COL_BIN=1
+	ret |= mt9p031_reg_write(client, REG_MT9P031_READ_MODE2, mt9p031_supported_formats[i].read_mode_2_config);		//READ_MODE_2, COL_SUM
+	ret |= mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_U, mt9p031_supported_formats[i].shutter_width_hi);		//SHUTTER_WIDTH_HI
+	ret |= mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_L, mt9p031_supported_formats[i].integ_time);		//SHUTTER_WIDTH_LOW (INTEG_TIME_REG)
+	ret |= mt9p031_reg_write(client, REG_MT9P031_SHUTTER_DELAY, mt9p031_supported_formats[i].shutter_delay);		//SHUTTER_DELAY_REG
+		
+	return ret;
+}
+
+/**
+ * mt9p031_init_camera - initialize camera settings
+ * @client: pointer to i2c client
+ * Initialize camera settings 
+ */ 
+static int mt9p031_init_camera(const struct i2c_client *client)
+{
+	int ret;
+	struct mt9p031_priv *priv = i2c_get_clientdata(client);
+	struct v4l2_pix_format *pix = &priv->pix;
+
+	ret = mt9p031_reg_write(client, REG_MT9P031_PLL_CTRL, 0x0051);  	//PLL_CTRL; power up pll
+	ret |= mt9p031_reg_write(client, REG_MT9P031_PLL_CONF1, 0x1801);		//PLL_CONFIG_1: m=24, n=1
+	ret |= mt9p031_reg_write(client, REG_MT9P031_PLL_CONF2, 0x0002);		//PLL_CONFIG_2: p1=2, p2=0
+	mdelay(10);  										//wait 10 ms for VCO to lock
+	ret |= mt9p031_reg_write(client, REG_MT9P031_PLL_CTRL, 0x0053);		//PLL_CONTROL; use PLL
+	mdelay(200);
+
+	ret |= mt9p031_set_params(priv->client, pix->width, pix->height);
+	
+	ret |= mt9p031_reg_write(client, REG_MT9P031_RESET, 0x0001);	//High
+	ret |= mt9p031_reg_write(client, REG_MT9P031_RESET, 0x0000);	//Low
+	mdelay(100);
+	
+	ret |= mt9p031_reg_write(client, REG_MT9P031_GREEN_1_GAIN, 0x0051);  	//Green1_gain_reg
+	ret |= mt9p031_reg_write(client, REG_MT9P031_BLUE_GAIN, 0x0051);  	//Blue_gain_reg
+	ret |= mt9p031_reg_write(client, REG_MT9P031_RED_GAIN, 0x0051);  	//Red_gain_reg
+	ret |= mt9p031_reg_write(client, REG_MT9P031_GREEN_2_GAIN, 0x0051);  	//Green2_gain_reg
+	ret |= mt9p031_reg_write(client, REG_MT9P031_GLOBAL_GAIN, 0x0008);		//Analog Gain
+	ret |= mt9p031_reg_write(client, REG_MT9P031_READ_MODE1, 0x0006);  	//Read_mode_1 //disable AB
+	ret |= mt9p031_reg_write(client, REG_MT9P031_OUT_CTRL, 0x1F8E);		//Enable parll fifo data
+	
+	return ret>= 0 ? 0 : -EIO;
+}
+
+/************************************************************************
+			i2c driver
+************************************************************************/
+/**
+ * mt9p031_detect - Detect if an mt9p031 is present, and if so which revision
+ * @client: pointer to the i2c client driver structure
+ *
+ * Returns a negative error number if no device is detected
+ */
+static int mt9p031_detect(struct i2c_client *client)
+{
+	struct mt9p031_priv *priv = i2c_get_clientdata(client);
+	const char	*devname;
+	u16 chipid;
+	
+	if (!client)
+		return -ENODEV;
+	/*
+	 * Set Normal Mode
+	 */
+	if(mt9p031_reg_write(client, REG_MT9P031_OUT_CTRL, MT9P031_NORMAL_OPERATION_MODE))
+		return -ENODEV;
+	/*
+	 * check and show chip ID
+	 */
+	if(mt9p031_reg_read(client, REG_MT9P031_CHIP_VERSION, &chipid)) 
+		return -ENODEV;
+		
+	if(chipid == MT9P031_CHIP_ID) {
+		devname = "mt9p031";
+		priv->model = V4L2_IDENT_MT9P031;
+		dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid);
+		return 0;
+	}
+			
+	dev_err(&client->dev, "Product ID error %04x\n", chipid);
+		return -ENODEV;
+}
+
+/**
+ * mt9p031_set_exposure_time - sets exposure time per input value
+ * @exp_time: exposure time to be set on device
+ * @client: pointer to standard i2c client
+ * @lvc: pointer to V4L2 exposure entry in video_controls array
+ *
+ * If the requested exposure time is within the allowed limits, the HW
+ * is configured to use the new exposure time, and the video_controls
+ * array is updated with the new current value.
+ * The function returns 0 upon success.  Otherwise an error code is
+ * returned.
+ */
+static int mt9p031_set_exposure_time(u32 exp_time, struct i2c_client *client,
+								struct vcontrol *lvc)
+{
+	int ret = 0, i, shutter_width, so_p, t_pix_clk, sd_p, shutter_delay;
+	int sw_l ,sw_u ,W ,h_blanking, t_row;
+	
+	if(exp_time < MT9P031_MIN_EXPOSURE)
+			exp_time = MT9P031_MIN_EXPOSURE;
+	else if(exp_time > MT9P031_MAX_EXPOSURE)
+			exp_time = MT9P031_MAX_EXPOSURE;
+	
+	shutter_delay = mt9p031_supported_formats[mt9p031_current_format].shutter_delay;
+	sd_p = min(shutter_delay + 1, 1504);
+	so_p = 208 * (mt9p031_supported_formats[mt9p031_current_format].row_bin + 1) + 98 + sd_p - 94;
+	t_pix_clk = (Q12/96 );	
+	h_blanking = mt9p031_supported_formats[mt9p031_current_format].hblank + 1;
+	W = 2 * (int)((mt9p031_supported_formats[mt9p031_current_format].row_size + 1) / (2 * (mt9p031_supported_formats[mt9p031_current_format].row_bin + 1)) + 1);		
+	t_row = 2 * t_pix_clk * max(W/2 + max(h_blanking, hb_min[mt9p031_supported_formats[mt9p031_current_format].row_bin][mt9p031_supported_formats[mt9p031_current_format].col_bin]),
+							  (41 + 346 * (mt9p031_supported_formats[mt9p031_current_format].row_bin + 1) + 99))/Q12;
+							  
+	shutter_width = (exp_time + 2*so_p*t_pix_clk) / t_row;
+	
+	if (shutter_width<  3) {
+		sd_p = 1232 >  shutter_delay ? 1232 : shutter_delay;
+		so_p = 208 * (mt9p031_supported_formats[mt9p031_current_format].row_bin + 1) + 98 + sd_p - 94;
+		shutter_width = ((exp_time*Q12 + 2*so_p*t_pix_clk) / (t_row * Q12));	
+	}
+	
+	if (shutter_width <  1)
+		shutter_width = 1;
+	sw_l = shutter_width&  0xffff;
+	sw_u = (shutter_width)>>  16;
+	ret = mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_L,sw_l);
+	mdelay(1);
+	ret = mt9p031_reg_write(client, REG_MT9P031_SHUTTER_WIDTH_U,sw_u);
+	
+	if (ret)
+		dev_err(&client->dev, "Error setting exposure time %d\n",
+									ret);
+	else{										
+		i = find_vctrl(V4L2_CID_EXPOSURE);
+		if (i >= 0) {
+			lvc = &mt9p031_video_control[i];
+			lvc->current_value = exp_time;
+		}
+	}
+	
+	return ret;	
+}
+
+/**
+ * mt9p031_set_gain - sets sensor analog gain per input value
+ * @lineargain: analog gain value index to be set on device
+ * @client: pointer to standard i2c client
+ * @lvc: pointer to V4L2 analog gain entry in video_controls array
+ *
+ * If the requested analog gain is within the allowed limits, the HW
+ * is configured to use the new gain value, and the video_controls
+ * array is updated with the new current value.
+ * The function returns 0 upon success.  Otherwise an error code is
+ * returned.
+ */
+int mt9p031_set_gain(u16 lineargain, struct i2c_client *client,
+							struct vcontrol *lvc)
+{
+	int ret= 0, i;
+	u16 reg_gain = 0;
+		
+	if (lineargain < MT9P031_EV_MIN_GAIN) {
+		lineargain = MT9P031_EV_MIN_GAIN;
+		v4l_err(client, "Gain out of legal range.");
+	}
+	if (lineargain > MT9P031_EV_MAX_GAIN) {
+		lineargain = MT9P031_EV_MAX_GAIN;
+		v4l_err(client, "Gain out of legal range.");
+	}
+
+	reg_gain = MT9P031_EV_GAIN_TBL[lineargain];
+	ret = mt9p031_reg_write(client, REG_MT9P031_GLOBAL_GAIN,
+					reg_gain);
+	
+	if (ret) {
+		dev_err(&client->dev, "Error setting gain.%d", ret);
+		return ret;	
+	}
+	else {
+		i = find_vctrl(V4L2_CID_GAIN);
+		if (i >= 0) {
+			lvc = &mt9p031_video_control[i];
+			lvc->current_value = lineargain;
+		}
+	}
+
+	return ret;
+}
+
+/************************************************************************
+			v4l2_ioctls
+************************************************************************/
+
+/**
+ * mt9p031_v4l2_int_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 mt9p031_v4l2_int_s_power(struct v4l2_int_device *s,
+				    enum v4l2_power power)
+{
+	struct mt9p031_priv *priv = s->priv;
+	struct i2c_client *client = priv->client;
+	
+	int ret;
+
+	switch (power) {
+	case V4L2_POWER_STANDBY:
+		/* FALLTHROUGH */
+	case V4L2_POWER_OFF:
+		ret = priv->pdata->power_set(s, power);
+		if (ret < 0) {
+			dev_err(&client->dev, "Unable to set target board power "
+					 "state (OFF/STANDBY)\n");
+			return ret;
+		}
+		break;
+	case V4L2_POWER_ON:
+		ret = priv->pdata->power_set(s, power);
+
+		if (ret < 0) {
+			dev_err(&client->dev, "Unable to set target board power "
+					 "state (ON)\n");
+			return ret;
+		}
+		if (!(priv->flags & INIT_DONE)) {
+			ret = mt9p031_detect(client);
+			if (ret < 0) {
+				dev_err(&client->dev, "Unable to detect sensor\n");
+				return ret;
+			}
+			priv->flags |= INIT_DONE;
+		}
+
+		ret = mt9p031_init_camera(client);
+		if (ret < 0) {
+				dev_err(&client->dev, "Unable to initialize sensor\n");
+				return ret;
+		}
+	}
+	
+	return 0;
+}
+
+/**
+ * mt9p031_v4l2_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 mt9p031_v4l2_s_ctrl(struct v4l2_int_device *s,
+			     struct v4l2_control *vc)
+{
+	int retval = -EINVAL;
+	int i;
+	struct vcontrol *lvc;
+	struct mt9p031_priv *priv = s->priv;
+	struct i2c_client *client = priv->client;
+	
+	i = find_vctrl(vc->id);
+	if (i < 0)
+		return -EINVAL;
+	lvc = &mt9p031_video_control[i];
+
+	switch (vc->id) {
+	case V4L2_CID_EXPOSURE:
+		retval = mt9p031_set_exposure_time(vc->value, client, lvc);
+		break;
+	case V4L2_CID_GAIN:
+		retval = mt9p031_set_gain(vc->value, client, lvc);
+		break;
+	}
+
+	return retval;
+}
+
+/**
+ * mt9p031_v4l2_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 mt9p031_v4l2_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 = &mt9p031_video_control[i];
+
+	switch (vc->id) {
+	case  V4L2_CID_EXPOSURE:
+		vc->value = lvc->current_value;
+		break;
+	case V4L2_CID_GAIN:
+		vc->value = lvc->current_value;
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * mt9p031_v4l2_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 mt9p031_v4l2_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 = mt9p031_video_control[i].qc;
+	return 0;
+}
+
+
+/**
+ * mt9p031_v4l2_int_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 mt9p031_v4l2_int_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 >= ARRAY_SIZE(mt9p031_formats))
+			return -EINVAL;
+	        break;
+	default:
+		return -EINVAL;
+	}
+
+	strlcpy(fmt->description, mt9p031_formats[index].description,
+					sizeof(fmt->description));
+	fmt->pixelformat = mt9p031_formats[index].pixelformat;
+
+	return 0;
+}
+
+/**
+ * mt9p031_v4l2_int_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 mt9p031_v4l2_int_try_fmt_cap(struct v4l2_int_device *s,
+					struct v4l2_format *f)
+{
+	enum mt9p031_image_size isize;
+	int ifmt;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	struct mt9p031_priv *priv = s->priv;
+	struct v4l2_pix_format *pix2 = &priv->pix;
+
+	isize = mt9p031_calc_size(pix->width, pix->height);
+	mt9p031_current_format = isize;
+	
+	pix->width = mt9p031_sizes[isize].width;
+	pix->height = mt9p031_sizes[isize].height;
+	for (ifmt = 0; ifmt < mt9p031_num_formats; ifmt++) {
+		if (pix->pixelformat == mt9p031_formats[ifmt].pixelformat)
+			break;
+	}
+	if (ifmt == mt9p031_num_formats)
+		ifmt = 0;
+	pix->pixelformat = mt9p031_formats[ifmt].pixelformat;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = pix->width * 2;
+	pix->sizeimage = pix->bytesperline * pix->height;
+	pix->priv = 0;
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	
+	*pix2 = *pix;
+
+	return 0;
+}
+
+/**
+ * mt9p031_v4l2_int_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 mt9p031_v4l2_int_s_fmt_cap(struct v4l2_int_device *s,
+				      struct v4l2_format *f)
+{
+	struct mt9p031_priv *priv = s->priv;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	int rval;
+	
+	rval = mt9p031_v4l2_int_try_fmt_cap(s, f);
+	if (!rval)
+		priv->pix = *pix;
+		
+	return rval;
+}
+
+/**
+ * mt9p031_v4l2_int_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 mt9p031_v4l2_int_g_fmt_cap(struct v4l2_int_device *s,
+				      struct v4l2_format *f)
+{
+	struct mt9p031_priv *priv = s->priv;
+	
+	f->fmt.pix.width	= priv->pix.width;
+	f->fmt.pix.height	= priv->pix.height;
+	f->fmt.pix.pixelformat	= V4L2_COLORSPACE_SRGB;
+	f->fmt.pix.pixelformat	= priv->pix.pixelformat;
+	f->fmt.pix.field	= V4L2_FIELD_NONE;
+
+	return 0;
+}
+
+/**
+ * mt9p031_v4l2_int_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 mt9p031_v4l2_int_s_parm(struct v4l2_int_device *s,
+				   struct v4l2_streamparm *a)
+{
+	struct mt9p031_priv *priv = s->priv;
+	struct i2c_client *client = priv->client;
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+
+	priv->timeperframe = *timeperframe;
+	priv->xclk_current = mt9p031_calc_xclk(client);
+	*timeperframe = priv->timeperframe;
+
+	return 0;
+}
+
+/**
+ * mt9p031_v4l2_int_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 mt9p031_v4l2_int_g_parm(struct v4l2_int_device *s,
+				   struct v4l2_streamparm *a)
+{
+	struct mt9p031_priv *priv = 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.numerator = 1;
+	cparm->timeperframe = priv->timeperframe;
+
+	return 0;
+}
+
+/**
+ * mt9p031_v4l2_int_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 mt9p031_v4l2_int_g_priv(struct v4l2_int_device *s, void *p)
+{
+	struct mt9p031_priv *priv = s->priv;
+
+	return priv->pdata->priv_data_set(p);
+}
+
+/**
+ * mt9p031_v4l2_int_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_priv_num
+ * @s: pointer to standard V4L2 device structure
+ * @p: void pointer to hold sensor's ifparm
+ *
+ * Returns device's (sensor's) ifparm in p parameter
+ */
+static int mt9p031_v4l2_int_g_ifparm(struct v4l2_int_device *s,
+				     struct v4l2_ifparm *p)
+{
+	struct mt9p031_priv *priv = s->priv;
+	int rval;
+
+	if (p == NULL)
+		return -EINVAL;
+
+	if (!priv->pdata->ifparm)
+		return -EINVAL;
+
+	rval = priv->pdata->ifparm(p);
+	if (rval) {
+		v4l_err(priv->client, "g_ifparm.Err[%d]\n", rval);
+		return rval;
+	}
+
+	return 0;
+}
+
+/**
+ * mt9p031_v4l2_int_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 mt9p031_v4l2_int_enum_framesizes(struct v4l2_int_device *s,
+					    struct v4l2_frmsizeenum *frms)
+{
+	int ifmt;
+
+	for (ifmt = 0; ifmt < ARRAY_SIZE(mt9p031_formats); ifmt++)
+		if (mt9p031_formats[ifmt].pixelformat == frms->pixel_format)
+			break;
+
+	if (ifmt == ARRAY_SIZE(mt9p031_formats))
+		return -EINVAL;
+
+	/* Do we already reached all discrete framesizes? */
+	if (frms->index >= ARRAY_SIZE(mt9p031_sizes))
+		return -EINVAL;
+
+	frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	frms->discrete.width = mt9p031_sizes[frms->index].width;
+	frms->discrete.height = mt9p031_sizes[frms->index].height;
+
+	return 0;
+}
+
+static int mt9p031_v4l2_int_enum_frameintervals(struct v4l2_int_device *s,
+						struct v4l2_frmivalenum *frmi)
+{
+	int ifmt;
+	int max_size;
+
+	for (ifmt = 0; ifmt < ARRAY_SIZE(mt9p031_formats); ifmt++)
+		if (mt9p031_formats[ifmt].pixelformat == frmi->pixel_format)
+			break;
+
+	if (ifmt == ARRAY_SIZE(mt9p031_formats))
+		return -EINVAL;
+
+	max_size = ARRAY_SIZE(mt9p031_sizes);
+	
+	for(ifmt = 0; ifmt < max_size; ifmt++) {
+		if(frmi->width <= mt9p031_sizes[ifmt].width) {
+			frmi->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+			frmi->discrete.numerator =
+				mt9p031_frameintervals[frmi->index].numerator;
+			frmi->discrete.denominator =
+				mt9p031_frameintervals[frmi->index].denominator;
+
+			if(frmi->discrete.denominator <= mt9p031_frameintervals[max_size - ifmt - 1].denominator)
+				return 0;
+			else
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static struct v4l2_int_ioctl_desc mt9p031_ioctl_desc[] = {
+	{ .num = vidioc_int_enum_framesizes_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_enum_framesizes },
+	{ .num = vidioc_int_enum_frameintervals_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_enum_frameintervals },
+	{ .num = vidioc_int_s_power_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_s_power },
+	{ .num = vidioc_int_g_priv_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_g_priv },
+	{ .num = vidioc_int_g_ifparm_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_g_ifparm },
+	{ .num = vidioc_int_enum_fmt_cap_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_enum_fmt_cap },
+	{ .num = vidioc_int_try_fmt_cap_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_try_fmt_cap },
+	{ .num = vidioc_int_g_fmt_cap_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_g_fmt_cap }, 
+	{ .num = vidioc_int_s_fmt_cap_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_s_fmt_cap },
+	{ .num = vidioc_int_g_parm_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_g_parm },
+	{ .num = vidioc_int_s_parm_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_int_s_parm },
+	{ .num = vidioc_int_g_ctrl_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_g_ctrl },
+	{ .num = vidioc_int_s_ctrl_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_s_ctrl },
+	{ .num = vidioc_int_queryctrl_num,
+	  .func = (v4l2_int_ioctl_func *)mt9p031_v4l2_queryctrl },
+};
+
+#ifdef MT9P031_DEBUG
+/**
+ * ---------------------------------------------------------------------------------
+ * Sysfs
+ * ---------------------------------------------------------------------------------
+ */
+
+/* Basic register read write support */
+static u16 mt9p031_attr_basic_addr  = 0x0000;
+
+static ssize_t
+mt9p031_basic_reg_addr_show( struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0x%x\n", mt9p031_attr_basic_addr);
+}
+
+static ssize_t
+mt9p031_basic_reg_addr_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
+{
+	u16 val;
+	sscanf(buf, "%hx", &val);
+	mt9p031_attr_basic_addr = (u16) val;
+	return n;
+}
+
+static DEVICE_ATTR( basic_reg_addr, S_IRUGO|S_IWUSR, mt9p031_basic_reg_addr_show, mt9p031_basic_reg_addr_store);
+
+
+static ssize_t
+mt9p031_basic_reg_val_show( struct device *dev, struct device_attribute *attr, char *buf)
+{
+	u16 val;
+	int ret;
+	ret = mt9p031_reg_read(sysPriv.client, mt9p031_attr_basic_addr, &val);
+	if(ret < 0){        
+		printk(KERN_INFO "mt9p031: Basic register read failed");
+		return 1; // nothing processed
+	} else {
+		return sprintf(buf, "0x%x\n", val);
+	}
+}
+
+static ssize_t
+mt9p031_basic_reg_val_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
+{
+	u32 val;
+	sscanf(buf, "%x", &val);
+
+	if (mt9p031_reg_write(sysPriv.client, mt9p031_attr_basic_addr, (u16)val)) {
+		printk(KERN_INFO "mt9p031: Basic regiser write failed");
+		return n; // nothing processed
+	} else {
+		return n;
+	}
+}
+static DEVICE_ATTR( basic_reg_val, S_IRUGO|S_IWUSR, mt9p031_basic_reg_val_show, mt9p031_basic_reg_val_store);
+
+
+/* Exposure time access support */
+static ssize_t
+mt9p031_exposure_val_show( struct device *dev, struct device_attribute *attr, char *buf)
+{
+	u32 val;
+	struct vcontrol *lvc;
+	int i = find_vctrl(V4L2_CID_EXPOSURE);
+	if (i < 0)
+		return -EINVAL;
+	lvc = &mt9p031_video_control[i];
+	val = lvc->current_value;
+	
+	if(val < 0){        
+		printk(KERN_INFO "mt9p031: Exposure value read failed");
+		return 1; // nothing processed
+	} else {
+		return sprintf(buf, "%d\n", val);
+	}
+}
+
+
+static ssize_t
+mt9p031_exposure_val_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
+{
+	u32 val;
+	struct i2c_client *client;
+	struct vcontrol *lvc;
+	
+	sscanf(buf, "%d", &val);
+	client = sysPriv.client;
+		
+	lvc = &mt9p031_video_control[V4L2_CID_EXPOSURE];	
+
+	if (mt9p031_set_exposure_time((u32)val, client, lvc)) {
+		printk(KERN_INFO "mt9p031: Exposure write failed");
+		return n; // nothing processed
+	} else {
+		return n;
+    }
+}
+
+static DEVICE_ATTR( exposure_val, S_IRUGO|S_IWUSR, mt9p031_exposure_val_show, mt9p031_exposure_val_store);
+
+
+/* Global Gain access support */
+static ssize_t
+mt9p031_gain_val_show( struct device *dev, struct device_attribute *attr, char *buf)
+{
+	u16 val;
+	struct vcontrol *lvc;
+    
+	int i = find_vctrl(V4L2_CID_GAIN);
+	if (i < 0)
+		return -EINVAL;
+	lvc = &mt9p031_video_control[i];
+	val = lvc->current_value;
+      
+	if(val < 0){        
+		printk(KERN_INFO "mt9p031: Global Gain value read failed");
+		return 1; // nothing processed
+	} else {
+		return sprintf(buf, "%d\n", val);
+    }
+}
+
+static ssize_t
+mt9p031_gain_val_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
+{
+	u16 val;
+	struct i2c_client *client;
+	struct vcontrol *lvc;
+	
+	sscanf(buf, "%hd", &val);
+	client = sysPriv.client;
+		
+	lvc = &mt9p031_video_control[V4L2_CID_GAIN];	
+		
+	if (mt9p031_set_gain(val, client, lvc)) {
+		printk(KERN_INFO "mt9p031: Global gain write failed");
+		return n; // nothing processed
+	} else {
+		return n;
+	}
+}
+
+static DEVICE_ATTR( gain_val, S_IRUGO|S_IWUSR, mt9p031_gain_val_show, mt9p031_gain_val_store);
+
+
+static struct attribute *mt9p031_sysfs_attr[] = {
+	&dev_attr_basic_reg_addr.attr,
+	&dev_attr_basic_reg_val.attr,
+	&dev_attr_exposure_val.attr,
+	&dev_attr_gain_val.attr,
+};
+
+static int mt9p031_sysfs_add(struct kobject *kobj)
+{
+	int i = ARRAY_SIZE(mt9p031_sysfs_attr);
+	int rval = 0;
+	
+	do {
+		rval = sysfs_create_file(kobj, mt9p031_sysfs_attr[--i]);
+	} while((i > 0) && (rval == 0));
+	return rval;
+}
+
+static int mt9p031_sysfs_rm(struct kobject *kobj)
+{
+	int i = ARRAY_SIZE(mt9p031_sysfs_attr);
+	int rval = 0;
+
+	do {
+		sysfs_remove_file(kobj, mt9p031_sysfs_attr[--i]);
+	} while(i > 0);
+	return rval;
+}
+#endif	//MT9P031_DEBUG
+
+static struct v4l2_int_slave mt9p031_slave = {
+	.ioctls = mt9p031_ioctl_desc,
+	.num_ioctls = ARRAY_SIZE(mt9p031_ioctl_desc),
+};
+
+static int mt9p031_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
+{
+	struct mt9p031_priv *priv;
+	struct v4l2_int_device *v4l2_int_device;
+	int ret;
+	if (!client->dev.platform_data) {
+		dev_err(&client->dev, "no platform data?\n");
+		return -ENODEV;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	v4l2_int_device = kzalloc(sizeof(*v4l2_int_device), GFP_KERNEL);
+	if (!v4l2_int_device) {
+		kfree(priv);
+		return -ENOMEM;
+	}
+
+#ifdef MT9P031_HEADBOARD
+	mt9p031_config_PCA9543A(client);		//configure i2c level shifter on mt9p031 head-board, no need for Leopard module
+	mdelay(10);
+#endif	//MT9P031_HEADBOARD
+	
+	v4l2_int_device->module = THIS_MODULE;
+	strncpy(v4l2_int_device->name, "mt9p031", sizeof(v4l2_int_device->name));
+	
+	v4l2_int_device->type = v4l2_int_type_slave;
+	v4l2_int_device->u.slave = &mt9p031_slave;
+
+	v4l2_int_device->priv = priv;
+
+	priv->v4l2_int_device = v4l2_int_device;
+	priv->client = client;
+	priv->pdata = client->dev.platform_data;
+	
+	priv->pdata->flags = MT9P031_FLAG_PCLK_RISING_EDGE;
+	
+	/* Setting Pixel Values */
+	priv->pix.width       = mt9p031_sizes[0].width;
+	priv->pix.height      = mt9p031_sizes[0].height;
+	priv->pix.pixelformat = mt9p031_formats[0].pixelformat;
+	
+	i2c_set_clientdata(client, priv);
+	
+	sysPriv.client = priv->client;
+
+	ret = v4l2_int_device_register(priv->v4l2_int_device);
+	if (ret) {
+		i2c_set_clientdata(client, NULL);
+		kfree(v4l2_int_device);
+		kfree(priv);
+	}
+	
+#ifdef MT9P031_DEBUG
+	mt9p031_sysfs_add(&client->dev.kobj);
+#endif	//MT9P031_DEBUG	
+	return ret;
+}
+
+static int mt9p031_remove(struct i2c_client *client)
+{
+	struct mt9p031_priv *priv = i2c_get_clientdata(client);
+
+	v4l2_int_device_unregister(priv->v4l2_int_device);
+	i2c_set_clientdata(client, NULL);
+	mt9p031_sysfs_rm(&client->dev.kobj);
+	
+	kfree(priv->v4l2_int_device);
+	kfree(priv);
+	return 0;
+}
+
+static const struct i2c_device_id mt9p031_id[] = {
+	{ "mt9p031", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9p031_id);
+
+static struct i2c_driver mt9p031_i2c_driver = {
+	.driver = {
+		.name = "mt9p031",
+	},
+	.probe    = mt9p031_probe,
+	.remove   = mt9p031_remove,
+	.id_table = mt9p031_id,
+};
+
+/************************************************************************
+			module function
+************************************************************************/
+static int __init mt9p031_module_init(void)
+{
+	return i2c_add_driver(&mt9p031_i2c_driver);
+}
+
+static void __exit mt9p031_module_exit(void)
+{
+	i2c_del_driver(&mt9p031_i2c_driver);
+}
+
+module_init(mt9p031_module_init);
+module_exit(mt9p031_module_exit);
+
+MODULE_DESCRIPTION("mt9p031 sensor driver");
+MODULE_AUTHOR("Aptina");
+MODULE_LICENSE("GPL v2");
+
diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h
new file mode 100644
index 0000000..d119589
--- /dev/null
+++ b/include/media/mt9p031.h
@@ -0,0 +1,30 @@
+/* mt9p031 Camera
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MT9P031_H__
+#define __MT9P031_H__
+
+#include <media/v4l2-int-device.h>
+
+#define MT9P031_I2C_ADDR		0x48 //(0x90 >> 1)
+
+#define MT9P031_CLK_MAX			(27000000) /* 27MHz */
+#define MT9P031_CLK_MIN			(6000000)  /* 6Mhz */
+
+#define MT9P031_FLAG_PCLK_RISING_EDGE	(1 << 0)
+#define MT9P031_FLAG_DATAWIDTH_8	(1 << 1) /* default width is 10 */
+
+struct mt9p031_platform_data {
+	char *master;
+	int (*power_set) (struct v4l2_int_device *s, enum v4l2_power on);
+	int (*ifparm) (struct v4l2_ifparm *p);
+	int (*priv_data_set) (void *);
+	u32 (*set_xclk) (struct v4l2_int_device *s, u32 xclkfreq);
+	u32 flags;
+};
+
+#endif /* __MT9P031_H__ */
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 6cc107d..7599bf1 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -271,6 +271,7 @@ enum {
 	V4L2_IDENT_MT9T112		= 45022,
 	V4L2_IDENT_MT9V111		= 45031,
 	V4L2_IDENT_MT9V112		= 45032,
+	V4L2_IDENT_MT9P031		= 6145,
 
 	/* HV7131R CMOS sensor: just ident 46000 */
 	V4L2_IDENT_HV7131R		= 46000,
-- 
1.6.6.1

