From bd42ce1ffea1be835f54ac61bb7ea4e0cd99e7aa Mon Sep 17 00:00:00 2001
From: Sergio Aguirre <saaguirre@ti.com>
Date: Thu, 1 Jul 2010 07:26:38 -0500
Subject: [PATCH 51/75] mt9t112: Migrate from soc_camera to v4l2-int-device

This is to use the driver with the old OMAP3 Camera-ISP platform.

Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
---
 drivers/media/video/Kconfig   |   12 +-
 drivers/media/video/Makefile  |    2 +-
 drivers/media/video/mt9t112.c |  658 +++++++++++++++++++++++------------------
 include/media/mt9t112.h       |   13 +
 4 files changed, 391 insertions(+), 294 deletions(-)

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 7caade9..4c1fb0f 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -354,6 +354,12 @@ config VIDEO_MT9P012
 	  MT9P012 camera.  It is currently working with the TI OMAP3
 	  camera controller.
 
+config VIDEO_MT9T112
+	tristate "mt9t112 support"
+	depends on I2C && VIDEO_V4L2
+	help
+	  This driver supports MT9T112 cameras from Aptina.
+
 config VIDEO_DW9710
 	tristate "Lens driver for DW9710"
 	depends on I2C && VIDEO_V4L2
@@ -832,12 +838,6 @@ config SOC_CAMERA_MT9T031
 	help
 	  This driver supports MT9T031 cameras from Micron.
 
-config SOC_CAMERA_MT9T112
-	tristate "mt9t112 support"
-	depends on SOC_CAMERA && I2C
-	help
-	  This driver supports MT9T112 cameras from Aptina.
-
 config SOC_CAMERA_MT9V022
 	tristate "mt9v022 support"
 	depends on SOC_CAMERA && I2C
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 61ae13f..fb7e46c 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -80,7 +80,6 @@ obj-$(CONFIG_VIDEO_MT9V113) += mt9v113.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
 obj-$(CONFIG_SOC_CAMERA_MT9T031)	+= mt9t031.o
-obj-$(CONFIG_SOC_CAMERA_MT9T112)	+= mt9t112.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
 obj-$(CONFIG_SOC_CAMERA_OV772X)		+= ov772x.o
 obj-$(CONFIG_SOC_CAMERA_OV9640)		+= ov9640.o
@@ -129,6 +128,7 @@ obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 obj-y				+= isp/
 obj-$(CONFIG_VIDEO_OMAP3)	+= omap34xxcam.o
 obj-$(CONFIG_VIDEO_MT9P012)     += mt9p012.o
+obj-$(CONFIG_VIDEO_MT9T112)	+= mt9t112.o
 obj-$(CONFIG_VIDEO_DW9710)	+= dw9710.o
 obj-$(CONFIG_VIDEO_TPS61059)    += tps61059.o
 obj-$(CONFIG_VIDEO_OV3640)	+= ov3640.o
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index 7438f8d..6f54394 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -25,10 +25,8 @@
 #include <linux/videodev2.h>
 
 #include <media/mt9t112.h>
-#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/v4l2-int-device.h>
 #include <media/v4l2-chip-ident.h>
-#include <media/v4l2-common.h>
 
 /* you can check PLL/clock info */
 /* #define EXT_CLOCK 24000000 */
@@ -43,8 +41,8 @@
 /*
  * frame size
  */
-#define MAX_WIDTH   2048
-#define MAX_HEIGHT  1536
+#define MAX_WIDTH   640 /* 2048 */
+#define MAX_HEIGHT  480 /* 1536 */
 
 #define VGA_WIDTH   640
 #define VGA_HEIGHT  480
@@ -91,20 +89,12 @@ struct mt9t112_frame_size {
 	u16 height;
 };
 
-struct mt9t112_format {
-	enum v4l2_mbus_pixelcode code;
-	enum v4l2_colorspace colorspace;
-	u16 fmt;
-	u16 order;
-};
-
 struct mt9t112_priv {
-	struct v4l2_subdev		 subdev;
+	struct mt9t112_platform_data	*pdata;
+	struct v4l2_int_device		*v4l2_int_device;
 	struct mt9t112_camera_info	*info;
 	struct i2c_client		*client;
-	struct soc_camera_device	 icd;
-	struct mt9t112_frame_size	 frame;
-	const struct mt9t112_format	*format;
+	struct v4l2_pix_format		 pix;
 	int				 model;
 	u32				 flags;
 /* for flags */
@@ -119,38 +109,42 @@ struct mt9t112_priv {
 
 ************************************************************************/
 
-static const struct mt9t112_format mt9t112_cfmts[] = {
+const static struct v4l2_fmtdesc mt9t112_formats[] = {
+	{
+		.description	= "YUYV (YUV 4:2:2), packed",
+		.pixelformat	= V4L2_PIX_FMT_YUYV,
+	},
 	{
-		.code		= V4L2_MBUS_FMT_YUYV8_2X8_BE,
-		.colorspace	= V4L2_COLORSPACE_JPEG,
-		.fmt		= 1,
-		.order		= 0,
-	}, {
-		.code		= V4L2_MBUS_FMT_YVYU8_2X8_BE,
-		.colorspace	= V4L2_COLORSPACE_JPEG,
-		.fmt		= 1,
-		.order		= 1,
-	}, {
-		.code		= V4L2_MBUS_FMT_YUYV8_2X8_LE,
-		.colorspace	= V4L2_COLORSPACE_JPEG,
-		.fmt		= 1,
-		.order		= 2,
-	}, {
-		.code		= V4L2_MBUS_FMT_YVYU8_2X8_LE,
-		.colorspace	= V4L2_COLORSPACE_JPEG,
-		.fmt		= 1,
-		.order		= 3,
-	}, {
-		.code		= V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
-		.colorspace	= V4L2_COLORSPACE_SRGB,
-		.fmt		= 8,
-		.order		= 2,
-	}, {
-		.code		= V4L2_MBUS_FMT_RGB565_2X8_LE,
-		.colorspace	= V4L2_COLORSPACE_SRGB,
-		.fmt		= 4,
-		.order		= 2,
+		.description	= "RGB555, le",
+		.pixelformat	= V4L2_PIX_FMT_RGB555,
 	},
+	{
+		.description	= "RGB565, le",
+		.pixelformat	= V4L2_PIX_FMT_RGB565,
+	},
+};
+
+/************************************************************************
+
+
+			supported sizes
+
+
+************************************************************************/
+const static struct mt9t112_frame_size mt9t112_sizes[] = {
+	{  640, 480 },
+	/* { 2048, 1536} */
+};
+
+/************************************************************************
+
+
+			supported sizes
+
+
+************************************************************************/
+const struct v4l2_fract mt9t112_frameintervals[] = {
+	{  .numerator = 1, .denominator = 10 }
 };
 
 /************************************************************************
@@ -160,11 +154,32 @@ static const struct mt9t112_format mt9t112_cfmts[] = {
 
 
 ************************************************************************/
-static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client)
+static u16 mt9t112_pixfmt_to_fmt(u32 pixelformat)
 {
-	return container_of(i2c_get_clientdata(client),
-			    struct mt9t112_priv,
-			    subdev);
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_RGB555:
+		return 8;
+	case V4L2_PIX_FMT_RGB565:
+		return 4;
+	case V4L2_PIX_FMT_YUYV:
+		/* FALLTHROUGH */
+	default:
+		return 1;
+	}
+}
+
+static u16 mt9t112_pixfmt_to_order(u32 pixelformat)
+{
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_RGB555:
+		/* FALLTHROUGH */
+	case V4L2_PIX_FMT_RGB565:
+		return 2;
+	case V4L2_PIX_FMT_YUYV:
+		/* FALLTHROUGH */
+	default:
+		return 0;
+	}
 }
 
 static int __mt9t112_reg_read(const struct i2c_client *client, u16 command)
@@ -438,7 +453,7 @@ static int mt9t112_set_pll_dividers(const struct i2c_client *client,
 
 static int mt9t112_init_pll(const struct i2c_client *client)
 {
-	struct mt9t112_priv *priv = to_mt9t112(client);
+	struct mt9t112_priv *priv = i2c_get_clientdata(client);
 	int data, i, ret;
 
 	mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001);
@@ -757,167 +772,12 @@ static int mt9t112_init_camera(const struct i2c_client *client)
 	return ret;
 }
 
-/************************************************************************
-
-
-			soc_camera_ops
-
-
-************************************************************************/
-static int mt9t112_set_bus_param(struct soc_camera_device *icd,
-				 unsigned long	flags)
-{
-	return 0;
-}
-
-static unsigned long mt9t112_query_bus_param(struct soc_camera_device *icd)
-{
-	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-	struct mt9t112_priv *priv = to_mt9t112(client);
-	struct soc_camera_link *icl = to_soc_camera_link(icd);
-	unsigned long flags = SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH |
-		SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH;
-
-	flags |= (priv->info->flags & MT9T112_FLAG_PCLK_RISING_EDGE) ?
-		SOCAM_PCLK_SAMPLE_RISING : SOCAM_PCLK_SAMPLE_FALLING;
-
-	if (priv->info->flags & MT9T112_FLAG_DATAWIDTH_8)
-		flags |= SOCAM_DATAWIDTH_8;
-	else
-		flags |= SOCAM_DATAWIDTH_10;
-
-	return soc_camera_apply_sensor_flags(icl, flags);
-}
-
-static struct soc_camera_ops mt9t112_ops = {
-	.set_bus_param		= mt9t112_set_bus_param,
-	.query_bus_param	= mt9t112_query_bus_param,
-};
-
-/************************************************************************
-
-
-			v4l2_subdev_core_ops
-
-
-************************************************************************/
-static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
-				struct v4l2_dbg_chip_ident *id)
-{
-	struct i2c_client *client = sd->priv;
-	struct mt9t112_priv *priv = to_mt9t112(client);
-
-	id->ident    = priv->model;
-	id->revision = 0;
-
-	return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9t112_g_register(struct v4l2_subdev *sd,
-			      struct v4l2_dbg_register *reg)
-{
-	struct i2c_client *client = sd->priv;
-	int                ret;
-
-	reg->size = 2;
-	mt9t112_reg_read(ret, client, reg->reg);
-
-	reg->val = (__u64)ret;
-
-	return 0;
-}
-
-static int mt9t112_s_register(struct v4l2_subdev *sd,
-			      struct v4l2_dbg_register *reg)
-{
-	struct i2c_client *client = sd->priv;
-	int ret;
-
-	mt9t112_reg_write(ret, client, reg->reg, reg->val);
-
-	return ret;
-}
-#endif
-
-static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
-	.g_chip_ident	= mt9t112_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	.g_register	= mt9t112_g_register,
-	.s_register	= mt9t112_s_register,
-#endif
-};
-
-
-/************************************************************************
-
-
-			v4l2_subdev_video_ops
-
-
-************************************************************************/
-static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
-{
-	struct i2c_client *client = sd->priv;
-	struct mt9t112_priv *priv = to_mt9t112(client);
-	int ret = 0;
-
-	if (!enable) {
-		/* FIXME
-		 *
-		 * If user selected large output size,
-		 * and used it long time,
-		 * mt9t112 camera will be very warm.
-		 *
-		 * But current driver can not stop mt9t112 camera.
-		 * So, set small size here to solve this problem.
-		 */
-		mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT);
-		return ret;
-	}
-
-	if (!(priv->flags & INIT_DONE)) {
-		u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE &
-			     priv->info->flags) ? 0x0001 : 0x0000;
-
-		ECHECKER(ret, mt9t112_init_camera(client));
-
-		/* Invert PCLK (Data sampled on falling edge of pixclk) */
-		mt9t112_reg_write(ret, client, 0x3C20, param);
-
-		mdelay(5);
-
-		priv->flags |= INIT_DONE;
-	}
-
-	mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt);
-	mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order);
-	mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
-
-	mt9t112_set_a_frame_size(client,
-				 priv->frame.width,
-				 priv->frame.height);
-
-	ECHECKER(ret, mt9t112_auto_focus_trigger(client));
-
-	dev_dbg(&client->dev, "format : %d\n", priv->format->code);
-	dev_dbg(&client->dev, "size   : %d x %d\n",
-		priv->frame.width,
-		priv->frame.height);
-
-	CLOCK_INFO(client, EXT_CLOCK);
-
-	return ret;
-}
-
 static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height,
-			      enum v4l2_mbus_pixelcode code)
+			      u32 pixelformat)
 {
-	struct mt9t112_priv *priv = to_mt9t112(client);
+	struct mt9t112_priv *priv = i2c_get_clientdata(client);
 	int i;
 
-	priv->format = NULL;
-
 	/*
 	 * frame size check
 	 */
@@ -926,22 +786,23 @@ static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height,
 	/*
 	 * get color format
 	 */
-	for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++)
-		if (mt9t112_cfmts[i].code == code)
+	for (i = 0; i < ARRAY_SIZE(mt9t112_formats); i++)
+		if (mt9t112_formats[i].pixelformat == pixelformat)
 			break;
 
-	if (i == ARRAY_SIZE(mt9t112_cfmts))
+	if (i == ARRAY_SIZE(mt9t112_formats))
 		return -EINVAL;
 
-	priv->frame.width  = (u16)width;
-	priv->frame.height = (u16)height;
+	priv->pix.width  = (u16)width;
+	priv->pix.height = (u16)height;
 
-	priv->format = mt9t112_cfmts + i;
+	priv->pix.pixelformat = pixelformat;
 
 	return 0;
 }
 
-static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+static int mt9t112_v4l2_int_cropcap(struct v4l2_int_device *s,
+				    struct v4l2_cropcap *a)
 {
 	a->bounds.left			= 0;
 	a->bounds.top			= 0;
@@ -955,7 +816,8 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 	return 0;
 }
 
-static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+static int mt9t112_v4l2_int_g_crop(struct v4l2_int_device *s,
+				   struct v4l2_crop *a)
 {
 	a->c.left	= 0;
 	a->c.top	= 0;
@@ -966,77 +828,116 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 	return 0;
 }
 
-static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+static int mt9t112_v4l2_int_s_crop(struct v4l2_int_device *s,
+				   struct v4l2_crop *a)
 {
-	struct i2c_client *client = sd->priv;
-	struct v4l2_rect *rect = &a->c;
-
-	return mt9t112_set_params(client, rect->width, rect->height,
-				 V4L2_MBUS_FMT_YUYV8_2X8_BE);
+	if ((a->c.left != 0) ||
+	    (a->c.top != 0) ||
+	    (a->c.width != VGA_WIDTH) ||
+	    (a->c.height != VGA_HEIGHT)) {
+		return -EINVAL;
+	}
+	return 0;
 }
 
-static int mt9t112_g_fmt(struct v4l2_subdev *sd,
-			 struct v4l2_mbus_framefmt *mf)
+static int mt9t112_v4l2_int_g_fmt_cap(struct v4l2_int_device *s,
+				      struct v4l2_format *f)
 {
-	struct i2c_client *client = sd->priv;
-	struct mt9t112_priv *priv = to_mt9t112(client);
+	struct mt9t112_priv *priv = s->priv;
+	struct i2c_client *client = priv->client;
 
-	if (!priv->format) {
+	if ((priv->pix.pixelformat == 0) ||
+	    (priv->pix.width == 0) ||
+	    (priv->pix.height == 0)) {
 		int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT,
-					     V4L2_MBUS_FMT_YUYV8_2X8_BE);
+					     V4L2_PIX_FMT_YUYV);
 		if (ret < 0)
 			return ret;
 	}
 
-	mf->width	= priv->frame.width;
-	mf->height	= priv->frame.height;
+	f->fmt.pix.width	= priv->pix.width;
+	f->fmt.pix.height	= priv->pix.height;
 	/* TODO: set colorspace */
-	mf->code	= priv->format->code;
-	mf->field	= V4L2_FIELD_NONE;
+	f->fmt.pix.pixelformat	= priv->pix.pixelformat;
+	f->fmt.pix.field	= V4L2_FIELD_NONE;
 
 	return 0;
 }
 
-static int mt9t112_s_fmt(struct v4l2_subdev *sd,
-			 struct v4l2_mbus_framefmt *mf)
+
+static int mt9t112_v4l2_int_s_fmt_cap(struct v4l2_int_device *s,
+				      struct v4l2_format *f)
 {
-	struct i2c_client *client = sd->priv;
+	struct mt9t112_priv *priv = s->priv;
+	struct i2c_client *client = priv->client;
 
 	/* TODO: set colorspace */
-	return mt9t112_set_params(client, mf->width, mf->height, mf->code);
+	return mt9t112_set_params(client, f->fmt.pix.width, f->fmt.pix.height,
+				  f->fmt.pix.pixelformat);
 }
 
-static int mt9t112_try_fmt(struct v4l2_subdev *sd,
-			   struct v4l2_mbus_framefmt *mf)
+static int mt9t112_v4l2_int_try_fmt_cap(struct v4l2_int_device *s,
+					struct v4l2_format *f)
 {
-	mt9t112_frame_check(&mf->width, &mf->height);
+	mt9t112_frame_check(&f->fmt.pix.width, &f->fmt.pix.height);
 
 	/* TODO: set colorspace */
-	mf->field = V4L2_FIELD_NONE;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
 
 	return 0;
 }
 
-static int mt9t112_enum_fmt(struct v4l2_subdev *sd, int index,
-			   enum v4l2_mbus_pixelcode *code)
+static int mt9t112_v4l2_int_enum_fmt_cap(struct v4l2_int_device *s,
+					 struct v4l2_fmtdesc *fmt)
 {
-	if ((unsigned int)index >= ARRAY_SIZE(mt9t112_cfmts))
+	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(mt9t112_formats))
+			return -EINVAL;
+	break;
+	default:
 		return -EINVAL;
+	}
 
-	*code = mt9t112_cfmts[index].code;
+	fmt->flags = mt9t112_formats[index].flags;
+	strlcpy(fmt->description, mt9t112_formats[index].description,
+					sizeof(fmt->description));
+	fmt->pixelformat = mt9t112_formats[index].pixelformat;
 	return 0;
 }
 
-static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = {
-	.s_stream	= mt9t112_s_stream,
-	.g_mbus_fmt	= mt9t112_g_fmt,
-	.s_mbus_fmt	= mt9t112_s_fmt,
-	.try_mbus_fmt	= mt9t112_try_fmt,
-	.cropcap	= mt9t112_cropcap,
-	.g_crop		= mt9t112_g_crop,
-	.s_crop		= mt9t112_s_crop,
-	.enum_mbus_fmt	= mt9t112_enum_fmt,
-};
+static int mt9t112_v4l2_int_s_parm(struct v4l2_int_device *s,
+				   struct v4l2_streamparm *a)
+{
+	/* TODO: set paramters */
+	return 0;
+}
+
+static int mt9t112_v4l2_int_g_parm(struct v4l2_int_device *s,
+				   struct v4l2_streamparm *a)
+{
+	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;
+	/* FIXME: Is 10 fps really the only option? */
+	cparm->timeperframe.numerator = 1;
+	cparm->timeperframe.denominator = 10;
+
+	return 0;
+}
 
 /************************************************************************
 
@@ -1045,27 +946,14 @@ static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = {
 
 
 ************************************************************************/
-static struct v4l2_subdev_ops mt9t112_subdev_ops = {
-	.core	= &mt9t112_subdev_core_ops,
-	.video	= &mt9t112_subdev_video_ops,
-};
 
-static int mt9t112_camera_probe(struct soc_camera_device *icd,
-				struct i2c_client *client)
+static int mt9t112_detect(struct i2c_client *client)
 {
-	struct mt9t112_priv *priv = to_mt9t112(client);
+	struct mt9t112_priv *priv = i2c_get_clientdata(client);
 	const char          *devname;
 	int                  chipid;
 
 	/*
-	 * We must have a parent by now. And it cannot be a wrong one.
-	 * So this entire test is completely redundant.
-	 */
-	if (!icd->dev.parent ||
-	    to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-		return -ENODEV;
-
-	/*
 	 * check and show chip ID
 	 */
 	mt9t112_reg_read(chipid, client, 0x0000);
@@ -1089,37 +977,232 @@ static int mt9t112_camera_probe(struct soc_camera_device *icd,
 	return 0;
 }
 
+static int mt9t112_v4l2_int_s_power(struct v4l2_int_device *s,
+				    enum v4l2_power power)
+{
+	struct mt9t112_priv *priv = s->priv;
+	struct i2c_client *client = priv->client;
+	int ret;
+
+	switch (power) {
+	case V4L2_POWER_STANDBY:
+		/* FALLTHROUGH */
+	case V4L2_POWER_OFF:
+		/* FIXME
+		 *
+		 * If user selected large output size,
+		 * and used it long time,
+		 * mt9t112 camera will be very warm.
+		 *
+		 * But current driver can not stop mt9t112 camera.
+		 * So, set small size here to solve this problem.
+		 */
+		mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT);
+
+		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)) {
+			u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE &
+				     priv->info->flags) ? 0x0001 : 0x0000;
+
+			ECHECKER(ret, mt9t112_detect(client));
+			ECHECKER(ret, mt9t112_init_camera(client));
+
+			/* Invert PCLK (Data sampled on falling edge of pixclk) */
+			mt9t112_reg_write(ret, client, 0x3C20, param);
+
+			mdelay(5);
+
+			priv->flags |= INIT_DONE;
+		}
+
+		mt9t112_mcu_write(ret, client, VAR(26, 7),
+				  mt9t112_pixfmt_to_fmt(priv->pix.pixelformat));
+		mt9t112_mcu_write(ret, client, VAR(26, 9),
+				  mt9t112_pixfmt_to_order(priv->pix.pixelformat));
+		mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+		mt9t112_set_a_frame_size(client,
+					 priv->pix.width,
+					 priv->pix.height);
+
+		ECHECKER(ret, mt9t112_auto_focus_trigger(client));
+
+		dev_dbg(&client->dev, "format : %d\n", priv->pix.pixelformat);
+		dev_dbg(&client->dev, "size   : %d x %d\n",
+			priv->pix.width,
+			priv->pix.height);
+
+		CLOCK_INFO(client, EXT_CLOCK);
+	}
+	return 0;
+}
+
+static int mt9t112_v4l2_int_g_priv(struct v4l2_int_device *s, void *p)
+{
+	struct mt9t112_priv *priv = s->priv;
+
+	return priv->pdata->priv_data_set(p);
+}
+
+static int mt9t112_v4l2_int_g_ifparm(struct v4l2_int_device *s,
+				     struct v4l2_ifparm *p)
+{
+	struct mt9t112_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;
+	}
+
+	p->u.ycbcr.clock_curr = 40 * 1000000; /* temporal value */
+
+	return 0;
+}
+
+static int mt9t112_v4l2_int_enum_framesizes(struct v4l2_int_device *s,
+					    struct v4l2_frmsizeenum *frms)
+{
+	int ifmt;
+
+	for (ifmt = 0; ifmt < ARRAY_SIZE(mt9t112_formats); ifmt++)
+		if (mt9t112_formats[ifmt].pixelformat == frms->pixel_format)
+			break;
+
+	if (ifmt == ARRAY_SIZE(mt9t112_formats))
+		return -EINVAL;
+
+	/* Do we already reached all discrete framesizes? */
+	if (frms->index >= ARRAY_SIZE(mt9t112_sizes))
+		return -EINVAL;
+
+	frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	frms->discrete.width = mt9t112_sizes[frms->index].width;
+	frms->discrete.height = mt9t112_sizes[frms->index].height;
+
+	return 0;
+
+}
+
+static int mt9t112_v4l2_int_enum_frameintervals(struct v4l2_int_device *s,
+						struct v4l2_frmivalenum *frmi)
+{
+	int ifmt;
+
+	for (ifmt = 0; ifmt < ARRAY_SIZE(mt9t112_formats); ifmt++)
+		if (mt9t112_formats[ifmt].pixelformat == frmi->pixel_format)
+			break;
+
+	if (ifmt == ARRAY_SIZE(mt9t112_formats))
+		return -EINVAL;
+
+	if (frmi->index >= ARRAY_SIZE(mt9t112_frameintervals))
+		return -EINVAL;
+
+	frmi->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	frmi->discrete.numerator =
+				mt9t112_frameintervals[frmi->index].numerator;
+	frmi->discrete.denominator =
+				mt9t112_frameintervals[frmi->index].denominator;
+	return 0;
+}
+
+static struct v4l2_int_ioctl_desc mt9t112_ioctl_desc[] = {
+	{ .num = vidioc_int_enum_framesizes_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_enum_framesizes },
+	{ .num = vidioc_int_enum_frameintervals_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_enum_frameintervals },
+	{ .num = vidioc_int_s_power_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_s_power },
+	{ .num = vidioc_int_g_priv_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_g_priv },
+	{ .num = vidioc_int_g_ifparm_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_g_ifparm },
+	{ .num = vidioc_int_enum_fmt_cap_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_enum_fmt_cap },
+	{ .num = vidioc_int_try_fmt_cap_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_try_fmt_cap },
+	{ .num = vidioc_int_g_fmt_cap_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_g_fmt_cap },
+	{ .num = vidioc_int_s_fmt_cap_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_s_fmt_cap },
+	{ .num = vidioc_int_g_parm_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_g_parm },
+	{ .num = vidioc_int_s_parm_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_s_parm },
+	{ .num = vidioc_int_cropcap_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_cropcap },
+	{ .num = vidioc_int_g_crop_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_g_crop },
+	{ .num = vidioc_int_s_crop_num,
+	  .func = (v4l2_int_ioctl_func *)mt9t112_v4l2_int_s_crop },
+};
+
+static struct v4l2_int_slave mt9t112_slave = {
+	.ioctls = mt9t112_ioctl_desc,
+	.num_ioctls = ARRAY_SIZE(mt9t112_ioctl_desc),
+};
+
 static int mt9t112_probe(struct i2c_client *client,
 			 const struct i2c_device_id *did)
 {
 	struct mt9t112_priv        *priv;
-	struct soc_camera_device   *icd = client->dev.platform_data;
-	struct soc_camera_link     *icl;
+	struct v4l2_int_device     *v4l2_int_device;
 	int                         ret;
 
-	if (!icd) {
-		dev_err(&client->dev, "mt9t112: missing soc-camera data!\n");
-		return -EINVAL;
+	if (!client->dev.platform_data) {
+		dev_err(&client->dev, "no platform data?\n");
+		return -ENODEV;
 	}
 
-	icl = to_soc_camera_link(icd);
-	if (!icl || !icl->priv)
-		return -EINVAL;
-
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
-	priv->info = icl->priv;
+	v4l2_int_device = kzalloc(sizeof(*v4l2_int_device), GFP_KERNEL);
+	if (!v4l2_int_device) {
+		kfree(priv);
+		return -ENOMEM;
+	}
 
-	v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
+	v4l2_int_device->module = THIS_MODULE;
+	strncpy(v4l2_int_device->name, "mt9t112", sizeof(v4l2_int_device->name));
+	v4l2_int_device->type = v4l2_int_type_slave;
+	v4l2_int_device->u.slave = &mt9t112_slave;
+	v4l2_int_device->priv = priv;
 
-	icd->ops = &mt9t112_ops;
+	priv->v4l2_int_device = v4l2_int_device;
+	priv->client = client;
+	priv->pdata = client->dev.platform_data;
 
-	ret = mt9t112_camera_probe(icd, client);
+	i2c_set_clientdata(client, priv);
+
+	//ret = mt9t112_detect(client);
+
+	ret = v4l2_int_device_register(priv->v4l2_int_device);
 	if (ret) {
-		icd->ops = NULL;
 		i2c_set_clientdata(client, NULL);
+		kfree(v4l2_int_device);
 		kfree(priv);
 	}
 
@@ -1128,11 +1211,12 @@ static int mt9t112_probe(struct i2c_client *client,
 
 static int mt9t112_remove(struct i2c_client *client)
 {
-	struct mt9t112_priv *priv = to_mt9t112(client);
-	struct soc_camera_device *icd = client->dev.platform_data;
+	struct mt9t112_priv *priv = i2c_get_clientdata(client);
 
-	icd->ops = NULL;
+	v4l2_int_device_unregister(priv->v4l2_int_device);
 	i2c_set_clientdata(client, NULL);
+
+	kfree(priv->v4l2_int_device);
 	kfree(priv);
 	return 0;
 }
@@ -1172,6 +1256,6 @@ static void __exit mt9t112_module_exit(void)
 module_init(mt9t112_module_init);
 module_exit(mt9t112_module_exit);
 
-MODULE_DESCRIPTION("SoC Camera driver for mt9t112");
+MODULE_DESCRIPTION("mt9t112 sensor driver");
 MODULE_AUTHOR("Kuninori Morimoto");
 MODULE_LICENSE("GPL v2");
diff --git a/include/media/mt9t112.h b/include/media/mt9t112.h
index a43c74a..62caaf5 100644
--- a/include/media/mt9t112.h
+++ b/include/media/mt9t112.h
@@ -11,6 +11,8 @@
 #ifndef __MT9T112_H__
 #define __MT9T112_H__
 
+#include <media/v4l2-int-device.h>
+
 #define MT9T112_FLAG_PCLK_RISING_EDGE	(1 << 0)
 #define MT9T112_FLAG_DATAWIDTH_8	(1 << 1) /* default width is 10 */
 
@@ -27,4 +29,15 @@ struct mt9t112_camera_info {
 	struct mt9t112_pll_divider divider;
 };
 
+struct mt9t112_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 *);
+	/* Interface control params */
+	bool clk_polarity;
+	bool hs_polarity;
+	bool vs_polarity;
+};
+
 #endif /* __MT9T112_H__ */
-- 
1.6.6.1

